FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/labpc.c
1 /*
2 * Copyright (c) 1995 HD Associates, Inc.
3 * All rights reserved.
4 *
5 * HD Associates, Inc.
6 * PO Box 276
7 * Pepperell, MA 01463-0276
8 * dufault@hda.com
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
24 *
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
35 * SUCH DAMAGE.
36 *
37 * Written by:
38 * Peter Dufault
39 * dufault@hda.com
40 */
41
42 #include "labpc.h"
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/time.h>
47
48 #include <sys/systm.h>
49
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/errno.h>
53 #include <sys/buf.h>
54 #define b_actf b_act.tqe_next
55 #include <sys/dataacq.h>
56 #include <sys/conf.h>
57 #include <sys/kernel.h>
58 #ifdef DEVFS
59 #include <sys/devfsext.h>
60 #endif /*DEVFS*/
61
62 #include <machine/clock.h>
63
64 #include <i386/isa/isa_device.h>
65
66
67
68 /* Miniumum timeout:
69 */
70 #ifndef LABPC_MIN_TMO
71 #define LABPC_MIN_TMO (hz)
72 #endif
73
74 #ifndef LABPC_DEFAULT_HERZ
75 #define LABPC_DEFAULT_HERZ 500
76 #endif
77
78 /* Minor number:
79 * UUSIDCCC
80 * UU: Board unit.
81 * S: SCAN bit for scan enable.
82 * I: INTERVAL for interval support
83 * D: 1: Digital I/O, 0: Analog I/O
84 * CCC: Channel.
85 * Analog (D==0):
86 * input: channel must be 0 to 7.
87 * output: channel must be 0 to 2
88 * 0: D-A 0
89 * 1: D-A 1
90 * 2: Alternate channel 0 then 1
91 *
92 * Digital (D==1):
93 * input: Channel must be 0 to 2.
94 * output: Channel must be 0 to 2.
95 */
96
97 /* Up to four boards:
98 */
99 #define MAX_UNITS 4
100 #define UNIT(dev) (((minor(dev) & 0xB0) >> 6) & 0x3)
101
102 #define SCAN(dev) ((minor(dev) & 0x20) >> 5)
103 #define INTERVAL(dev) ((minor(dev) & 0x10) >> 4)
104 #define DIGITAL(dev) ((minor(dev) & 0x08) >> 3)
105
106 /* Eight channels:
107 */
108
109 #define CHAN(dev) (minor(dev) & 0x7)
110
111 /* History: Derived from "dt2811.c" March 1995
112 */
113
114 struct ctlr
115 {
116 int err;
117 #define DROPPED_INPUT 0x100
118 int base;
119 int unit;
120 unsigned long flags;
121 #define BUSY 0x00000001
122
123 u_char cr_image[4];
124
125 u_short sample_us;
126
127 struct buf start_queue; /* Start queue */
128 struct buf *last; /* End of start queue */
129 u_char *data;
130 u_char *data_end;
131 long tmo; /* Timeout in Herz */
132 long min_tmo; /* Timeout in Herz */
133 int cleared_intr;
134
135 int gains[8];
136
137 dev_t dev; /* Copy of device */
138
139 void (*starter)(struct ctlr *ctlr, long count);
140 void (*stop)(struct ctlr *ctlr);
141 void (*intr)(struct ctlr *ctlr);
142
143 /* Digital I/O support. Copy of Data Control Register for 8255:
144 */
145 u_char dcr_val, dcr_is;
146
147 /* Device configuration structure:
148 */
149 #ifdef DEVFS
150 void *devfs_token;
151 #endif
152 };
153
154 #ifdef LOUTB
155 /* loutb is a slow outb for debugging. The overrun test may fail
156 * with this for some slower processors.
157 */
158 static inline void loutb(int port, u_char val)
159 {
160 outb(port, val);
161 DELAY(1);
162 }
163 #else
164 #define loutb(port, val) outb(port, val)
165 #endif
166
167 static struct ctlr **labpcs; /* XXX: Should be dynamic */
168
169 /* CR_EXPR: A macro that sets the shadow register in addition to
170 * sending out the data.
171 */
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)])); \
175 } while (0)
176
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)
180
181 /* Configuration and Status Register Group.
182 */
183 #define CR1(LABPC) ((LABPC)->base + 0x00) /* Page 4-5 */
184 #define SCANEN 0x80
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)]); \
190 } while (0)
191
192 #define TWOSCMP 0x08
193 #define MAMASK 0x07
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)]); \
198 } while (0)
199
200 #define STATUS(LABPC) ((LABPC)->base + 0x00) /* Page 4-7 */
201 #define LABPCPLUS 0x80
202 #define EXTGATA0 0x40
203 #define GATA0 0x20
204 #define DMATC 0x10
205 #define CNTINT 0x08
206 #define OVERFLOW 0x04
207 #define OVERRUN 0x02
208 #define DAVAIL 0x01
209
210 #define CR2(LABPC) ((LABPC)->base + 0x01) /* Page 4-9 */
211 #define LDAC1 0x80
212 #define LDAC0 0x40
213 #define _2SDAC1 0x20
214 #define _2SDAC0 0x10
215 #define TBSEL 0x08
216 #define SWTRIG 0x04
217 #define HWTRIG 0x02
218 #define PRETRIG 0x01
219 #define SWTRIGGERRED(LABPC) ((LABPC->cr_image[1]) & SWTRIG)
220
221 #define CR3(LABPC) ((LABPC)->base + 0x02) /* Page 4-11 */
222 #define FIFOINTEN 0x20
223 #define ERRINTEN 0x10
224 #define CNTINTEN 0x08
225 #define TCINTEN 0x04
226 #define DIOINTEN 0x02
227 #define DMAEN 0x01
228
229 #define ALLINTEN 0x3E
230 #define FIFOINTENABLED(LABPC) ((LABPC->cr_image[2]) & FIFOINTEN)
231
232 #define CR4(LABPC) ((LABPC)->base + 0x0F) /* Page 4-13 */
233 #define ECLKRCV 0x10
234 #define SE_D 0x08
235 #define ECKDRV 0x04
236 #define EOIRCV 0x02
237 #define INTSCAN 0x01
238
239 /* Analog Input Register Group
240 */
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 */
245
246 /* Analog Output Register Group
247 */
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 */
252
253 /* 8253 registers:
254 */
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)
259
260 #define TICR(LABPC) ((LABPC)->base + 0x0c)
261
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)
266
267 /* 8255 registers:
268 */
269
270 #define PORTX(LABPC, X) ((LABPC)->base + 0x10 + X)
271
272 #define PORTA(LABPC) PORTX(LABPC, 0)
273 #define PORTB(LABPC) PORTX(LABPC, 1)
274 #define PORTC(LABPC) PORTX(LABPC, 2)
275
276 #define DCR(LABPC) ((LABPC)->base + 0x13)
277
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 };
282
283 static d_open_t labpcopen;
284 static d_close_t labpcclose;
285 static d_ioctl_t labpcioctl;
286 static d_strategy_t labpcstrategy;
287
288 #define CDEV_MAJOR 66
289 static struct cdevsw labpc_cdevsw =
290 { labpcopen, labpcclose, rawread, rawwrite, /*66*/
291 labpcioctl, nostop, nullreset, nodevtotty,/* labpc */
292 seltrue, nommap, labpcstrategy, "labpc", NULL, -1 };
293
294 static void start(struct ctlr *ctlr);
295
296 static void
297 bp_done(struct buf *bp, int err)
298 {
299 bp->b_error = err;
300
301 if (err || bp->b_resid)
302 {
303 bp->b_flags |= B_ERROR;
304 }
305
306 biodone(bp);
307 }
308
309 static void tmo_stop(void *p);
310
311 static void
312 done_and_start_next(struct ctlr *ctlr, struct buf *bp, int err)
313 {
314 bp->b_resid = ctlr->data_end - ctlr->data;
315
316 ctlr->data = 0;
317
318 ctlr->start_queue.b_actf = bp->b_actf;
319 bp_done(bp, err);
320
321 untimeout(tmo_stop, ctlr);
322
323 start(ctlr);
324 }
325
326 static inline void
327 ad_clear(struct ctlr *ctlr)
328 {
329 int i;
330 loutb(ADCLEAR(ctlr), 0);
331 for (i = 0; i < 10000 && (inb(STATUS(ctlr)) & GATA0); i++)
332 ;
333 (void)inb(ADFIFO(ctlr));
334 (void)inb(ADFIFO(ctlr));
335 }
336
337 /* reset: Reset the board following the sequence on page 5-1
338 */
339 static inline void
340 reset(struct ctlr *ctlr)
341 {
342 int s = splhigh();
343
344 CR_CLR(ctlr, 3); /* Turn off interrupts first */
345 splx(s);
346
347 CR_CLR(ctlr, 1);
348 CR_CLR(ctlr, 2);
349 CR_CLR(ctlr, 4);
350
351 loutb(AMODE(ctlr), 0x34);
352 loutb(A0DATA(ctlr),0x0A);
353 loutb(A0DATA(ctlr),0x00);
354
355 loutb(DMATCICLR(ctlr), 0x00);
356 loutb(TICR(ctlr), 0x00);
357
358 ad_clear(ctlr);
359
360 loutb(DAC0L(ctlr), 0);
361 loutb(DAC0H(ctlr), 0);
362 loutb(DAC1L(ctlr), 0);
363 loutb(DAC1H(ctlr), 0);
364
365 ad_clear(ctlr);
366 }
367
368 /* overrun: slam the start convert register and OVERRUN should get set:
369 */
370 static u_char
371 overrun(struct ctlr *ctlr)
372 {
373 int i;
374
375 u_char status = inb(STATUS(ctlr));
376 for (i = 0; ((status & OVERRUN) == 0) && i < 100; i++)
377 {
378 loutb(ADSTART(ctlr), 1);
379 status = inb(STATUS(ctlr));
380 }
381
382 return status;
383 }
384
385 static int
386 labpcinit(void)
387 {
388 if (NLABPC > MAX_UNITS)
389 return 0;
390
391 labpcs = malloc(NLABPC * sizeof(struct ctlr *), M_DEVBUF, M_NOWAIT);
392 if (labpcs)
393 {
394 bzero(labpcs, NLABPC * sizeof(struct cltr *));
395 return 1;
396 }
397 return 0;
398 }
399
400 static int
401 labpcprobe(struct isa_device *dev)
402 {
403 static unit;
404 struct ctlr scratch, *ctlr;
405 u_char status;
406
407 if (!labpcs)
408 {
409 if (labpcinit() == 0)
410 {
411 printf("labpcprobe: init failed\n");
412 return 0;
413 }
414 }
415
416 if (unit > NLABPC)
417 {
418 printf("Too many LAB-PCs. Reconfigure O/S.\n");
419 return 0;
420 }
421 ctlr = &scratch; /* Need somebody with the right base for the macros */
422 ctlr->base = dev->id_iobase;
423
424 /* XXX: There really isn't a perfect way to probe this board.
425 * Here is my best attempt:
426 */
427 reset(ctlr);
428
429 /* After reset none of these bits should be set:
430 */
431 status = inb(STATUS(ctlr));
432 if (status & (GATA0 | OVERFLOW | DAVAIL | OVERRUN))
433 return 0;
434
435 /* Now try to overrun the board FIFO and get the overrun bit set:
436 */
437 status = overrun(ctlr);
438
439 if ((status & OVERRUN) == 0) /* No overrun bit set? */
440 return 0;
441
442 /* Assume we have a board.
443 */
444 reset(ctlr);
445
446 if ( (labpcs[unit] = malloc(sizeof(struct ctlr), M_DEVBUF, M_NOWAIT)) )
447 {
448 struct ctlr *l = labpcs[unit];
449
450 bzero(l, sizeof(struct ctlr));
451 l->base = ctlr->base;
452 dev->id_unit = l->unit = unit;
453
454 unit++;
455 return 0x20;
456 }
457 else
458 {
459 printf("labpc%d: Can't malloc.\n", unit);
460 return 0;
461 }
462 }
463
464 /* attach: Set things in a normal state.
465 */
466 static int
467 labpcattach(struct isa_device *dev)
468 {
469 struct ctlr *ctlr = labpcs[dev->id_unit];
470
471 ctlr->sample_us = (1000000.0 / (double)LABPC_DEFAULT_HERZ) + .50;
472 reset(ctlr);
473
474 ctlr->min_tmo = LABPC_MIN_TMO;
475
476 ctlr->dcr_val = 0x80;
477 ctlr->dcr_is = 0x80;
478 loutb(DCR(ctlr), ctlr->dcr_val);
479
480 #ifdef DEVFS
481 ctlr->devfs_token =
482 devfs_add_devswf(&labpc_cdevsw, 0, DV_CHR,
483 /* what UID GID PERM */
484 0, 0, 0600,
485 "labpc%d", dev->id_unit);
486 #endif
487 return 1;
488 }
489
490 /* Null handlers:
491 */
492 static void null_intr (struct ctlr *ctlr) { }
493 static void null_start(struct ctlr *ctlr, long count) { }
494 static void null_stop (struct ctlr *ctlr) { }
495
496 static inline void
497 trigger(struct ctlr *ctlr)
498 {
499 CR_EXPR(ctlr, 2, |= SWTRIG);
500 }
501
502 static void
503 ad_start(struct ctlr *ctlr, long count)
504 {
505 if (!SWTRIGGERRED(ctlr)) {
506 int chan = CHAN(ctlr->dev);
507 CR_EXPR(ctlr, 1, &= ~SCANEN);
508 CR_EXPR(ctlr, 2, &= ~TBSEL);
509
510 MA(ctlr, chan);
511 GAIN(ctlr, ctlr->gains[chan]);
512
513 if (SCAN(ctlr->dev))
514 CR_EXPR(ctlr, 1, |= SCANEN);
515
516 loutb(AMODE(ctlr), 0x34);
517 loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us & 0xff)));
518 loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff));
519 loutb(AMODE(ctlr), 0x70);
520
521 ad_clear(ctlr);
522 trigger(ctlr);
523 }
524
525 ctlr->tmo = ((count + 16) * (long)ctlr->sample_us * hz) / 1000000 +
526 ctlr->min_tmo;
527 }
528
529 static void
530 ad_interval_start(struct ctlr *ctlr, long count)
531 {
532 int chan = CHAN(ctlr->dev);
533 int n_frames = count / (chan + 1);
534
535 if (!SWTRIGGERRED(ctlr)) {
536 CR_EXPR(ctlr, 1, &= ~SCANEN);
537 CR_EXPR(ctlr, 2, &= ~TBSEL);
538
539 MA(ctlr, chan);
540 GAIN(ctlr, ctlr->gains[chan]);
541
542 /* XXX: Is it really possible that you clear INTSCAN as
543 * the documentation says? That seems pretty unlikely.
544 */
545 CR_EXPR(ctlr, 4, &= ~INTSCAN); /* XXX: Is this possible? */
546
547 /* Program the sample interval counter to run as fast as
548 * possible.
549 */
550 loutb(AMODE(ctlr), 0x34);
551 loutb(A0DATA(ctlr), (u_char)(0x02));
552 loutb(A0DATA(ctlr), (u_char)(0x00));
553 loutb(AMODE(ctlr), 0x70);
554
555 /* Program the interval scanning counter to run at the sample
556 * frequency.
557 */
558 loutb(BMODE(ctlr), 0x74);
559 loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us & 0xff)));
560 loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff));
561 CR_EXPR(ctlr, 1, |= SCANEN);
562
563 ad_clear(ctlr);
564 trigger(ctlr);
565 }
566
567 /* Each frame time takes two microseconds per channel times
568 * the number of channels being sampled plus the sample period.
569 */
570 ctlr->tmo = ((n_frames + 16) *
571 ((long)ctlr->sample_us + (chan + 1 ) * 2 ) * hz) / 1000000 +
572 ctlr->min_tmo;
573 }
574
575 static void
576 all_stop(struct ctlr *ctlr)
577 {
578 reset(ctlr);
579 }
580
581 static void
582 tmo_stop(void *p)
583 {
584 struct ctlr *ctlr = (struct ctlr *)p;
585 struct buf *bp;
586
587 int s = spltty();
588
589 if (ctlr == 0)
590 {
591 printf("labpc?: Null ctlr struct?\n");
592 splx(s);
593 return;
594 }
595
596 printf("labpc%d: timeout", ctlr->unit);
597
598 (*ctlr->stop)(ctlr);
599
600 bp = ctlr->start_queue.b_actf;
601
602 if (bp == 0) {
603 printf(", Null bp.\n");
604 splx(s);
605 return;
606 }
607
608 printf("\n");
609
610 done_and_start_next(ctlr, bp, ETIMEDOUT);
611
612 splx(s);
613 }
614
615 static void ad_intr(struct ctlr *ctlr)
616 {
617 u_char status;
618
619 if (ctlr->cr_image[2] == 0)
620 {
621 if (ctlr->cleared_intr)
622 {
623 ctlr->cleared_intr = 0;
624 return;
625 }
626
627 printf("ad_intr (should not happen) interrupt with interrupts off\n");
628 printf("status %x, cr3 %x\n", inb(STATUS(ctlr)), ctlr->cr_image[2]);
629 return;
630 }
631
632 while ( (status = (inb(STATUS(ctlr)) & (DAVAIL|OVERRUN|OVERFLOW)) ) )
633 {
634 if ((status & (OVERRUN|OVERFLOW)))
635 {
636 struct buf *bp = ctlr->start_queue.b_actf;
637
638 printf("ad_intr: error: bp %0p, data %0p, status %x",
639 bp, ctlr->data, status);
640
641 if (status & OVERRUN)
642 printf(" Conversion overrun (multiple A-D trigger)");
643
644 if (status & OVERFLOW)
645 printf(" FIFO overflow");
646
647 printf("\n");
648
649 if (bp)
650 {
651 done_and_start_next(ctlr, bp, EIO);
652 return;
653 }
654 else
655 {
656 printf("ad_intr: (should not happen) error between records\n");
657 ctlr->err = status; /* Set overrun condition */
658 return;
659 }
660 }
661 else /* FIFO interrupt */
662 {
663 struct buf *bp = ctlr->start_queue.b_actf;
664
665 if (ctlr->data)
666 {
667 *ctlr->data++ = inb(ADFIFO(ctlr));
668 if (ctlr->data == ctlr->data_end) /* Normal completion */
669 {
670 done_and_start_next(ctlr, bp, 0);
671 return;
672 }
673 }
674 else /* Interrupt with no where to put the data. */
675 {
676 printf("ad_intr: (should not happen) dropped input.\n");
677 (void)inb(ADFIFO(ctlr));
678
679 printf("bp %0p, status %x, cr3 %x\n", bp, status,
680 ctlr->cr_image[2]);
681
682 ctlr->err = DROPPED_INPUT;
683 return;
684 }
685 }
686 }
687 }
688
689 void labpcintr(int unit)
690 {
691 struct ctlr *ctlr = labpcs[unit];
692 (*ctlr->intr)(ctlr);
693 }
694
695 /* lockout_multiple_opens: Return whether or not we can open again, or
696 * if the new mode is inconsistent with an already opened mode.
697 * We only permit multiple opens for digital I/O now.
698 */
699
700 static int
701 lockout_multiple_open(dev_t current, dev_t next)
702 {
703 return ! (DIGITAL(current) && DIGITAL(next));
704 }
705
706 static int
707 labpcopen(dev_t dev, int flags, int fmt, struct proc *p)
708 {
709 u_short unit = UNIT(dev);
710
711 struct ctlr *ctlr;
712
713 if (unit >= MAX_UNITS)
714 return ENXIO;
715
716 ctlr = labpcs[unit];
717
718 if (ctlr == 0)
719 return ENXIO;
720
721 /* Don't allow another open if we have to change modes.
722 */
723
724 if ( (ctlr->flags & BUSY) == 0)
725 {
726 ctlr->flags |= BUSY;
727
728 reset(ctlr);
729
730 ctlr->err = 0;
731 ctlr->dev = dev;
732
733 ctlr->intr = null_intr;
734 ctlr->starter = null_start;
735 ctlr->stop = null_stop;
736 }
737 else if (lockout_multiple_open(ctlr->dev, dev))
738 return EBUSY;
739
740 return 0;
741 }
742
743 static int
744 labpcclose(dev_t dev, int flags, int fmt, struct proc *p)
745 {
746 struct ctlr *ctlr = labpcs[UNIT(dev)];
747
748 (*ctlr->stop)(ctlr);
749
750 ctlr->flags &= ~BUSY;
751
752 return 0;
753 }
754
755 /* Start: Start a frame going in or out.
756 */
757 static void
758 start(struct ctlr *ctlr)
759 {
760 struct buf *bp;
761
762 if ((bp = ctlr->start_queue.b_actf) == 0)
763 {
764 /* We must turn off FIFO interrupts when there is no
765 * place to put the data. We have to get back to
766 * reading before the FIFO overflows.
767 */
768 CR_EXPR(ctlr, 3, &= ~(FIFOINTEN|ERRINTEN));
769 ctlr->cleared_intr = 1;
770 ctlr->start_queue.b_bcount = 0;
771 return;
772 }
773
774 ctlr->data = (u_char *)bp->b_un.b_addr;
775 ctlr->data_end = ctlr->data + bp->b_bcount;
776
777 if (ctlr->err)
778 {
779 printf("labpc start: (should not happen) error between records.\n");
780 done_and_start_next(ctlr, bp, EIO);
781 return;
782 }
783
784 if (ctlr->data == 0)
785 {
786 printf("labpc start: (should not happen) NULL data pointer.\n");
787 done_and_start_next(ctlr, bp, EIO);
788 return;
789 }
790
791
792 (*ctlr->starter)(ctlr, bp->b_bcount);
793
794 if (!FIFOINTENABLED(ctlr)) /* We can store the data again */
795 {
796 CR_EXPR(ctlr, 3, |= (FIFOINTEN|ERRINTEN));
797
798 /* Don't wait for the interrupts to fill things up.
799 */
800 (*ctlr->intr)(ctlr);
801 }
802
803 timeout(tmo_stop, ctlr, ctlr->tmo);
804 }
805
806 static void
807 ad_strategy(struct buf *bp, struct ctlr *ctlr)
808 {
809 int s;
810
811 s = spltty();
812 bp->b_actf = NULL;
813
814 if (ctlr->start_queue.b_bcount)
815 {
816 ctlr->last->b_actf = bp;
817 ctlr->last = bp;
818 }
819 else
820 {
821 ctlr->start_queue.b_bcount = 1;
822 ctlr->start_queue.b_actf = bp;
823 ctlr->last = bp;
824 start(ctlr);
825 }
826 splx(s);
827 }
828
829 /* da_strategy: Send data to the D-A. The CHAN field should be
830 * 0: D-A port 0
831 * 1: D-A port 1
832 * 2: Alternate port 0 then port 1
833 *
834 * XXX:
835 *
836 * 1. There is no state for CHAN field 2:
837 * the first sample in each buffer goes to channel 0.
838 *
839 * 2. No interrupt support yet.
840 */
841 static void
842 da_strategy(struct buf *bp, struct ctlr *ctlr)
843 {
844 int len;
845 u_char *data;
846 int port;
847 int i;
848
849 switch(CHAN(bp->b_dev))
850 {
851 case 0:
852 port = DAC0L(ctlr);
853 break;
854
855 case 1:
856 port = DAC1L(ctlr);
857 break;
858
859 case 2: /* Device 2 handles both ports interleaved. */
860 if (bp->b_bcount <= 2)
861 {
862 port = DAC0L(ctlr);
863 break;
864 }
865
866 len = bp->b_bcount / 2;
867 data = (u_char *)bp->b_un.b_addr;
868
869 for (i = 0; i < len; i++)
870 {
871 loutb(DAC0H(ctlr), *data++);
872 loutb(DAC0L(ctlr), *data++);
873 loutb(DAC1H(ctlr), *data++);
874 loutb(DAC1L(ctlr), *data++);
875 }
876
877 bp->b_resid = bp->b_bcount & 3;
878 bp_done(bp, 0);
879 return;
880
881 default:
882 bp_done(bp, ENXIO);
883 return;
884 }
885
886 /* Port 0 or 1 falls through to here.
887 */
888 if (bp->b_bcount & 1) /* Odd transfers are illegal */
889 bp_done(bp, EIO);
890
891 len = bp->b_bcount;
892 data = (u_char *)bp->b_un.b_addr;
893
894 for (i = 0; i < len; i++)
895 {
896 loutb(port + 1, *data++);
897 loutb(port, *data++);
898 }
899
900 bp->b_resid = 0;
901
902 bp_done(bp, 0);
903 }
904
905 /* Input masks for MODE 0 of the ports treating PC as a single
906 * 8 bit port. Set these bits to set the port to input.
907 */
908 /* A B lowc highc combined */
909 static u_char set_input[] = { 0x10, 0x02, 0x01, 0x08, 0x09 };
910
911 static void flush_dcr(struct ctlr *ctlr)
912 {
913 if (ctlr->dcr_is != ctlr->dcr_val)
914 {
915 loutb(DCR(ctlr), ctlr->dcr_val);
916 ctlr->dcr_is = ctlr->dcr_val;
917 }
918 }
919
920 /* do: Digital output
921 */
922 static void
923 digital_out_strategy(struct buf *bp, struct ctlr *ctlr)
924 {
925 int len;
926 u_char *data;
927 int port;
928 int i;
929 int chan = CHAN(bp->b_dev);
930
931 ctlr->dcr_val &= ~set_input[chan]; /* Digital out: Clear bit */
932 flush_dcr(ctlr);
933
934 port = PORTX(ctlr, chan);
935
936 len = bp->b_bcount;
937 data = (u_char *)bp->b_un.b_addr;
938
939 for (i = 0; i < len; i++)
940 {
941 loutb(port, *data++);
942 }
943
944 bp->b_resid = 0;
945
946 bp_done(bp, 0);
947 }
948
949 /* digital_in_strategy: Digital input
950 */
951 static void
952 digital_in_strategy(struct buf *bp, struct ctlr *ctlr)
953 {
954 int len;
955 u_char *data;
956 int port;
957 int i;
958 int chan = CHAN(bp->b_dev);
959
960 ctlr->dcr_val |= set_input[chan]; /* Digital in: Set bit */
961 flush_dcr(ctlr);
962 port = PORTX(ctlr, chan);
963
964 len = bp->b_bcount;
965 data = (u_char *)bp->b_un.b_addr;
966
967 for (i = 0; i < len; i++)
968 {
969 *data++ = inb(port);
970 }
971
972 bp->b_resid = 0;
973
974 bp_done(bp, 0);
975 }
976
977
978 static void
979 labpcstrategy(struct buf *bp)
980 {
981 struct ctlr *ctlr = labpcs[UNIT(bp->b_dev)];
982
983 if (DIGITAL(bp->b_dev)) {
984 if (bp->b_flags & B_READ) {
985 ctlr->starter = null_start;
986 ctlr->stop = all_stop;
987 ctlr->intr = null_intr;
988 digital_in_strategy(bp, ctlr);
989 }
990 else
991 {
992 ctlr->starter = null_start;
993 ctlr->stop = all_stop;
994 ctlr->intr = null_intr;
995 digital_out_strategy(bp, ctlr);
996 }
997 }
998 else {
999 if (bp->b_flags & B_READ) {
1000
1001 ctlr->starter = INTERVAL(ctlr->dev) ? ad_interval_start : ad_start;
1002 ctlr->stop = all_stop;
1003 ctlr->intr = ad_intr;
1004 ad_strategy(bp, ctlr);
1005 }
1006 else
1007 {
1008 ctlr->starter = null_start;
1009 ctlr->stop = all_stop;
1010 ctlr->intr = null_intr;
1011 da_strategy(bp, ctlr);
1012 }
1013 }
1014 }
1015
1016 static int
1017 labpcioctl(dev_t dev, int cmd, caddr_t arg, int mode, struct proc *p)
1018 {
1019 struct ctlr *ctlr = labpcs[UNIT(dev)];
1020
1021 switch(cmd)
1022 {
1023 case AD_MICRO_PERIOD_SET:
1024 {
1025 /* XXX I'm only supporting what I have to, which is
1026 * no slow periods. You can't get any slower than 15 Hz
1027 * with the current setup. To go slower you'll need to
1028 * support TCINTEN in CR3.
1029 */
1030
1031 long sample_us = *(long *)arg;
1032
1033 if (sample_us > 65535)
1034 return EIO;
1035
1036 ctlr->sample_us = sample_us;
1037 return 0;
1038 }
1039
1040 case AD_MICRO_PERIOD_GET:
1041 *(long *)arg = ctlr->sample_us;
1042 return 0;
1043
1044 case AD_NGAINS_GET:
1045 *(int *)arg = 8;
1046 return 0;
1047
1048 case AD_NCHANS_GET:
1049 *(int *)arg = 8;
1050 return 0;
1051
1052 case AD_SUPPORTED_GAINS:
1053 {
1054 static double gains[] = {1., 1.25, 2., 5., 10., 20., 50., 100.};
1055 copyout(gains, *(caddr_t *)arg, sizeof(gains));
1056
1057 return 0;
1058 }
1059
1060 case AD_GAINS_SET:
1061 {
1062 copyin(*(caddr_t *)arg, ctlr->gains, sizeof(ctlr->gains));
1063 return 0;
1064 }
1065
1066 case AD_GAINS_GET:
1067 {
1068 copyout(ctlr->gains, *(caddr_t *)arg, sizeof(ctlr->gains));
1069 return 0;
1070 }
1071
1072 default:
1073 return ENOTTY;
1074 }
1075 }
1076
1077
1078 static labpc_devsw_installed = 0;
1079
1080 static void labpc_drvinit(void *unused)
1081 {
1082 dev_t dev;
1083
1084 if( ! labpc_devsw_installed ) {
1085 dev = makedev(CDEV_MAJOR,0);
1086 cdevsw_add(&dev,&labpc_cdevsw,NULL);
1087 labpc_devsw_installed = 1;
1088 }
1089 }
1090
1091 SYSINIT(labpcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,labpc_drvinit,NULL)
1092
1093
Cache object: c42d8b2c1d10feed1d4bdb367640ff9f
|