2 * Copyright (c) 1995 HD Associates, Inc.
7 * Pepperell, MA 01463-0276
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by HD Associates, Inc.
21 * 4. The name of HD Associates, Inc.
22 * may not be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * $FreeBSD: src/sys/i386/isa/labpc.c,v 1.35 1999/09/25 18:24:08 phk Exp $
46 #include "opt_debug_outb.h"
47 #include <sys/param.h>
49 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
54 #define b_actf b_act.tqe_next
55 #include <sys/dataacq.h>
59 #include <machine/clock.h>
62 #include <i386/isa/isa_device.h>
69 #define LABPC_MIN_TMO (hz)
72 #ifndef LABPC_DEFAULT_HERZ
73 #define LABPC_DEFAULT_HERZ 500
79 * S: SCAN bit for scan enable.
80 * I: INTERVAL for interval support
81 * D: 1: Digital I/O, 0: Analog I/O
84 * input: channel must be 0 to 7.
85 * output: channel must be 0 to 2
88 * 2: Alternate channel 0 then 1
91 * input: Channel must be 0 to 2.
92 * output: Channel must be 0 to 2.
98 #define UNIT(dev) (((minor(dev) & 0xB0) >> 6) & 0x3)
100 #define SCAN(dev) ((minor(dev) & 0x20) >> 5)
101 #define INTERVAL(dev) ((minor(dev) & 0x10) >> 4)
102 #define DIGITAL(dev) ((minor(dev) & 0x08) >> 3)
107 #define CHAN(dev) (minor(dev) & 0x7)
109 /* History: Derived from "dt2811.c" March 1995
115 #define DROPPED_INPUT 0x100
119 #define BUSY 0x00000001
125 struct buf start_queue; /* Start queue */
126 struct buf *last; /* End of start queue */
129 long tmo; /* Timeout in Herz */
130 long min_tmo; /* Timeout in Herz */
135 dev_t dev; /* Copy of device */
137 void (*starter)(struct ctlr *ctlr, long count);
138 void (*stop)(struct ctlr *ctlr);
139 void (*intr)(struct ctlr *ctlr);
141 /* Digital I/O support. Copy of Data Control Register for 8255:
143 u_char dcr_val, dcr_is;
146 * Handle for canceling our timeout.
148 struct callout_handle ch;
150 /* Device configuration structure:
155 /* loutb is a slow outb for debugging. The overrun test may fail
156 * with this for some slower processors.
158 static __inline void loutb(int port, u_char val)
164 #define loutb(port, val) outb(port, val)
167 static struct ctlr **labpcs; /* XXX: Should be dynamic */
169 /* CR_EXPR: A macro that sets the shadow register in addition to
170 * sending out the data.
172 #define CR_EXPR(LABPC, CR, EXPR) do { \
173 (LABPC)->cr_image[CR - 1] EXPR ; \
174 loutb(((LABPC)->base + ( (CR == 4) ? (0x0F) : (CR - 1))), ((LABPC)->cr_image[(CR - 1)])); \
177 #define CR_CLR(LABPC, CR) CR_EXPR(LABPC, CR, &=0)
178 #define CR_REFRESH(LABPC, CR) CR_EXPR(LABPC, CR, &=0xff)
179 #define CR_SET(LABPC, CR, EXPR) CR_EXPR(LABPC, CR, = EXPR)
181 /* Configuration and Status Register Group.
183 #define CR1(LABPC) ((LABPC)->base + 0x00) /* Page 4-5 */
185 #define GAINMASK 0x70
186 #define GAIN(LABPC, SEL) do { \
187 (LABPC)->cr_image[1 - 1] &= ~GAINMASK; \
188 (LABPC)->cr_image[1 - 1] |= (SEL << 4); \
189 loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \
194 #define MA(LABPC, SEL) do { \
195 (LABPC)->cr_image[1 - 1] &= ~MAMASK; \
196 (LABPC)->cr_image[1 - 1] |= SEL; \
197 loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \
200 #define STATUS(LABPC) ((LABPC)->base + 0x00) /* Page 4-7 */
201 #define LABPCPLUS 0x80
202 #define EXTGATA0 0x40
206 #define OVERFLOW 0x04
210 #define CR2(LABPC) ((LABPC)->base + 0x01) /* Page 4-9 */
219 #define SWTRIGGERRED(LABPC) ((LABPC->cr_image[1]) & SWTRIG)
221 #define CR3(LABPC) ((LABPC)->base + 0x02) /* Page 4-11 */
222 #define FIFOINTEN 0x20
223 #define ERRINTEN 0x10
224 #define CNTINTEN 0x08
226 #define DIOINTEN 0x02
229 #define ALLINTEN 0x3E
230 #define FIFOINTENABLED(LABPC) ((LABPC->cr_image[2]) & FIFOINTEN)
232 #define CR4(LABPC) ((LABPC)->base + 0x0F) /* Page 4-13 */
239 /* Analog Input Register Group
241 #define ADFIFO(LABPC) ((LABPC)->base + 0x0A) /* Page 4-16 */
242 #define ADCLEAR(LABPC) ((LABPC)->base + 0x08) /* Page 4-18 */
243 #define ADSTART(LABPC) ((LABPC)->base + 0x03) /* Page 4-19 */
244 #define DMATCICLR(LABPC) ((LABPC)->base + 0x0A) /* Page 4-20 */
246 /* Analog Output Register Group
248 #define DAC0L(LABPC) ((LABPC)->base + 0x04) /* Page 4-22 */
249 #define DAC0H(LABPC) ((LABPC)->base + 0x05) /* Page 4-22 */
250 #define DAC1L(LABPC) ((LABPC)->base + 0x06) /* Page 4-22 */
251 #define DAC1H(LABPC) ((LABPC)->base + 0x07) /* Page 4-22 */
255 #define A0DATA(LABPC) ((LABPC)->base + 0x14)
256 #define A1DATA(LABPC) ((LABPC)->base + 0x15)
257 #define A2DATA(LABPC) ((LABPC)->base + 0x16)
258 #define AMODE(LABPC) ((LABPC)->base + 0x17)
260 #define TICR(LABPC) ((LABPC)->base + 0x0c)
262 #define B0DATA(LABPC) ((LABPC)->base + 0x18)
263 #define B1DATA(LABPC) ((LABPC)->base + 0x19)
264 #define B2DATA(LABPC) ((LABPC)->base + 0x1A)
265 #define BMODE(LABPC) ((LABPC)->base + 0x1B)
270 #define PORTX(LABPC, X) ((LABPC)->base + 0x10 + X)
272 #define PORTA(LABPC) PORTX(LABPC, 0)
273 #define PORTB(LABPC) PORTX(LABPC, 1)
274 #define PORTC(LABPC) PORTX(LABPC, 2)
276 #define DCR(LABPC) ((LABPC)->base + 0x13)
278 static int labpcattach(struct isa_device *dev);
279 static int labpcprobe(struct isa_device *dev);
280 struct isa_driver labpcdriver =
281 { labpcprobe, labpcattach, "labpc", 0 };
283 static d_open_t labpcopen;
284 static d_close_t labpcclose;
285 static d_ioctl_t labpcioctl;
286 static d_strategy_t labpcstrategy;
288 #define CDEV_MAJOR 66
289 static struct cdevsw labpc_cdevsw = {
290 /* open */ labpcopen,
291 /* close */ labpcclose,
293 /* write */ physwrite,
294 /* ioctl */ labpcioctl,
297 /* strategy */ labpcstrategy,
299 /* maj */ CDEV_MAJOR,
306 static ointhand2_t labpcintr;
307 static void start(struct ctlr *ctlr);
310 bp_done(struct buf *bp, int err)
314 if (err || bp->b_resid)
316 bp->b_flags |= B_ERROR;
322 static void tmo_stop(void *p);
325 done_and_start_next(struct ctlr *ctlr, struct buf *bp, int err)
327 bp->b_resid = ctlr->data_end - ctlr->data;
331 ctlr->start_queue.b_actf = bp->b_actf;
334 untimeout(tmo_stop, ctlr, ctlr->ch);
340 ad_clear(struct ctlr *ctlr)
343 loutb(ADCLEAR(ctlr), 0);
344 for (i = 0; i < 10000 && (inb(STATUS(ctlr)) & GATA0); i++)
346 (void)inb(ADFIFO(ctlr));
347 (void)inb(ADFIFO(ctlr));
350 /* reset: Reset the board following the sequence on page 5-1
353 reset(struct ctlr *ctlr)
357 CR_CLR(ctlr, 3); /* Turn off interrupts first */
364 loutb(AMODE(ctlr), 0x34);
365 loutb(A0DATA(ctlr),0x0A);
366 loutb(A0DATA(ctlr),0x00);
368 loutb(DMATCICLR(ctlr), 0x00);
369 loutb(TICR(ctlr), 0x00);
373 loutb(DAC0L(ctlr), 0);
374 loutb(DAC0H(ctlr), 0);
375 loutb(DAC1L(ctlr), 0);
376 loutb(DAC1H(ctlr), 0);
381 /* overrun: slam the start convert register and OVERRUN should get set:
384 overrun(struct ctlr *ctlr)
388 u_char status = inb(STATUS(ctlr));
389 for (i = 0; ((status & OVERRUN) == 0) && i < 100; i++)
391 loutb(ADSTART(ctlr), 1);
392 status = inb(STATUS(ctlr));
401 if (NLABPC > MAX_UNITS)
404 labpcs = malloc(NLABPC * sizeof(struct ctlr *), M_DEVBUF, M_NOWAIT);
407 bzero(labpcs, NLABPC * sizeof(struct ctlr *));
410 cdevsw_add(&labpc_cdevsw);
415 labpcprobe(struct isa_device *dev)
418 struct ctlr scratch, *ctlr;
423 if (labpcinit() == 0)
425 printf("labpcprobe: init failed\n");
432 printf("Too many LAB-PCs. Reconfigure O/S.\n");
435 ctlr = &scratch; /* Need somebody with the right base for the macros */
436 ctlr->base = dev->id_iobase;
438 /* XXX: There really isn't a perfect way to probe this board.
439 * Here is my best attempt:
443 /* After reset none of these bits should be set:
445 status = inb(STATUS(ctlr));
446 if (status & (GATA0 | OVERFLOW | DAVAIL | OVERRUN))
449 /* Now try to overrun the board FIFO and get the overrun bit set:
451 status = overrun(ctlr);
453 if ((status & OVERRUN) == 0) /* No overrun bit set? */
456 /* Assume we have a board.
460 if ( (labpcs[unit] = malloc(sizeof(struct ctlr), M_DEVBUF, M_NOWAIT)) )
462 struct ctlr *l = labpcs[unit];
464 bzero(l, sizeof(struct ctlr));
465 l->base = ctlr->base;
466 dev->id_unit = l->unit = unit;
473 printf("labpc%d: Can't malloc.\n", unit);
478 /* attach: Set things in a normal state.
481 labpcattach(struct isa_device *dev)
483 struct ctlr *ctlr = labpcs[dev->id_unit];
485 dev->id_ointr = labpcintr;
486 callout_handle_init(&ctlr->ch);
487 ctlr->sample_us = (1000000.0 / (double)LABPC_DEFAULT_HERZ) + .50;
490 ctlr->min_tmo = LABPC_MIN_TMO;
492 ctlr->dcr_val = 0x80;
494 loutb(DCR(ctlr), ctlr->dcr_val);
496 make_dev(&labpc_cdevsw, 0, 0, 0, 0600, "labpc%d", dev->id_unit);
502 static void null_intr (struct ctlr *ctlr) { }
503 static void null_start(struct ctlr *ctlr, long count) { }
504 static void null_stop (struct ctlr *ctlr) { }
507 trigger(struct ctlr *ctlr)
509 CR_EXPR(ctlr, 2, |= SWTRIG);
513 ad_start(struct ctlr *ctlr, long count)
515 if (!SWTRIGGERRED(ctlr)) {
516 int chan = CHAN(ctlr->dev);
517 CR_EXPR(ctlr, 1, &= ~SCANEN);
518 CR_EXPR(ctlr, 2, &= ~TBSEL);
521 GAIN(ctlr, ctlr->gains[chan]);
524 CR_EXPR(ctlr, 1, |= SCANEN);
526 loutb(AMODE(ctlr), 0x34);
527 loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us & 0xff)));
528 loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff));
529 loutb(AMODE(ctlr), 0x70);
535 ctlr->tmo = ((count + 16) * (long)ctlr->sample_us * hz) / 1000000 +
540 ad_interval_start(struct ctlr *ctlr, long count)
542 int chan = CHAN(ctlr->dev);
543 int n_frames = count / (chan + 1);
545 if (!SWTRIGGERRED(ctlr)) {
546 CR_EXPR(ctlr, 1, &= ~SCANEN);
547 CR_EXPR(ctlr, 2, &= ~TBSEL);
550 GAIN(ctlr, ctlr->gains[chan]);
552 /* XXX: Is it really possible that you clear INTSCAN as
553 * the documentation says? That seems pretty unlikely.
555 CR_EXPR(ctlr, 4, &= ~INTSCAN); /* XXX: Is this possible? */
557 /* Program the sample interval counter to run as fast as
560 loutb(AMODE(ctlr), 0x34);
561 loutb(A0DATA(ctlr), (u_char)(0x02));
562 loutb(A0DATA(ctlr), (u_char)(0x00));
563 loutb(AMODE(ctlr), 0x70);
565 /* Program the interval scanning counter to run at the sample
568 loutb(BMODE(ctlr), 0x74);
569 loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us & 0xff)));
570 loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff));
571 CR_EXPR(ctlr, 1, |= SCANEN);
577 /* Each frame time takes two microseconds per channel times
578 * the number of channels being sampled plus the sample period.
580 ctlr->tmo = ((n_frames + 16) *
581 ((long)ctlr->sample_us + (chan + 1 ) * 2 ) * hz) / 1000000 +
586 all_stop(struct ctlr *ctlr)
594 struct ctlr *ctlr = (struct ctlr *)p;
601 printf("labpc?: Null ctlr struct?\n");
606 printf("labpc%d: timeout", ctlr->unit);
610 bp = ctlr->start_queue.b_actf;
613 printf(", Null bp.\n");
620 done_and_start_next(ctlr, bp, ETIMEDOUT);
625 static void ad_intr(struct ctlr *ctlr)
629 if (ctlr->cr_image[2] == 0)
631 if (ctlr->cleared_intr)
633 ctlr->cleared_intr = 0;
637 printf("ad_intr (should not happen) interrupt with interrupts off\n");
638 printf("status %x, cr3 %x\n", inb(STATUS(ctlr)), ctlr->cr_image[2]);
642 while ( (status = (inb(STATUS(ctlr)) & (DAVAIL|OVERRUN|OVERFLOW)) ) )
644 if ((status & (OVERRUN|OVERFLOW)))
646 struct buf *bp = ctlr->start_queue.b_actf;
648 printf("ad_intr: error: bp %p, data %p, status %x",
649 (void *)bp, (void *)ctlr->data, status);
651 if (status & OVERRUN)
652 printf(" Conversion overrun (multiple A-D trigger)");
654 if (status & OVERFLOW)
655 printf(" FIFO overflow");
661 done_and_start_next(ctlr, bp, EIO);
666 printf("ad_intr: (should not happen) error between records\n");
667 ctlr->err = status; /* Set overrun condition */
671 else /* FIFO interrupt */
673 struct buf *bp = ctlr->start_queue.b_actf;
677 *ctlr->data++ = inb(ADFIFO(ctlr));
678 if (ctlr->data == ctlr->data_end) /* Normal completion */
680 done_and_start_next(ctlr, bp, 0);
684 else /* Interrupt with no where to put the data. */
686 printf("ad_intr: (should not happen) dropped input.\n");
687 (void)inb(ADFIFO(ctlr));
689 printf("bp %p, status %x, cr3 %x\n",
690 (void *)bp, status, ctlr->cr_image[2]);
692 ctlr->err = DROPPED_INPUT;
699 static void labpcintr(int unit)
701 struct ctlr *ctlr = labpcs[unit];
705 /* lockout_multiple_opens: Return whether or not we can open again, or
706 * if the new mode is inconsistent with an already opened mode.
707 * We only permit multiple opens for digital I/O now.
711 lockout_multiple_open(dev_t current, dev_t next)
713 return ! (DIGITAL(current) && DIGITAL(next));
717 labpcopen(dev_t dev, int flags, int fmt, struct proc *p)
719 u_short unit = UNIT(dev);
723 if (unit >= MAX_UNITS)
731 /* Don't allow another open if we have to change modes.
734 if ( (ctlr->flags & BUSY) == 0)
743 ctlr->intr = null_intr;
744 ctlr->starter = null_start;
745 ctlr->stop = null_stop;
747 else if (lockout_multiple_open(ctlr->dev, dev))
754 labpcclose(dev_t dev, int flags, int fmt, struct proc *p)
756 struct ctlr *ctlr = labpcs[UNIT(dev)];
760 ctlr->flags &= ~BUSY;
766 * Start: Start a frame going in or out.
769 start(struct ctlr *ctlr)
773 if ((bp = ctlr->start_queue.b_actf) == 0)
775 /* We must turn off FIFO interrupts when there is no
776 * place to put the data. We have to get back to
777 * reading before the FIFO overflows.
779 CR_EXPR(ctlr, 3, &= ~(FIFOINTEN|ERRINTEN));
780 ctlr->cleared_intr = 1;
781 ctlr->start_queue.b_bcount = 0;
785 ctlr->data = (u_char *)bp->b_data;
786 ctlr->data_end = ctlr->data + bp->b_bcount;
790 printf("labpc start: (should not happen) error between records.\n");
791 done_and_start_next(ctlr, bp, EIO);
797 printf("labpc start: (should not happen) NULL data pointer.\n");
798 done_and_start_next(ctlr, bp, EIO);
803 (*ctlr->starter)(ctlr, bp->b_bcount);
805 if (!FIFOINTENABLED(ctlr)) /* We can store the data again */
807 CR_EXPR(ctlr, 3, |= (FIFOINTEN|ERRINTEN));
809 /* Don't wait for the interrupts to fill things up.
814 ctlr->ch = timeout(tmo_stop, ctlr, ctlr->tmo);
818 ad_strategy(struct buf *bp, struct ctlr *ctlr)
825 if (ctlr->start_queue.b_bcount)
827 ctlr->last->b_actf = bp;
832 ctlr->start_queue.b_bcount = 1;
833 ctlr->start_queue.b_actf = bp;
840 /* da_strategy: Send data to the D-A. The CHAN field should be
843 * 2: Alternate port 0 then port 1
847 * 1. There is no state for CHAN field 2:
848 * the first sample in each buffer goes to channel 0.
850 * 2. No interrupt support yet.
853 da_strategy(struct buf *bp, struct ctlr *ctlr)
860 switch(CHAN(bp->b_dev))
870 case 2: /* Device 2 handles both ports interleaved. */
871 if (bp->b_bcount <= 2)
877 len = bp->b_bcount / 2;
878 data = (u_char *)bp->b_data;
880 for (i = 0; i < len; i++)
882 loutb(DAC0H(ctlr), *data++);
883 loutb(DAC0L(ctlr), *data++);
884 loutb(DAC1H(ctlr), *data++);
885 loutb(DAC1L(ctlr), *data++);
888 bp->b_resid = bp->b_bcount & 3;
897 /* Port 0 or 1 falls through to here.
899 if (bp->b_bcount & 1) /* Odd transfers are illegal */
903 data = (u_char *)bp->b_data;
905 for (i = 0; i < len; i++)
907 loutb(port + 1, *data++);
908 loutb(port, *data++);
916 /* Input masks for MODE 0 of the ports treating PC as a single
917 * 8 bit port. Set these bits to set the port to input.
919 /* A B lowc highc combined */
920 static u_char set_input[] = { 0x10, 0x02, 0x01, 0x08, 0x09 };
922 static void flush_dcr(struct ctlr *ctlr)
924 if (ctlr->dcr_is != ctlr->dcr_val)
926 loutb(DCR(ctlr), ctlr->dcr_val);
927 ctlr->dcr_is = ctlr->dcr_val;
931 /* do: Digital output
934 digital_out_strategy(struct buf *bp, struct ctlr *ctlr)
940 int chan = CHAN(bp->b_dev);
942 ctlr->dcr_val &= ~set_input[chan]; /* Digital out: Clear bit */
945 port = PORTX(ctlr, chan);
948 data = (u_char *)bp->b_data;
950 for (i = 0; i < len; i++)
952 loutb(port, *data++);
960 /* digital_in_strategy: Digital input
963 digital_in_strategy(struct buf *bp, struct ctlr *ctlr)
969 int chan = CHAN(bp->b_dev);
971 ctlr->dcr_val |= set_input[chan]; /* Digital in: Set bit */
973 port = PORTX(ctlr, chan);
976 data = (u_char *)bp->b_data;
978 for (i = 0; i < len; i++)
990 labpcstrategy(struct buf *bp)
992 struct ctlr *ctlr = labpcs[UNIT(bp->b_dev)];
994 if (DIGITAL(bp->b_dev)) {
995 if (bp->b_flags & B_READ) {
996 ctlr->starter = null_start;
997 ctlr->stop = all_stop;
998 ctlr->intr = null_intr;
999 digital_in_strategy(bp, ctlr);
1003 ctlr->starter = null_start;
1004 ctlr->stop = all_stop;
1005 ctlr->intr = null_intr;
1006 digital_out_strategy(bp, ctlr);
1010 if (bp->b_flags & B_READ) {
1012 ctlr->starter = INTERVAL(ctlr->dev) ? ad_interval_start : ad_start;
1013 ctlr->stop = all_stop;
1014 ctlr->intr = ad_intr;
1015 ad_strategy(bp, ctlr);
1019 ctlr->starter = null_start;
1020 ctlr->stop = all_stop;
1021 ctlr->intr = null_intr;
1022 da_strategy(bp, ctlr);
1028 labpcioctl(dev_t dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
1030 struct ctlr *ctlr = labpcs[UNIT(dev)];
1034 case AD_MICRO_PERIOD_SET:
1036 /* XXX I'm only supporting what I have to, which is
1037 * no slow periods. You can't get any slower than 15 Hz
1038 * with the current setup. To go slower you'll need to
1039 * support TCINTEN in CR3.
1042 long sample_us = *(long *)arg;
1044 if (sample_us > 65535)
1047 ctlr->sample_us = sample_us;
1051 case AD_MICRO_PERIOD_GET:
1052 *(long *)arg = ctlr->sample_us;
1063 case AD_SUPPORTED_GAINS:
1065 static double gains[] = {1., 1.25, 2., 5., 10., 20., 50., 100.};
1066 copyout(gains, *(caddr_t *)arg, sizeof(gains));
1073 copyin(*(caddr_t *)arg, ctlr->gains, sizeof(ctlr->gains));
1079 copyout(ctlr->gains, *(caddr_t *)arg, sizeof(ctlr->gains));