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  * $FreeBSD$
   42  *
   43  */
   44 
   45 #include "labpc.h"
   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>
   54 #define b_actf  b_act.tqe_next
   55 #include <sys/dataacq.h>
   56 #include <sys/conf.h>
   57 
   58 #ifdef LOUTB
   59 #include <machine/clock.h>
   60 #endif
   61 
   62 #include <i386/isa/isa_device.h>
   63 
   64 
   65 
   66 /* Miniumum timeout:
   67  */
   68 #ifndef LABPC_MIN_TMO
   69 #define LABPC_MIN_TMO (hz)
   70 #endif
   71 
   72 #ifndef LABPC_DEFAULT_HERZ
   73 #define LABPC_DEFAULT_HERZ 500
   74 #endif
   75 
   76 /* Minor number:
   77  * UUSIDCCC
   78  * UU: Board unit.
   79  * S: SCAN bit for scan enable.
   80  * I: INTERVAL for interval support
   81  * D: 1: Digital I/O, 0: Analog I/O
   82  * CCC: Channel.
   83  *  Analog (D==0):
   84  *  input: channel must be 0 to 7.
   85  *  output: channel must be 0 to 2
   86  *          0: D-A 0
   87  *          1: D-A 1
   88  *          2: Alternate channel 0 then 1
   89  *
   90  *  Digital (D==1):
   91  *  input: Channel must be 0 to 2.
   92  *  output: Channel must be 0 to 2.
   93  */
   94 
   95 /* Up to four boards:
   96  */
   97 #define MAX_UNITS 4
   98 #define UNIT(dev) (((minor(dev) & 0xB0) >> 6) & 0x3)
   99 
  100 #define SCAN(dev)     ((minor(dev) & 0x20) >> 5)
  101 #define INTERVAL(dev) ((minor(dev) & 0x10) >> 4)
  102 #define DIGITAL(dev)  ((minor(dev) & 0x08) >> 3)
  103 
  104 /* Eight channels:
  105  */
  106 
  107 #define CHAN(dev) (minor(dev) & 0x7)
  108 
  109 /* History: Derived from "dt2811.c" March 1995
  110  */
  111 
  112 struct ctlr
  113 {
  114         int err;
  115 #define DROPPED_INPUT 0x100
  116         int base;
  117         int unit;
  118         unsigned long flags;
  119 #define BUSY 0x00000001
  120 
  121         u_char cr_image[4];
  122 
  123         u_short sample_us;
  124 
  125         struct buf start_queue; /* Start queue */
  126         struct buf *last;       /* End of start queue */
  127         u_char *data;
  128         u_char *data_end;
  129         long tmo;                       /* Timeout in Herz */
  130         long min_tmo;           /* Timeout in Herz */
  131         int cleared_intr;
  132 
  133         int gains[8];
  134 
  135         dev_t dev;                      /* Copy of device */
  136 
  137         void (*starter)(struct ctlr *ctlr, long count);
  138         void (*stop)(struct ctlr *ctlr);
  139         void (*intr)(struct ctlr *ctlr);
  140 
  141         /* Digital I/O support.  Copy of Data Control Register for 8255:
  142          */
  143         u_char dcr_val, dcr_is;
  144 
  145         /*
  146          * Handle for canceling our timeout.
  147          */
  148         struct callout_handle ch;
  149 
  150         /* Device configuration structure:
  151          */
  152 };
  153 
  154 #ifdef LOUTB
  155 /* loutb is a slow outb for debugging.  The overrun test may fail
  156  * with this for some slower processors.
  157  */
  158 static __inline void loutb(int port, u_char val)
  159 {
  160         outb(port, val);
  161         DELAY(1);
  162 }
  163 #else
  164 #define loutb(port, val) outb(port, val)
  165 #endif
  166 
  167 static struct ctlr **labpcs;    /* XXX: Should be dynamic */
  168 
  169 /* CR_EXPR: A macro that sets the shadow register in addition to
  170  * sending out the data.
  171  */
  172 #define CR_EXPR(LABPC, CR, EXPR) do { \
  173         (LABPC)->cr_image[CR - 1] EXPR ; \
  174         loutb(((LABPC)->base + ( (CR == 4) ? (0x0F) : (CR - 1))), ((LABPC)->cr_image[(CR - 1)])); \
  175 } while (0)
  176 
  177 #define CR_CLR(LABPC, CR) CR_EXPR(LABPC, CR, &=0)
  178 #define CR_REFRESH(LABPC, CR) CR_EXPR(LABPC, CR, &=0xff)
  179 #define CR_SET(LABPC, CR, EXPR) CR_EXPR(LABPC, CR, = EXPR)
  180 
  181 /* Configuration and Status Register Group.
  182  */
  183 #define     CR1(LABPC) ((LABPC)->base + 0x00)   /* Page 4-5 */
  184         #define SCANEN    0x80
  185         #define GAINMASK  0x70
  186         #define GAIN(LABPC, SEL) do { \
  187                 (LABPC)->cr_image[1 - 1] &= ~GAINMASK; \
  188                 (LABPC)->cr_image[1 - 1] |= (SEL << 4); \
  189                 loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \
  190                 } while (0)
  191 
  192         #define TWOSCMP   0x08
  193         #define MAMASK    0x07
  194         #define MA(LABPC, SEL) do { \
  195                 (LABPC)->cr_image[1 - 1] &= ~MAMASK; \
  196                 (LABPC)->cr_image[1 - 1] |= SEL; \
  197                 loutb((LABPC)->base + (1 - 1), (LABPC)->cr_image[(1 - 1)]); \
  198                 } while (0)
  199 
  200 #define  STATUS(LABPC) ((LABPC)->base + 0x00)   /* Page 4-7 */
  201         #define LABPCPLUS 0x80
  202         #define EXTGATA0  0x40
  203         #define GATA0     0x20
  204         #define DMATC     0x10
  205         #define CNTINT    0x08
  206         #define OVERFLOW  0x04
  207         #define OVERRUN   0x02
  208         #define DAVAIL    0x01
  209 
  210 #define     CR2(LABPC) ((LABPC)->base + 0x01)   /* Page 4-9 */
  211         #define LDAC1     0x80
  212         #define LDAC0     0x40
  213         #define _2SDAC1   0x20
  214         #define _2SDAC0   0x10
  215         #define TBSEL     0x08
  216         #define SWTRIG    0x04
  217         #define HWTRIG    0x02
  218         #define PRETRIG   0x01
  219         #define SWTRIGGERRED(LABPC) ((LABPC->cr_image[1]) & SWTRIG)
  220 
  221 #define     CR3(LABPC) ((LABPC)->base + 0x02)   /* Page 4-11 */
  222         #define FIFOINTEN 0x20
  223         #define ERRINTEN  0x10
  224         #define CNTINTEN  0x08
  225         #define TCINTEN   0x04
  226         #define DIOINTEN  0x02
  227         #define DMAEN     0x01
  228 
  229         #define ALLINTEN  0x3E
  230         #define FIFOINTENABLED(LABPC) ((LABPC->cr_image[2]) & FIFOINTEN)
  231 
  232 #define     CR4(LABPC) ((LABPC)->base + 0x0F)   /* Page 4-13 */
  233         #define ECLKRCV   0x10
  234         #define SE_D      0x08
  235         #define ECKDRV    0x04
  236         #define EOIRCV    0x02
  237         #define INTSCAN   0x01
  238 
  239 /* Analog Input Register Group
  240  */
  241 #define   ADFIFO(LABPC) ((LABPC)->base + 0x0A)  /* Page 4-16 */
  242 #define  ADCLEAR(LABPC) ((LABPC)->base + 0x08)  /* Page 4-18 */
  243 #define  ADSTART(LABPC) ((LABPC)->base + 0x03)  /* Page 4-19 */
  244 #define DMATCICLR(LABPC) ((LABPC)->base + 0x0A) /* Page 4-20 */
  245 
  246 /* Analog Output Register Group
  247  */
  248 #define    DAC0L(LABPC) ((LABPC)->base + 0x04)  /* Page 4-22 */
  249 #define    DAC0H(LABPC) ((LABPC)->base + 0x05)  /* Page 4-22 */
  250 #define    DAC1L(LABPC) ((LABPC)->base + 0x06)  /* Page 4-22 */
  251 #define    DAC1H(LABPC) ((LABPC)->base + 0x07)  /* Page 4-22 */
  252 
  253 /* 8253 registers:
  254  */
  255 #define A0DATA(LABPC) ((LABPC)->base + 0x14)
  256 #define A1DATA(LABPC) ((LABPC)->base + 0x15)
  257 #define A2DATA(LABPC) ((LABPC)->base + 0x16)
  258 #define AMODE(LABPC) ((LABPC)->base + 0x17)
  259 
  260 #define TICR(LABPC) ((LABPC)->base + 0x0c)
  261 
  262 #define B0DATA(LABPC) ((LABPC)->base + 0x18)
  263 #define B1DATA(LABPC) ((LABPC)->base + 0x19)
  264 #define B2DATA(LABPC) ((LABPC)->base + 0x1A)
  265 #define BMODE(LABPC) ((LABPC)->base + 0x1B)
  266 
  267 /* 8255 registers:
  268  */
  269 
  270 #define PORTX(LABPC, X) ((LABPC)->base + 0x10 + X)
  271 
  272 #define PORTA(LABPC) PORTX(LABPC, 0)
  273 #define PORTB(LABPC) PORTX(LABPC, 1)
  274 #define PORTC(LABPC) PORTX(LABPC, 2)
  275 
  276 #define DCR(LABPC) ((LABPC)->base + 0x13)
  277 
  278 static int labpcattach(struct isa_device *dev);
  279 static int labpcprobe(struct isa_device *dev);
  280 struct isa_driver labpcdriver =
  281         { labpcprobe, labpcattach, "labpc", 0  };
  282 
  283 static  d_open_t        labpcopen;
  284 static  d_close_t       labpcclose;
  285 static  d_ioctl_t       labpcioctl;
  286 static  d_strategy_t    labpcstrategy;
  287 
  288 #define CDEV_MAJOR 66
  289 static struct cdevsw labpc_cdevsw = {
  290         /* open */      labpcopen,
  291         /* close */     labpcclose,
  292         /* read */      physread,
  293         /* write */     physwrite,
  294         /* ioctl */     labpcioctl,
  295         /* poll */      nopoll,
  296         /* mmap */      nommap,
  297         /* strategy */  labpcstrategy,
  298         /* name */      "labpc",
  299         /* maj */       CDEV_MAJOR,
  300         /* dump */      nodump,
  301         /* psize */     nopsize,
  302         /* flags */     0,
  303         /* bmaj */      -1
  304 };
  305 
  306 static ointhand2_t labpcintr;
  307 static void start(struct ctlr *ctlr);
  308 
  309 static void
  310 bp_done(struct buf *bp, int err)
  311 {
  312         bp->b_error = err;
  313 
  314         if (err || bp->b_resid)
  315         {
  316                 bp->b_flags |= B_ERROR;
  317         }
  318 
  319         biodone(bp);
  320 }
  321 
  322 static void tmo_stop(void *p);
  323 
  324 static void
  325 done_and_start_next(struct ctlr *ctlr, struct buf *bp, int err)
  326 {
  327         bp->b_resid = ctlr->data_end - ctlr->data;
  328 
  329         ctlr->data = 0;
  330 
  331         ctlr->start_queue.b_actf = bp->b_actf;
  332         bp_done(bp, err);
  333 
  334         untimeout(tmo_stop, ctlr, ctlr->ch);
  335 
  336         start(ctlr);
  337 }
  338 
  339 static __inline void
  340 ad_clear(struct ctlr *ctlr)
  341 {
  342         int i;
  343         loutb(ADCLEAR(ctlr), 0);
  344         for (i = 0; i < 10000 && (inb(STATUS(ctlr)) & GATA0); i++)
  345                 ;
  346         (void)inb(ADFIFO(ctlr));
  347         (void)inb(ADFIFO(ctlr));
  348 }
  349 
  350 /* reset: Reset the board following the sequence on page 5-1
  351  */
  352 static __inline void
  353 reset(struct ctlr *ctlr)
  354 {
  355         int s = splhigh();
  356 
  357         CR_CLR(ctlr, 3);        /* Turn off interrupts first */
  358         splx(s);
  359 
  360         CR_CLR(ctlr, 1);
  361         CR_CLR(ctlr, 2);
  362         CR_CLR(ctlr, 4);
  363 
  364         loutb(AMODE(ctlr), 0x34);
  365         loutb(A0DATA(ctlr),0x0A);
  366         loutb(A0DATA(ctlr),0x00);
  367 
  368         loutb(DMATCICLR(ctlr), 0x00);
  369         loutb(TICR(ctlr), 0x00);
  370 
  371         ad_clear(ctlr);
  372 
  373         loutb(DAC0L(ctlr), 0);
  374         loutb(DAC0H(ctlr), 0);
  375         loutb(DAC1L(ctlr), 0);
  376         loutb(DAC1H(ctlr), 0);
  377 
  378         ad_clear(ctlr);
  379 }
  380 
  381 /* overrun: slam the start convert register and OVERRUN should get set:
  382  */
  383 static u_char
  384 overrun(struct ctlr *ctlr)
  385 {
  386         int i;
  387 
  388         u_char status = inb(STATUS(ctlr));
  389         for (i = 0; ((status & OVERRUN) == 0) && i < 100; i++)
  390         {
  391                 loutb(ADSTART(ctlr), 1);
  392                 status = inb(STATUS(ctlr));
  393         }
  394 
  395         return status;
  396 }
  397 
  398 static int
  399 labpcinit(void)
  400 {
  401         if (NLABPC > MAX_UNITS)
  402                 return 0;
  403 
  404         labpcs = malloc(NLABPC * sizeof(struct ctlr *), M_DEVBUF, M_NOWAIT);
  405         if (labpcs)
  406         {
  407                 bzero(labpcs, NLABPC * sizeof(struct ctlr *));
  408                 return 1;
  409         }
  410         cdevsw_add(&labpc_cdevsw);
  411         return 0;
  412 }
  413 
  414 static int
  415 labpcprobe(struct isa_device *dev)
  416 {
  417         static int unit;
  418         struct ctlr scratch, *ctlr;
  419         u_char status;
  420 
  421         if (!labpcs)
  422         {
  423                 if (labpcinit() == 0)
  424                 {
  425                         printf("labpcprobe: init failed\n");
  426                         return 0;
  427                 }
  428         }
  429 
  430         if (unit > NLABPC)
  431         {
  432                 printf("Too many LAB-PCs.  Reconfigure O/S.\n");
  433                 return 0;
  434         }
  435         ctlr = &scratch;        /* Need somebody with the right base for the macros */
  436         ctlr->base = dev->id_iobase;
  437 
  438         /* XXX: There really isn't a perfect way to probe this board.
  439          *      Here is my best attempt:
  440          */
  441         reset(ctlr);
  442 
  443         /* After reset none of these bits should be set:
  444          */
  445         status = inb(STATUS(ctlr));
  446         if (status & (GATA0 | OVERFLOW | DAVAIL | OVERRUN))
  447                 return 0;
  448 
  449         /* Now try to overrun the board FIFO and get the overrun bit set:
  450          */
  451         status = overrun(ctlr);
  452 
  453         if ((status & OVERRUN) == 0)    /* No overrun bit set? */
  454                 return 0;
  455 
  456         /* Assume we have a board.
  457          */
  458         reset(ctlr);
  459 
  460         if ( (labpcs[unit] = malloc(sizeof(struct ctlr), M_DEVBUF, M_NOWAIT)) )
  461         {
  462                 struct ctlr *l = labpcs[unit];
  463 
  464                 bzero(l, sizeof(struct ctlr));
  465                 l->base = ctlr->base;
  466                 dev->id_unit = l->unit = unit;
  467 
  468                 unit++;
  469                 return 0x20;
  470         }
  471         else
  472         {
  473                 printf("labpc%d: Can't malloc.\n", unit);
  474                 return 0;
  475         }
  476 }
  477 
  478 /* attach: Set things in a normal state.
  479  */
  480 static int
  481 labpcattach(struct isa_device *dev)
  482 {
  483         struct ctlr *ctlr = labpcs[dev->id_unit];
  484 
  485         dev->id_ointr = labpcintr;
  486         callout_handle_init(&ctlr->ch);
  487         ctlr->sample_us = (1000000.0 / (double)LABPC_DEFAULT_HERZ) + .50;
  488         reset(ctlr);
  489 
  490         ctlr->min_tmo = LABPC_MIN_TMO;
  491 
  492         ctlr->dcr_val = 0x80;
  493         ctlr->dcr_is = 0x80;
  494         loutb(DCR(ctlr), ctlr->dcr_val);
  495 
  496         make_dev(&labpc_cdevsw, 0, 0, 0, 0600, "labpc%d", dev->id_unit);
  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 /*
  766  * Start: Start a frame going in or out.
  767  */
  768 static void
  769 start(struct ctlr *ctlr)
  770 {
  771         struct buf *bp;
  772 
  773         if ((bp = ctlr->start_queue.b_actf) == 0)
  774         {
  775                 /* We must turn off FIFO interrupts when there is no
  776                  * place to put the data.  We have to get back to
  777                  * reading before the FIFO overflows.
  778                  */
  779                 CR_EXPR(ctlr, 3, &= ~(FIFOINTEN|ERRINTEN));
  780                 ctlr->cleared_intr = 1;
  781                 ctlr->start_queue.b_bcount = 0;
  782                 return;
  783         }
  784 
  785         ctlr->data = (u_char *)bp->b_data;
  786         ctlr->data_end = ctlr->data + bp->b_bcount;
  787 
  788         if (ctlr->err)
  789         {
  790                 printf("labpc start: (should not happen) error between records.\n");
  791                 done_and_start_next(ctlr, bp, EIO);
  792                 return;
  793         }
  794 
  795         if (ctlr->data == 0)
  796         {
  797                 printf("labpc start: (should not happen) NULL data pointer.\n");
  798                 done_and_start_next(ctlr, bp, EIO);
  799                 return;
  800         }
  801 
  802 
  803         (*ctlr->starter)(ctlr, bp->b_bcount);
  804 
  805         if (!FIFOINTENABLED(ctlr))      /* We can store the data again */
  806         {
  807                 CR_EXPR(ctlr, 3, |= (FIFOINTEN|ERRINTEN));
  808 
  809                 /* Don't wait for the interrupts to fill things up.
  810                  */
  811                 (*ctlr->intr)(ctlr);
  812         }
  813 
  814         ctlr->ch = timeout(tmo_stop, ctlr, ctlr->tmo);
  815 }
  816 
  817 static void
  818 ad_strategy(struct buf *bp, struct ctlr *ctlr)
  819 {
  820         int s;
  821 
  822         s = spltty();
  823         bp->b_actf = NULL;
  824 
  825         if (ctlr->start_queue.b_bcount)
  826         {
  827                 ctlr->last->b_actf = bp;
  828                 ctlr->last = bp;
  829         }
  830         else
  831         {
  832                 ctlr->start_queue.b_bcount = 1;
  833                 ctlr->start_queue.b_actf = bp;
  834                 ctlr->last = bp;
  835                 start(ctlr);
  836         }
  837         splx(s);
  838 }
  839 
  840 /* da_strategy: Send data to the D-A.  The CHAN field should be
  841  * 0: D-A port 0
  842  * 1: D-A port 1
  843  * 2: Alternate port 0 then port 1
  844  *
  845  * XXX:
  846  *
  847  * 1. There is no state for CHAN field 2:
  848  * the first sample in each buffer goes to channel 0.
  849  *
  850  * 2. No interrupt support yet.
  851  */
  852 static void
  853 da_strategy(struct buf *bp, struct ctlr *ctlr)
  854 {
  855         int len;
  856         u_char *data;
  857         int port;
  858         int i;
  859 
  860         switch(CHAN(bp->b_dev))
  861         {
  862                 case 0:
  863                         port = DAC0L(ctlr);
  864                         break;
  865 
  866                 case 1:
  867                         port = DAC1L(ctlr);
  868                         break;
  869 
  870                 case 2: /* Device 2 handles both ports interleaved. */
  871                         if (bp->b_bcount <= 2)
  872                         {
  873                                 port = DAC0L(ctlr);
  874                                 break;
  875                         }
  876 
  877                         len = bp->b_bcount / 2;
  878                         data = (u_char *)bp->b_data;
  879 
  880                         for (i = 0; i < len; i++)
  881                         {
  882                                 loutb(DAC0H(ctlr), *data++);
  883                                 loutb(DAC0L(ctlr), *data++);
  884                                 loutb(DAC1H(ctlr), *data++);
  885                                 loutb(DAC1L(ctlr), *data++);
  886                         }
  887 
  888                         bp->b_resid = bp->b_bcount & 3;
  889                         bp_done(bp, 0);
  890                         return;
  891 
  892                 default:
  893                         bp_done(bp, ENXIO);
  894                         return;
  895         }
  896 
  897         /* Port 0 or 1 falls through to here.
  898          */
  899         if (bp->b_bcount & 1)   /* Odd transfers are illegal */
  900                 bp_done(bp, EIO);
  901 
  902         len = bp->b_bcount;
  903         data = (u_char *)bp->b_data;
  904 
  905         for (i = 0; i < len; i++)
  906         {
  907                 loutb(port + 1, *data++);
  908                 loutb(port, *data++);
  909         }
  910 
  911         bp->b_resid = 0;
  912 
  913         bp_done(bp, 0);
  914 }
  915 
  916 /* Input masks for MODE 0 of the ports treating PC as a single
  917  * 8 bit port.  Set these bits to set the port to input.
  918  */
  919                             /* A     B    lowc  highc combined */
  920 static u_char set_input[] = { 0x10, 0x02, 0x01,  0x08,  0x09 };
  921 
  922 static void flush_dcr(struct ctlr *ctlr)
  923 {
  924         if (ctlr->dcr_is != ctlr->dcr_val)
  925         {
  926                 loutb(DCR(ctlr), ctlr->dcr_val);
  927                 ctlr->dcr_is = ctlr->dcr_val;
  928         }
  929 }
  930 
  931 /* do: Digital output
  932  */
  933 static void
  934 digital_out_strategy(struct buf *bp, struct ctlr *ctlr)
  935 {
  936         int len;
  937         u_char *data;
  938         int port;
  939         int i;
  940         int chan = CHAN(bp->b_dev);
  941 
  942         ctlr->dcr_val &= ~set_input[chan];      /* Digital out: Clear bit */
  943         flush_dcr(ctlr);
  944 
  945         port = PORTX(ctlr, chan);
  946 
  947         len = bp->b_bcount;
  948         data = (u_char *)bp->b_data;
  949 
  950         for (i = 0; i < len; i++)
  951         {
  952                 loutb(port, *data++);
  953         }
  954 
  955         bp->b_resid = 0;
  956 
  957         bp_done(bp, 0);
  958 }
  959 
  960 /* digital_in_strategy: Digital input
  961  */
  962 static void
  963 digital_in_strategy(struct buf *bp, struct ctlr *ctlr)
  964 {
  965         int len;
  966         u_char *data;
  967         int port;
  968         int i;
  969         int chan = CHAN(bp->b_dev);
  970 
  971         ctlr->dcr_val |= set_input[chan];       /* Digital in: Set bit */
  972         flush_dcr(ctlr);
  973         port = PORTX(ctlr, chan);
  974 
  975         len = bp->b_bcount;
  976         data = (u_char *)bp->b_data;
  977 
  978         for (i = 0; i < len; i++)
  979         {
  980                 *data++ = inb(port);
  981         }
  982 
  983         bp->b_resid = 0;
  984 
  985         bp_done(bp, 0);
  986 }
  987 
  988 
  989 static  void
  990 labpcstrategy(struct buf *bp)
  991 {
  992         struct ctlr *ctlr = labpcs[UNIT(bp->b_dev)];
  993 
  994         if (DIGITAL(bp->b_dev)) {
  995                 if (bp->b_flags & B_READ) {
  996                         ctlr->starter = null_start;
  997                         ctlr->stop = all_stop;
  998                         ctlr->intr = null_intr;
  999                         digital_in_strategy(bp, ctlr);
 1000                 }
 1001                 else
 1002                 {
 1003                         ctlr->starter = null_start;
 1004                         ctlr->stop = all_stop;
 1005                         ctlr->intr = null_intr;
 1006                         digital_out_strategy(bp, ctlr);
 1007                 }
 1008         }
 1009         else {
 1010                 if (bp->b_flags & B_READ) {
 1011 
 1012                         ctlr->starter = INTERVAL(ctlr->dev) ? ad_interval_start : ad_start;
 1013                         ctlr->stop = all_stop;
 1014                         ctlr->intr = ad_intr;
 1015                         ad_strategy(bp, ctlr);
 1016                 }
 1017                 else
 1018                 {
 1019                         ctlr->starter = null_start;
 1020                         ctlr->stop = all_stop;
 1021                         ctlr->intr = null_intr;
 1022                         da_strategy(bp, ctlr);
 1023                 }
 1024         }
 1025 }
 1026 
 1027 static  int
 1028 labpcioctl(dev_t dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
 1029 {
 1030         struct ctlr *ctlr = labpcs[UNIT(dev)];
 1031 
 1032         switch(cmd)
 1033         {
 1034                 case AD_MICRO_PERIOD_SET:
 1035                 {
 1036                         /* XXX I'm only supporting what I have to, which is
 1037                          * no slow periods.  You can't get any slower than 15 Hz
 1038                          * with the current setup.  To go slower you'll need to
 1039                          * support TCINTEN in CR3.
 1040                          */
 1041 
 1042                         long sample_us = *(long *)arg;
 1043 
 1044                         if (sample_us > 65535)
 1045                                 return EIO;
 1046 
 1047                         ctlr->sample_us = sample_us;
 1048                         return 0;
 1049                 }
 1050 
 1051                 case AD_MICRO_PERIOD_GET:
 1052                         *(long *)arg = ctlr->sample_us;
 1053                         return 0;
 1054 
 1055                 case AD_NGAINS_GET:
 1056                         *(int *)arg = 8;
 1057                         return 0;
 1058 
 1059                 case AD_NCHANS_GET:
 1060                         *(int *)arg = 8;
 1061                         return 0;
 1062 
 1063                 case AD_SUPPORTED_GAINS:
 1064                 {
 1065                         static double gains[] = {1., 1.25, 2., 5., 10., 20., 50., 100.};
 1066                         copyout(gains, *(caddr_t *)arg, sizeof(gains));
 1067 
 1068                         return 0;
 1069                 }
 1070 
 1071                 case AD_GAINS_SET:
 1072                 {
 1073                         copyin(*(caddr_t *)arg, ctlr->gains, sizeof(ctlr->gains));
 1074                         return 0;
 1075                 }
 1076 
 1077                 case AD_GAINS_GET:
 1078                 {
 1079                         copyout(ctlr->gains, *(caddr_t *)arg, sizeof(ctlr->gains));
 1080                         return 0;
 1081                 }
 1082 
 1083                 default:
 1084                         return ENOTTY;
 1085         }
 1086 }

Cache object: 453f1eac1699c687ac472c1d6e0fc901


[ 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.