diff options
Diffstat (limited to 'sys/i386/isa/labpc.c')
-rw-r--r-- | sys/i386/isa/labpc.c | 1091 |
1 files changed, 0 insertions, 1091 deletions
diff --git a/sys/i386/isa/labpc.c b/sys/i386/isa/labpc.c deleted file mode 100644 index 1f0800c..0000000 --- a/sys/i386/isa/labpc.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * Copyright (c) 1995 HD Associates, Inc. - * All rights reserved. - * - * HD Associates, Inc. - * PO Box 276 - * Pepperell, MA 01463-0276 - * dufault@hda.com - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by HD Associates, Inc. - * 4. The name of HD Associates, Inc. - * may not be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Written by: - * Peter Dufault - * dufault@hda.com - * - * $FreeBSD$ - * - */ - -#include "labpc.h" -#include "opt_debug_outb.h" -#include <sys/param.h> - -#include <sys/systm.h> - -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/bio.h> -#define b_actf bio_queue.tqe_next -#include <sys/dataacq.h> -#include <sys/conf.h> -#include <sys/bus.h> - -#ifdef LOUTB -#endif - -#include <i386/isa/isa_device.h> - - - -/* Miniumum timeout: - */ -#ifndef LABPC_MIN_TMO -#define LABPC_MIN_TMO (hz) -#endif - -#ifndef LABPC_DEFAULT_HERZ -#define LABPC_DEFAULT_HERZ 500 -#endif - -/* Minor number: - * UUSIDCCC - * UU: Board unit. - * S: SCAN bit for scan enable. - * I: INTERVAL for interval support - * D: 1: Digital I/O, 0: Analog I/O - * CCC: Channel. - * Analog (D==0): - * input: channel must be 0 to 7. - * output: channel must be 0 to 2 - * 0: D-A 0 - * 1: D-A 1 - * 2: Alternate channel 0 then 1 - * - * Digital (D==1): - * input: Channel must be 0 to 2. - * output: Channel must be 0 to 2. - */ - -/* Up to four boards: - */ -#define MAX_UNITS 4 -#define UNIT(dev) (((minor(dev) & 0xB0) >> 6) & 0x3) - -#define SCAN(dev) ((minor(dev) & 0x20) >> 5) -#define INTERVAL(dev) ((minor(dev) & 0x10) >> 4) -#define DIGITAL(dev) ((minor(dev) & 0x08) >> 3) - -/* Eight channels: - */ - -#define CHAN(dev) (minor(dev) & 0x7) - -/* History: Derived from "dt2811.c" March 1995 - */ - -struct ctlr -{ - int err; -#define DROPPED_INPUT 0x100 - int base; - int unit; - unsigned long flags; -#define BUSY 0x00000001 - - u_char cr_image[4]; - - u_short sample_us; - - struct bio start_queue; /* Start queue */ - struct bio *last; /* End of start queue */ - u_char *data; - u_char *data_end; - long tmo; /* Timeout in Herz */ - long min_tmo; /* Timeout in Herz */ - int cleared_intr; - - int gains[8]; - - dev_t dev; /* Copy of device */ - - void (*starter)(struct ctlr *ctlr, long count); - void (*stop)(struct ctlr *ctlr); - void (*intr)(struct ctlr *ctlr); - - /* Digital I/O support. Copy of Data Control Register for 8255: - */ - u_char dcr_val, dcr_is; - - /* - * Handle for canceling our timeout. - */ - struct callout_handle ch; - - /* Device configuration structure: - */ -}; - -#ifdef LOUTB -/* loutb is a slow outb for debugging. The overrun test may fail - * with this for some slower processors. - */ -static __inline void loutb(int port, u_char val) -{ - outb(port, val); - DELAY(1); -} -#else -#define loutb(port, val) outb(port, val) -#endif - -static struct ctlr **labpcs; /* XXX: Should be dynamic */ - -/* CR_EXPR: A macro that sets the shadow register in addition to - * sending out the data. - */ -#define CR_EXPR(LABPC, CR, EXPR) do { \ - (LABPC)->cr_image[CR - 1] EXPR ; \ - loutb(((LABPC)->base + ( (CR == 4) ? (0x0F) : (CR - 1))), ((LABPC)->cr_image[(CR - 1)])); \ -} while (0) - -#define CR_CLR(LABPC, CR) CR_EXPR(LABPC, CR, &=0) -#define CR_REFRESH(LABPC, CR) CR_EXPR(LABPC, CR, &=0xff) -#define CR_SET(LABPC, CR, EXPR) CR_EXPR(LABPC, CR, = EXPR) - -/* Configuration and Status Register Group. - */ -#define CR1(LABPC) ((LABPC)->base + 0x00) /* Page 4-5 */ - #define SCANEN 0x80 - #define GAINMASK 0x70 - #define GAIN(LABPC, SEL) do { \ - (LABPC)->cr_image[1 - 1] &= ~GAINMASK; \ - (LABPC)->cr_image[1 - 1] |= (SEL << 4); \ - loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \ - } while (0) - - #define TWOSCMP 0x08 - #define MAMASK 0x07 - #define MA(LABPC, SEL) do { \ - (LABPC)->cr_image[1 - 1] &= ~MAMASK; \ - (LABPC)->cr_image[1 - 1] |= SEL; \ - loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \ - } while (0) - -#define STATUS(LABPC) ((LABPC)->base + 0x00) /* Page 4-7 */ - #define LABPCPLUS 0x80 - #define EXTGATA0 0x40 - #define GATA0 0x20 - #define DMATC 0x10 - #define CNTINT 0x08 - #define OVERFLOW 0x04 - #define OVERRUN 0x02 - #define DAVAIL 0x01 - -#define CR2(LABPC) ((LABPC)->base + 0x01) /* Page 4-9 */ - #define LDAC1 0x80 - #define LDAC0 0x40 - #define _2SDAC1 0x20 - #define _2SDAC0 0x10 - #define TBSEL 0x08 - #define SWTRIG 0x04 - #define HWTRIG 0x02 - #define PRETRIG 0x01 - #define SWTRIGGERRED(LABPC) ((LABPC->cr_image[1]) & SWTRIG) - -#define CR3(LABPC) ((LABPC)->base + 0x02) /* Page 4-11 */ - #define FIFOINTEN 0x20 - #define ERRINTEN 0x10 - #define CNTINTEN 0x08 - #define TCINTEN 0x04 - #define DIOINTEN 0x02 - #define DMAEN 0x01 - - #define ALLINTEN 0x3E - #define FIFOINTENABLED(LABPC) ((LABPC->cr_image[2]) & FIFOINTEN) - -#define CR4(LABPC) ((LABPC)->base + 0x0F) /* Page 4-13 */ - #define ECLKRCV 0x10 - #define SE_D 0x08 - #define ECKDRV 0x04 - #define EOIRCV 0x02 - #define INTSCAN 0x01 - -/* Analog Input Register Group - */ -#define ADFIFO(LABPC) ((LABPC)->base + 0x0A) /* Page 4-16 */ -#define ADCLEAR(LABPC) ((LABPC)->base + 0x08) /* Page 4-18 */ -#define ADSTART(LABPC) ((LABPC)->base + 0x03) /* Page 4-19 */ -#define DMATCICLR(LABPC) ((LABPC)->base + 0x0A) /* Page 4-20 */ - -/* Analog Output Register Group - */ -#define DAC0L(LABPC) ((LABPC)->base + 0x04) /* Page 4-22 */ -#define DAC0H(LABPC) ((LABPC)->base + 0x05) /* Page 4-22 */ -#define DAC1L(LABPC) ((LABPC)->base + 0x06) /* Page 4-22 */ -#define DAC1H(LABPC) ((LABPC)->base + 0x07) /* Page 4-22 */ - -/* 8253 registers: - */ -#define A0DATA(LABPC) ((LABPC)->base + 0x14) -#define A1DATA(LABPC) ((LABPC)->base + 0x15) -#define A2DATA(LABPC) ((LABPC)->base + 0x16) -#define AMODE(LABPC) ((LABPC)->base + 0x17) - -#define TICR(LABPC) ((LABPC)->base + 0x0c) - -#define B0DATA(LABPC) ((LABPC)->base + 0x18) -#define B1DATA(LABPC) ((LABPC)->base + 0x19) -#define B2DATA(LABPC) ((LABPC)->base + 0x1A) -#define BMODE(LABPC) ((LABPC)->base + 0x1B) - -/* 8255 registers: - */ - -#define PORTX(LABPC, X) ((LABPC)->base + 0x10 + X) - -#define PORTA(LABPC) PORTX(LABPC, 0) -#define PORTB(LABPC) PORTX(LABPC, 1) -#define PORTC(LABPC) PORTX(LABPC, 2) - -#define DCR(LABPC) ((LABPC)->base + 0x13) - -static int labpcattach(struct isa_device *dev); -static int labpcprobe(struct isa_device *dev); -struct isa_driver labpcdriver = { - INTR_TYPE_TTY, - labpcprobe, - labpcattach, - "labpc", - 0 -}; -COMPAT_ISA_DRIVER(labpc, labpcdriver); - -static d_open_t labpcopen; -static d_close_t labpcclose; -static d_ioctl_t labpcioctl; -static d_strategy_t labpcstrategy; - -#define CDEV_MAJOR 66 -static struct cdevsw labpc_cdevsw = { - /* open */ labpcopen, - /* close */ labpcclose, - /* read */ physread, - /* write */ physwrite, - /* ioctl */ labpcioctl, - /* poll */ nopoll, - /* mmap */ nommap, - /* strategy */ labpcstrategy, - /* name */ "labpc", - /* maj */ CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 -}; - -static ointhand2_t labpcintr; -static void start(struct ctlr *ctlr); - -static void -bp_done(struct bio *bp, int err) -{ - bp->bio_error = err; - - if (err || bp->bio_resid) - { - bp->bio_flags |= BIO_ERROR; - } - - biodone(bp); -} - -static void tmo_stop(void *p); - -static void -done_and_start_next(struct ctlr *ctlr, struct bio *bp, int err) -{ - bp->bio_resid = ctlr->data_end - ctlr->data; - - ctlr->data = 0; - - ctlr->start_queue.b_actf = bp->b_actf; - bp_done(bp, err); - - untimeout(tmo_stop, ctlr, ctlr->ch); - - start(ctlr); -} - -static __inline void -ad_clear(struct ctlr *ctlr) -{ - int i; - loutb(ADCLEAR(ctlr), 0); - for (i = 0; i < 10000 && (inb(STATUS(ctlr)) & GATA0); i++) - ; - (void)inb(ADFIFO(ctlr)); - (void)inb(ADFIFO(ctlr)); -} - -/* reset: Reset the board following the sequence on page 5-1 - */ -static __inline void -reset(struct ctlr *ctlr) -{ - int s = splhigh(); - - CR_CLR(ctlr, 3); /* Turn off interrupts first */ - splx(s); - - CR_CLR(ctlr, 1); - CR_CLR(ctlr, 2); - CR_CLR(ctlr, 4); - - loutb(AMODE(ctlr), 0x34); - loutb(A0DATA(ctlr),0x0A); - loutb(A0DATA(ctlr),0x00); - - loutb(DMATCICLR(ctlr), 0x00); - loutb(TICR(ctlr), 0x00); - - ad_clear(ctlr); - - loutb(DAC0L(ctlr), 0); - loutb(DAC0H(ctlr), 0); - loutb(DAC1L(ctlr), 0); - loutb(DAC1H(ctlr), 0); - - ad_clear(ctlr); -} - -/* overrun: slam the start convert register and OVERRUN should get set: - */ -static u_char -overrun(struct ctlr *ctlr) -{ - int i; - - u_char status = inb(STATUS(ctlr)); - for (i = 0; ((status & OVERRUN) == 0) && i < 100; i++) - { - loutb(ADSTART(ctlr), 1); - status = inb(STATUS(ctlr)); - } - - return status; -} - -static int -labpcinit(void) -{ - if (NLABPC > MAX_UNITS) - return 0; - - labpcs = malloc(NLABPC * sizeof(struct ctlr *), M_DEVBUF, - M_NOWAIT | M_ZERO); - if (labpcs == NULL) - return 0; - - cdevsw_add(&labpc_cdevsw); - return 1; -} - -static int -labpcprobe(struct isa_device *dev) -{ - static int unit; - struct ctlr scratch, *ctlr; - u_char status; - - if (!labpcs) - { - if (labpcinit() == 0) - { - printf("labpcprobe: init failed\n"); - return 0; - } - } - - if (unit > NLABPC) - { - printf("Too many LAB-PCs. Reconfigure O/S.\n"); - return 0; - } - ctlr = &scratch; /* Need somebody with the right base for the macros */ - ctlr->base = dev->id_iobase; - - /* XXX: There really isn't a perfect way to probe this board. - * Here is my best attempt: - */ - reset(ctlr); - - /* After reset none of these bits should be set: - */ - status = inb(STATUS(ctlr)); - if (status & (GATA0 | OVERFLOW | DAVAIL | OVERRUN)) - return 0; - - /* Now try to overrun the board FIFO and get the overrun bit set: - */ - status = overrun(ctlr); - - if ((status & OVERRUN) == 0) /* No overrun bit set? */ - return 0; - - /* Assume we have a board. - */ - reset(ctlr); - - if ( (labpcs[unit] = malloc(sizeof(struct ctlr), M_DEVBUF, M_NOWAIT)) ) - { - struct ctlr *l = labpcs[unit]; - - bzero(l, sizeof(struct ctlr)); - l->base = ctlr->base; - dev->id_unit = l->unit = unit; - - unit++; - return 0x20; - } - else - { - printf("labpc%d: Can't malloc.\n", unit); - return 0; - } -} - -/* attach: Set things in a normal state. - */ -static int -labpcattach(struct isa_device *dev) -{ - struct ctlr *ctlr = labpcs[dev->id_unit]; - - dev->id_ointr = labpcintr; - callout_handle_init(&ctlr->ch); - ctlr->sample_us = (1000000.0 / (double)LABPC_DEFAULT_HERZ) + .50; - reset(ctlr); - - ctlr->min_tmo = LABPC_MIN_TMO; - - ctlr->dcr_val = 0x80; - ctlr->dcr_is = 0x80; - loutb(DCR(ctlr), ctlr->dcr_val); - - make_dev(&labpc_cdevsw, 0, 0, 0, 0600, "labpc%d", dev->id_unit); - return 1; -} - -/* Null handlers: - */ -static void null_intr (struct ctlr *ctlr) { } -static void null_start(struct ctlr *ctlr, long count) { } -static void null_stop (struct ctlr *ctlr) { } - -static __inline void -trigger(struct ctlr *ctlr) -{ - CR_EXPR(ctlr, 2, |= SWTRIG); -} - -static void -ad_start(struct ctlr *ctlr, long count) -{ - if (!SWTRIGGERRED(ctlr)) { - int chan = CHAN(ctlr->dev); - CR_EXPR(ctlr, 1, &= ~SCANEN); - CR_EXPR(ctlr, 2, &= ~TBSEL); - - MA(ctlr, chan); - GAIN(ctlr, ctlr->gains[chan]); - - if (SCAN(ctlr->dev)) - CR_EXPR(ctlr, 1, |= SCANEN); - - loutb(AMODE(ctlr), 0x34); - loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us & 0xff))); - loutb(A0DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff)); - loutb(AMODE(ctlr), 0x70); - - ad_clear(ctlr); - trigger(ctlr); - } - - ctlr->tmo = ((count + 16) * (long)ctlr->sample_us * hz) / 1000000 + - ctlr->min_tmo; -} - -static void -ad_interval_start(struct ctlr *ctlr, long count) -{ - int chan = CHAN(ctlr->dev); - int n_frames = count / (chan + 1); - - if (!SWTRIGGERRED(ctlr)) { - CR_EXPR(ctlr, 1, &= ~SCANEN); - CR_EXPR(ctlr, 2, &= ~TBSEL); - - MA(ctlr, chan); - GAIN(ctlr, ctlr->gains[chan]); - - /* XXX: Is it really possible that you clear INTSCAN as - * the documentation says? That seems pretty unlikely. - */ - CR_EXPR(ctlr, 4, &= ~INTSCAN); /* XXX: Is this possible? */ - - /* Program the sample interval counter to run as fast as - * possible. - */ - loutb(AMODE(ctlr), 0x34); - loutb(A0DATA(ctlr), (u_char)(0x02)); - loutb(A0DATA(ctlr), (u_char)(0x00)); - loutb(AMODE(ctlr), 0x70); - - /* Program the interval scanning counter to run at the sample - * frequency. - */ - loutb(BMODE(ctlr), 0x74); - loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us & 0xff))); - loutb(B1DATA(ctlr), (u_char)((ctlr->sample_us >> 8)&0xff)); - CR_EXPR(ctlr, 1, |= SCANEN); - - ad_clear(ctlr); - trigger(ctlr); - } - - /* Each frame time takes two microseconds per channel times - * the number of channels being sampled plus the sample period. - */ - ctlr->tmo = ((n_frames + 16) * - ((long)ctlr->sample_us + (chan + 1 ) * 2 ) * hz) / 1000000 + - ctlr->min_tmo; -} - -static void -all_stop(struct ctlr *ctlr) -{ - reset(ctlr); -} - -static void -tmo_stop(void *p) -{ - struct ctlr *ctlr = (struct ctlr *)p; - struct bio *bp; - - int s = spltty(); - - if (ctlr == 0) - { - printf("labpc?: Null ctlr struct?\n"); - splx(s); - return; - } - - printf("labpc%d: timeout", ctlr->unit); - - (*ctlr->stop)(ctlr); - - bp = ctlr->start_queue.b_actf; - - if (bp == 0) { - printf(", Null bp.\n"); - splx(s); - return; - } - - printf("\n"); - - done_and_start_next(ctlr, bp, ETIMEDOUT); - - splx(s); -} - -static void ad_intr(struct ctlr *ctlr) -{ - u_char status; - - if (ctlr->cr_image[2] == 0) - { - if (ctlr->cleared_intr) - { - ctlr->cleared_intr = 0; - return; - } - - printf("ad_intr (should not happen) interrupt with interrupts off\n"); - printf("status %x, cr3 %x\n", inb(STATUS(ctlr)), ctlr->cr_image[2]); - return; - } - - while ( (status = (inb(STATUS(ctlr)) & (DAVAIL|OVERRUN|OVERFLOW)) ) ) - { - if ((status & (OVERRUN|OVERFLOW))) - { - struct bio *bp = ctlr->start_queue.b_actf; - - printf("ad_intr: error: bp %p, data %p, status %x", - (void *)bp, (void *)ctlr->data, status); - - if (status & OVERRUN) - printf(" Conversion overrun (multiple A-D trigger)"); - - if (status & OVERFLOW) - printf(" FIFO overflow"); - - printf("\n"); - - if (bp) - { - done_and_start_next(ctlr, bp, EIO); - return; - } - else - { - printf("ad_intr: (should not happen) error between records\n"); - ctlr->err = status; /* Set overrun condition */ - return; - } - } - else /* FIFO interrupt */ - { - struct bio *bp = ctlr->start_queue.b_actf; - - if (ctlr->data) - { - *ctlr->data++ = inb(ADFIFO(ctlr)); - if (ctlr->data == ctlr->data_end) /* Normal completion */ - { - done_and_start_next(ctlr, bp, 0); - return; - } - } - else /* Interrupt with no where to put the data. */ - { - printf("ad_intr: (should not happen) dropped input.\n"); - (void)inb(ADFIFO(ctlr)); - - printf("bp %p, status %x, cr3 %x\n", - (void *)bp, status, ctlr->cr_image[2]); - - ctlr->err = DROPPED_INPUT; - return; - } - } - } -} - -static void labpcintr(int unit) -{ - struct ctlr *ctlr = labpcs[unit]; - (*ctlr->intr)(ctlr); -} - -/* lockout_multiple_opens: Return whether or not we can open again, or - * if the new mode is inconsistent with an already opened mode. - * We only permit multiple opens for digital I/O now. - */ - -static int -lockout_multiple_open(dev_t current, dev_t next) -{ - return ! (DIGITAL(current) && DIGITAL(next)); -} - -static int -labpcopen(dev_t dev, int flags, int fmt, struct proc *p) -{ - u_short unit = UNIT(dev); - - struct ctlr *ctlr; - - if (unit >= MAX_UNITS) - return ENXIO; - - ctlr = labpcs[unit]; - - if (ctlr == 0) - return ENXIO; - - /* Don't allow another open if we have to change modes. - */ - - if ( (ctlr->flags & BUSY) == 0) - { - ctlr->flags |= BUSY; - - reset(ctlr); - - ctlr->err = 0; - ctlr->dev = dev; - - ctlr->intr = null_intr; - ctlr->starter = null_start; - ctlr->stop = null_stop; - } - else if (lockout_multiple_open(ctlr->dev, dev)) - return EBUSY; - - return 0; -} - -static int -labpcclose(dev_t dev, int flags, int fmt, struct proc *p) -{ - struct ctlr *ctlr = labpcs[UNIT(dev)]; - - (*ctlr->stop)(ctlr); - - ctlr->flags &= ~BUSY; - - return 0; -} - -/* - * Start: Start a frame going in or out. - */ -static void -start(struct ctlr *ctlr) -{ - struct bio *bp; - - if ((bp = ctlr->start_queue.b_actf) == 0) - { - /* We must turn off FIFO interrupts when there is no - * place to put the data. We have to get back to - * reading before the FIFO overflows. - */ - CR_EXPR(ctlr, 3, &= ~(FIFOINTEN|ERRINTEN)); - ctlr->cleared_intr = 1; - ctlr->start_queue.bio_bcount = 0; - return; - } - - ctlr->data = (u_char *)bp->bio_data; - ctlr->data_end = ctlr->data + bp->bio_bcount; - - if (ctlr->err) - { - printf("labpc start: (should not happen) error between records.\n"); - done_and_start_next(ctlr, bp, EIO); - return; - } - - if (ctlr->data == 0) - { - printf("labpc start: (should not happen) NULL data pointer.\n"); - done_and_start_next(ctlr, bp, EIO); - return; - } - - - (*ctlr->starter)(ctlr, bp->bio_bcount); - - if (!FIFOINTENABLED(ctlr)) /* We can store the data again */ - { - CR_EXPR(ctlr, 3, |= (FIFOINTEN|ERRINTEN)); - - /* Don't wait for the interrupts to fill things up. - */ - (*ctlr->intr)(ctlr); - } - - ctlr->ch = timeout(tmo_stop, ctlr, ctlr->tmo); -} - -static void -ad_strategy(struct bio *bp, struct ctlr *ctlr) -{ - int s; - - s = spltty(); - bp->b_actf = NULL; - - if (ctlr->start_queue.bio_bcount) - { - ctlr->last->b_actf = bp; - ctlr->last = bp; - } - else - { - ctlr->start_queue.bio_bcount = 1; - ctlr->start_queue.b_actf = bp; - ctlr->last = bp; - start(ctlr); - } - splx(s); -} - -/* da_strategy: Send data to the D-A. The CHAN field should be - * 0: D-A port 0 - * 1: D-A port 1 - * 2: Alternate port 0 then port 1 - * - * XXX: - * - * 1. There is no state for CHAN field 2: - * the first sample in each buffer goes to channel 0. - * - * 2. No interrupt support yet. - */ -static void -da_strategy(struct bio *bp, struct ctlr *ctlr) -{ - int len; - u_char *data; - int port; - int i; - - switch(CHAN(bp->bio_dev)) - { - case 0: - port = DAC0L(ctlr); - break; - - case 1: - port = DAC1L(ctlr); - break; - - case 2: /* Device 2 handles both ports interleaved. */ - if (bp->bio_bcount <= 2) - { - port = DAC0L(ctlr); - break; - } - - len = bp->bio_bcount / 2; - data = (u_char *)bp->bio_data; - - for (i = 0; i < len; i++) - { - loutb(DAC0H(ctlr), *data++); - loutb(DAC0L(ctlr), *data++); - loutb(DAC1H(ctlr), *data++); - loutb(DAC1L(ctlr), *data++); - } - - bp->bio_resid = bp->bio_bcount & 3; - bp_done(bp, 0); - return; - - default: - bp_done(bp, ENXIO); - return; - } - - /* Port 0 or 1 falls through to here. - */ - if (bp->bio_bcount & 1) /* Odd transfers are illegal */ - bp_done(bp, EIO); - - len = bp->bio_bcount; - data = (u_char *)bp->bio_data; - - for (i = 0; i < len; i++) - { - loutb(port + 1, *data++); - loutb(port, *data++); - } - - bp->bio_resid = 0; - - bp_done(bp, 0); -} - -/* Input masks for MODE 0 of the ports treating PC as a single - * 8 bit port. Set these bits to set the port to input. - */ - /* A B lowc highc combined */ -static u_char set_input[] = { 0x10, 0x02, 0x01, 0x08, 0x09 }; - -static void flush_dcr(struct ctlr *ctlr) -{ - if (ctlr->dcr_is != ctlr->dcr_val) - { - loutb(DCR(ctlr), ctlr->dcr_val); - ctlr->dcr_is = ctlr->dcr_val; - } -} - -/* do: Digital output - */ -static void -digital_out_strategy(struct bio *bp, struct ctlr *ctlr) -{ - int len; - u_char *data; - int port; - int i; - int chan = CHAN(bp->bio_dev); - - ctlr->dcr_val &= ~set_input[chan]; /* Digital out: Clear bit */ - flush_dcr(ctlr); - - port = PORTX(ctlr, chan); - - len = bp->bio_bcount; - data = (u_char *)bp->bio_data; - - for (i = 0; i < len; i++) - { - loutb(port, *data++); - } - - bp->bio_resid = 0; - - bp_done(bp, 0); -} - -/* digital_in_strategy: Digital input - */ -static void -digital_in_strategy(struct bio *bp, struct ctlr *ctlr) -{ - int len; - u_char *data; - int port; - int i; - int chan = CHAN(bp->bio_dev); - - ctlr->dcr_val |= set_input[chan]; /* Digital in: Set bit */ - flush_dcr(ctlr); - port = PORTX(ctlr, chan); - - len = bp->bio_bcount; - data = (u_char *)bp->bio_data; - - for (i = 0; i < len; i++) - { - *data++ = inb(port); - } - - bp->bio_resid = 0; - - bp_done(bp, 0); -} - - -static void -labpcstrategy(struct bio *bp) -{ - struct ctlr *ctlr = labpcs[UNIT(bp->bio_dev)]; - - if (DIGITAL(bp->bio_dev)) { - if (bp->bio_cmd == BIO_READ) { - ctlr->starter = null_start; - ctlr->stop = all_stop; - ctlr->intr = null_intr; - digital_in_strategy(bp, ctlr); - } - else - { - ctlr->starter = null_start; - ctlr->stop = all_stop; - ctlr->intr = null_intr; - digital_out_strategy(bp, ctlr); - } - } - else { - if (bp->bio_cmd == BIO_READ) { - - ctlr->starter = INTERVAL(ctlr->dev) ? ad_interval_start : ad_start; - ctlr->stop = all_stop; - ctlr->intr = ad_intr; - ad_strategy(bp, ctlr); - } - else - { - ctlr->starter = null_start; - ctlr->stop = all_stop; - ctlr->intr = null_intr; - da_strategy(bp, ctlr); - } - } -} - -static int -labpcioctl(dev_t dev, u_long cmd, caddr_t arg, int mode, struct proc *p) -{ - struct ctlr *ctlr = labpcs[UNIT(dev)]; - - switch(cmd) - { - case AD_MICRO_PERIOD_SET: - { - /* XXX I'm only supporting what I have to, which is - * no slow periods. You can't get any slower than 15 Hz - * with the current setup. To go slower you'll need to - * support TCINTEN in CR3. - */ - - long sample_us = *(long *)arg; - - if (sample_us > 65535) - return EIO; - - ctlr->sample_us = sample_us; - return 0; - } - - case AD_MICRO_PERIOD_GET: - *(long *)arg = ctlr->sample_us; - return 0; - - case AD_NGAINS_GET: - *(int *)arg = 8; - return 0; - - case AD_NCHANS_GET: - *(int *)arg = 8; - return 0; - - case AD_SUPPORTED_GAINS: - { - static double gains[] = {1., 1.25, 2., 5., 10., 20., 50., 100.}; - copyout(gains, *(caddr_t *)arg, sizeof(gains)); - - return 0; - } - - case AD_GAINS_SET: - { - copyin(*(caddr_t *)arg, ctlr->gains, sizeof(ctlr->gains)); - return 0; - } - - case AD_GAINS_GET: - { - copyout(ctlr->gains, *(caddr_t *)arg, sizeof(ctlr->gains)); - return 0; - } - - default: - return ENOTTY; - } -} |