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