The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/labpc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.