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