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