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/asc.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 /* asc.c - device driver for hand scanners
    2  *
    3  * Current version supports:
    4  *
    5  *      - AmiScan (Mustek) Color and BW hand scanners (GI1904 chipset)
    6  *
    7  * Copyright (c) 1995 Gunther Schadow.  All rights reserved.
    8  * Copyright (c) 1995,1996,1997 Luigi Rizzo.  All rights reserved.
    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 Gunther Schadow
   21  *      and Luigi Rizzo.
   22  * 4. The name of the author may not be used to endorse or promote products
   23  *    derived from this software without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   28  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 /*
   37  * $FreeBSD$
   38  */
   39 
   40 #include "asc.h"
   41 #if NASC > 0
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/conf.h>
   45 #include <sys/proc.h>
   46 #include <sys/buf.h>
   47 #include <sys/malloc.h>
   48 #include <sys/kernel.h>
   49 #include <sys/poll.h>
   50 
   51 #include "opt_devfs.h"
   52 
   53 #ifdef DEVFS
   54 #include <sys/devfsext.h>
   55 #endif /*DEVFS*/
   56 #include <sys/uio.h>
   57 
   58 #include <machine/asc_ioctl.h>
   59 
   60 #include <i386/isa/isa.h>
   61 #include <i386/isa/isa_device.h>
   62 #include <i386/isa/ascreg.h>
   63 
   64 /***
   65  *** CONSTANTS & DEFINES
   66  ***
   67  ***/
   68 
   69 #define PROBE_FAIL    0
   70 #define PROBE_SUCCESS IO_ASCSIZE
   71 #define ATTACH_FAIL   0
   72 #define ATTACH_SUCCESS 1
   73 #define SUCCESS       0
   74 #define FAIL         -1
   75 #define INVALID       FAIL
   76 
   77 #define DMA1_READY  0x08
   78 #define ASCDEBUG
   79 #ifdef ASCDEBUG
   80 #       define lprintf if(scu->flags & FLAG_DEBUG) printf
   81 #else
   82 #       define lprintf (void)
   83 #endif
   84 
   85 #define TIMEOUT (hz*15)  /* timeout while reading a buffer - default value */
   86 #define ASCPRI  PRIBIO   /* priority while reading a buffer */
   87 
   88 /***
   89  *** LAYOUT OF THE MINOR NUMBER
   90  ***/
   91 
   92 #define UNIT_MASK 0xc0    /* unit asc0 .. asc3 */
   93 #define UNIT(x)   (x >> 6)
   94 #define DBUG_MASK 0x20
   95 #define FRMT_MASK 0x18    /* output format */
   96 #define FRMT_RAW  0x00    /* output bits as read from scanner */
   97 #define FRMT_GRAY 0x1     /* output gray mode for color scanner */
   98 #define FRMT_PBM  0x08    /* output pbm format */
   99 #define FRMT_PGM  0x18
  100 
  101 /***
  102  *** THE GEMOMETRY TABLE
  103  ***/
  104 
  105 #define GREY_LINE 826 /* 825, or 826 , or 550 ??? */
  106 static const struct asc_geom {
  107   int dpi;     /* dots per inch */
  108   int dpl;     /* dots per line */
  109   int bpl;     /* bytes per line */
  110   int g_res;   /* get resolution value (ASC_STAT) */
  111 } geomtab[] = {
  112   { 800, 3312, 414, ASC_RES_800},
  113   { 700, 2896, 362, ASC_RES_700},
  114   { 600, 2480, 310, ASC_RES_600},
  115   { 500, 1656, 258, ASC_RES_500},
  116   { 400, 1656, 207, ASC_RES_400},
  117   { 300, 1240, 155, ASC_RES_300},
  118   { 200, 832, 104, ASC_RES_200},
  119   { 100, 416, 52, ASC_RES_100},
  120   { 200, 3*GREY_LINE, 3*GREY_LINE, 0 /* returned by color scanner */},
  121   { 200, GREY_LINE, GREY_LINE, 0 /* color scanner, grey mode */},
  122   { INVALID, 416, 52, INVALID } /* terminator */
  123 };
  124 
  125 /***
  126  *** THE TABLE OF UNITS
  127  ***/
  128 
  129 struct _sbuf {
  130   size_t  size;
  131   size_t  rptr;
  132   size_t  wptr; /* only changed in ascintr */
  133   size_t  count;
  134   char   *base;
  135 };
  136 
  137 struct asc_unit {
  138   long thedev;  /* XXX */
  139   int base;             /* base address */
  140   int dma_num;          /* dma number */
  141   char    dma_byte;       /* mask of byte for setting DMA value */
  142   char    int_byte;       /* mask of byte for setting int value */
  143   char    cfg_byte;       /* mirror of byte written to config reg (ASC_CFG). */
  144   char    cmd_byte;       /* mirror of byte written to cmd port (ASC_CMD)*/
  145   char   portf_byte;
  146   int flags;
  147 #define ATTACHED        0x01
  148 #define OPEN            0x02
  149 #define READING         0x04
  150 #define DMA_ACTIVE      0x08
  151 #define SLEEPING        0x10
  152 #define SEL_COLL        0x20
  153 #define PBM_MODE        0x40
  154 #define FLAG_DEBUG      0x80
  155   int     geometry;       /* resolution as geomtab index */
  156   int     linesize;       /* length of one scan line (from geom.table) */
  157   int     blen;           /* length of buffer in lines */
  158   int     btime;          /* timeout of buffer in seconds/hz */
  159   struct  _sbuf sbuf;
  160   long    icnt;         /* interrupt count XXX for debugging */
  161   struct selinfo selp;
  162   int     height;         /* height, for pnm modes */
  163   size_t  bcount;         /* bytes to read, for pnm modes */
  164 #ifdef DEVFS
  165   void *devfs_asc;        /* storage for devfs tokens (handles) */
  166   void *devfs_ascp;
  167   void *devfs_ascd;
  168   void *devfs_ascpd;
  169 #endif
  170 };
  171 
  172 static struct asc_unit unittab[NASC];                                 
  173 
  174 /*** I could not find a reasonable buffer size limit other than by
  175  *** experiments. MAXPHYS is obviously too much, while DEV_BSIZE and
  176  *** PAGE_SIZE are really too small. There must be something wrong
  177  *** with isa_dmastart/isa_dmarangecheck HELP!!!
  178  ***
  179  *** Note, must be DEFAULT_BLEN * samples_per_line <= MAX_BUFSIZE
  180  ***/
  181 #define MAX_BUFSIZE 0xb000 /* XXX was 0x3000 */
  182 #define DEFAULT_BLEN 16
  183 
  184 /***
  185  *** THE PER-DRIVER RECORD FOR ISA.C
  186  ***/
  187 static int ascprobe (struct isa_device *isdp);
  188 static int ascattach(struct isa_device *isdp);
  189 struct isa_driver ascdriver = { ascprobe, ascattach, "asc" };
  190 
  191 static ointhand2_t      ascintr;
  192 
  193 static d_open_t         ascopen;
  194 static d_close_t        ascclose;
  195 static d_read_t         ascread;
  196 static d_ioctl_t        ascioctl;
  197 static d_poll_t         ascpoll;
  198 
  199 #define CDEV_MAJOR 71
  200 
  201 static struct cdevsw asc_cdevsw = 
  202         { ascopen,      ascclose,       ascread,        nowrite,        /*71*/
  203           ascioctl,     nostop,         nullreset,      nodevtotty, /* asc */   
  204           ascpoll,      nommap,         NULL,   "asc",  NULL,   -1 };
  205 
  206 #define STATIC static
  207 
  208 /***
  209  *** LOCALLY USED SUBROUTINES
  210  ***
  211  ***/
  212 
  213 /***
  214  *** get_resolution
  215  ***    read resolution from the scanner
  216  ***/
  217 static void
  218 get_resolution(struct asc_unit *scu)
  219 {
  220     int res, i, delay;
  221 
  222     res=0;
  223     scu->cmd_byte = ASC_STANDBY;
  224     outb(ASC_CMD, scu->cmd_byte);
  225     tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascres", hz/10);
  226     for(delay= 100; (res=inb(ASC_STAT)) & ASC_RDY_FLAG; delay--)
  227     {
  228         i = tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascres0", 1);
  229         if ( ( i == 0 ) || ( i == EWOULDBLOCK ) )
  230             i = SUCCESS;
  231         else
  232             break;
  233     }
  234     if (delay==0) {
  235         lprintf("asc.get_resolution: timeout completing command\n");
  236         return /*  -1 */;
  237     }
  238     /* ... actual read resolution... */
  239     res &= ASC_RES_MASK;
  240     for (i=0; geomtab[i].dpi != INVALID; i++) {
  241         if (geomtab[i].g_res == res) break;
  242     }
  243     if (geomtab[i].dpi==INVALID) {
  244         scu->geometry= i; /* INVALID; */
  245         lprintf("asc.get_resolution: wrong resolution\n");
  246     } else {
  247         lprintf("asc.get_resolution: %d dpi\n",geomtab[i].dpi);
  248         scu->geometry = i;
  249     }
  250     scu->portf_byte=0; /* default */
  251     if (geomtab[scu->geometry].g_res==0 && !(scu->thedev&FRMT_GRAY)) {
  252         /* color scanner seems to require this */
  253         scu->portf_byte=2;
  254         /* scu->geometry++; */
  255     }
  256     scu->linesize = geomtab[scu->geometry].bpl;
  257     scu->height = geomtab[scu->geometry].dpl; /* default... */
  258 }
  259 
  260 /***
  261  *** buffer_allocate
  262  ***    allocate/reallocate a buffer
  263  ***    Now just checks that the preallocated buffer is large enough.
  264  ***/
  265 
  266 static int
  267 buffer_allocate(struct asc_unit *scu)
  268 {
  269   size_t size, size1;
  270 
  271   size = scu->blen * scu->linesize;
  272 
  273   lprintf("asc.buffer_allocate: need 0x%x bytes\n", size);
  274 
  275   if ( size > MAX_BUFSIZE ) {
  276       size1=size;
  277       size= ( (MAX_BUFSIZE+scu->linesize-1) / scu->linesize)*scu->linesize;
  278       lprintf("asc.buffer_allocate: 0x%x bytes are too much, try 0x%x\n",
  279           size1, size);
  280       return ENOMEM;
  281   }
  282 
  283   scu->sbuf.size = size;
  284   scu->sbuf.rptr  = 0;
  285   scu->sbuf.wptr  = 0;
  286   scu->sbuf.count  = 0; /* available data for reading */
  287 
  288   lprintf("asc.buffer_allocate: ok\n");
  289 
  290   return SUCCESS;
  291 }
  292 
  293 /*** dma_restart
  294  ***    invoked locally to start dma. Must run in a critical section
  295  ***/
  296 static void
  297 dma_restart(struct asc_unit *scu)
  298 {
  299     unsigned char al=scu->cmd_byte;
  300 
  301     if (geomtab[scu->geometry].g_res==0) {/* color */
  302         isa_dmastart(B_READ, scu->sbuf.base+scu->sbuf.wptr,
  303             scu->linesize + 90 /* XXX */ , scu->dma_num);
  304         /*
  305          * looks like we have to set and then clear this
  306          * bit to enable the scanner to send interrupts
  307          */
  308         outb( ASC_CMD, al |= 4 ); /* seems to disable interrupts */
  309 #if 0
  310         outb( ASC_CMD, al |= 8 ); /* ??? seems useless */
  311 #endif
  312         outb( ASC_CMD, al &= 0xfb );
  313         scu->cmd_byte = al;
  314     } else {                                    /* normal */
  315     isa_dmastart(B_READ, scu->sbuf.base+scu->sbuf.wptr,
  316         scu->linesize, scu->dma_num);
  317     /*** this is done in sub_20, after dmastart ? ***/  
  318 #if 0
  319     outb( ASC_CMD, al |= 4 );
  320     outb( ASC_CMD, al |= 8 ); /* ??? seems useless */
  321     outb( ASC_CMD, al &= 0xfb );
  322     scu->cmd_byte = al;
  323 #else
  324     outb( ASC_CMD, ASC_OPERATE); 
  325 #endif
  326     }
  327     scu->flags |= DMA_ACTIVE;
  328 }
  329 
  330 /***
  331  *** the main functions
  332  ***/
  333 
  334 /*** asc_reset
  335  ***    resets the scanner and the config bytes...
  336  ***/
  337 static void
  338 asc_reset(struct asc_unit *scu)
  339 {
  340   scu->cfg_byte = 0 ; /* clear... */
  341   scu->cmd_byte = 0 ; /* clear... */
  342 
  343   outb(ASC_CFG,scu->cfg_byte);  /* for safety, do this here */
  344   outb(ASC_CMD,scu->cmd_byte);  /* probably not needed */
  345   tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascres", hz/10); /* sleep .1 sec */
  346 
  347   scu->blen = DEFAULT_BLEN;
  348   scu->btime = TIMEOUT;
  349   scu->height = 0 ; /* don't know better... */
  350 }
  351 /**************************************************************************
  352  ***
  353  *** ascprobe
  354  ***    read status port and check for proper configuration:
  355  ***    - if address group matches (status byte has reasonable value)
  356  ***      cannot check interrupt/dma, only clear the config byte.
  357  ***/
  358 static int
  359 ascprobe (struct isa_device *isdp)
  360 {
  361   int unit = isdp->id_unit;
  362   struct asc_unit *scu = unittab + unit;
  363   int stb;
  364 
  365   scu->base = isdp->id_iobase; /*** needed by the following macros ***/
  366   scu->flags = FLAG_DEBUG;
  367 
  368   if ( isdp->id_iobase < 0 ) {
  369       lprintf("asc%d.probe: no iobase given\n", unit);
  370       return PROBE_FAIL;
  371   }
  372 
  373   if ((stb=inb(ASC_PROBE)) != ASC_PROBE_VALUE) {
  374       lprintf("asc%d.probe: failed, got 0x%02x instead of 0x%02x\n",
  375           unit, stb, ASC_PROBE_VALUE);
  376       return PROBE_FAIL;
  377   }
  378 
  379 /*
  380  * NOTE NOTE NOTE
  381  * the new AmiScan Color board uses int 10,11,12 instead of 3,5,10
  382  * respectively. This means that the driver must act accordingly.
  383  * Unfortunately there is no easy way of telling which board one has,
  384  * other than trying to get an interrupt and noticing that it is
  385  * missing. use "option ASC_NEW_BOARD" if you have a new board.
  386  *
  387  */
  388 
  389 #if ASC_NEW_BOARD
  390 #define ASC_IRQ_A       10
  391 #define ASC_IRQ_B       11
  392 #define ASC_IRQ_C       12
  393 #else
  394 #define ASC_IRQ_A       3
  395 #define ASC_IRQ_B       5
  396 #define ASC_IRQ_C       10
  397 #endif
  398 
  399   switch(ffs(isdp->id_irq) - 1) {
  400     case ASC_IRQ_A :
  401       scu->int_byte = ASC_CNF_IRQ3;
  402       break;
  403     case ASC_IRQ_B :
  404       scu->int_byte = ASC_CNF_IRQ5;
  405       break;
  406     case ASC_IRQ_C :
  407       scu->int_byte = ASC_CNF_IRQ10;
  408       break;
  409 #if 0
  410     case -1:
  411       scu->int_byte = 0;
  412       lprintf("asc%d.probe: warning - going interruptless\n", unit);
  413       break;
  414 #endif
  415     default:
  416       lprintf("asc%d.probe: unsupported INT %d (only 3, 5, 10)\n",
  417                 unit, ffs(isdp->id_irq) - 1 );
  418       return PROBE_FAIL;
  419   }
  420   scu->dma_num = isdp->id_drq;
  421   switch(scu->dma_num) {
  422     case 1:
  423       scu->dma_byte = ASC_CNF_DMA1;
  424       break;
  425     case 3:
  426       scu->dma_byte = ASC_CNF_DMA3;
  427       break;
  428     default:
  429       lprintf("asc%d.probe: unsupported DMA %d (only 1 or 3)\n", 
  430                 unit, scu->dma_num);
  431       return PROBE_FAIL;
  432   }
  433   asc_reset(scu);
  434 /*  lprintf("asc%d.probe: ok\n", unit); */
  435 
  436   scu->flags &= ~FLAG_DEBUG;
  437   scu->icnt = 0;
  438   return PROBE_SUCCESS;
  439 }
  440 
  441 /**************************************************************************
  442  ***
  443  *** ascattach
  444  ***    finish initialization of unit structure, get geometry value (?)
  445  ***/
  446 
  447 static int
  448 ascattach(struct isa_device *isdp)
  449 {
  450   int unit = isdp->id_unit;
  451   struct asc_unit *scu = unittab + unit;
  452 
  453   isdp->id_ointr = ascintr;
  454   scu->flags |= FLAG_DEBUG;
  455   printf("asc%d: [GI1904/Trust Ami-Scan Grey/Color]\n", unit);
  456 
  457   /*
  458    * Initialize buffer structure.
  459    * XXX this must be done early to give a good chance of getting a
  460    * contiguous buffer.  This wastes memory.
  461    */
  462   scu->sbuf.base = contigmalloc((unsigned long)MAX_BUFSIZE, M_DEVBUF, M_NOWAIT,
  463                                 0ul, 0xfffffful, 1ul, 0x10000ul);
  464   if ( scu->sbuf.base == NULL )
  465     {
  466       lprintf("asc%d.attach: buffer allocation failed\n", unit);
  467       return ATTACH_FAIL;       /* XXX attach must not fail */
  468     }
  469   scu->sbuf.size = INVALID;
  470   scu->sbuf.rptr  = INVALID;
  471 
  472   scu->flags |= ATTACHED;
  473 /*  lprintf("asc%d.attach: ok\n", unit); */
  474   scu->flags &= ~FLAG_DEBUG;
  475 
  476     scu->selp.si_flags=0;
  477     scu->selp.si_pid=(pid_t)0;
  478 #ifdef DEVFS
  479 #define ASC_UID 0
  480 #define ASC_GID 13
  481     scu->devfs_asc = 
  482                 devfs_add_devswf(&asc_cdevsw, unit<<6, DV_CHR, ASC_UID,
  483                                  ASC_GID, 0666, "asc%d", unit);
  484     scu->devfs_ascp = 
  485                 devfs_add_devswf(&asc_cdevsw, ((unit<<6) + FRMT_PBM), DV_CHR, 
  486                                  ASC_UID,  ASC_GID, 0666, "asc%dp", unit);
  487     scu->devfs_ascd = 
  488                 devfs_add_devswf(&asc_cdevsw, ((unit<<6) + DBUG_MASK), DV_CHR, 
  489                                  ASC_UID,  ASC_GID, 0666, "asc%dd", unit);
  490     scu->devfs_ascpd = 
  491                 devfs_add_devswf(&asc_cdevsw, ((unit<<6) + DBUG_MASK+FRMT_PBM),
  492                                  DV_CHR, ASC_UID, ASC_GID, 0666, "asc%dpd", 
  493                                  unit);
  494 #endif /*DEVFS*/
  495   return ATTACH_SUCCESS;
  496 }
  497 
  498 /**************************************************************************
  499  ***
  500  *** ascintr
  501  ***    the interrupt routine, at the end of DMA...
  502  ***/
  503 static void
  504 ascintr(int unit)
  505 {
  506     struct asc_unit *scu = unittab + unit;
  507     int chan_bit = 0x01 << scu->dma_num;
  508 
  509     scu->icnt++;
  510     /* ignore stray interrupts... */
  511     if ( scu->flags & (OPEN |READING) != (OPEN | READING) ) {
  512         /* must be after closing... */
  513         scu->flags &= ~(OPEN | READING | DMA_ACTIVE | SLEEPING | SEL_COLL);
  514         return;
  515     }
  516     if ( (scu->flags & DMA_ACTIVE) && (inb(DMA1_READY) & chan_bit) != 0) {
  517         outb( ASC_CMD, ASC_STANDBY);
  518         scu->flags &= ~DMA_ACTIVE;
  519                 /* bounce buffers... */
  520         isa_dmadone(B_READ, scu->sbuf.base+scu->sbuf.wptr,
  521             scu->linesize, scu->dma_num);
  522         scu->sbuf.wptr += scu->linesize;
  523         if (scu->sbuf.wptr >= scu->sbuf.size) scu->sbuf.wptr=0;
  524         scu->sbuf.count += scu->linesize;
  525         if (scu->flags & SLEEPING) {
  526             scu->flags &= ~SLEEPING;
  527             wakeup((caddr_t)scu);
  528         }
  529         if (scu->sbuf.size - scu->sbuf.count >= scu->linesize) {
  530             dma_restart(scu);
  531         }
  532         if (scu->selp.si_pid) {
  533             selwakeup(&scu->selp);
  534             scu->selp.si_pid=(pid_t)0;
  535             scu->selp.si_flags = 0;
  536         }
  537     }
  538 }
  539 
  540 /**************************************************************************
  541  ***
  542  *** ascopen
  543  ***    set open flag, set modes according to minor number
  544  ***    FOR RELEASE:
  545  ***    don't switch scanner on, wait until first read or ioctls go before
  546  ***/
  547 
  548 STATIC int
  549 ascopen(dev_t dev, int flags, int fmt, struct proc *p)
  550 {
  551   struct asc_unit *scu;
  552   int unit;
  553 
  554   unit = UNIT(minor(dev)) & UNIT_MASK;
  555   if ( unit >= NASC )
  556     {
  557 #ifdef ASCDEBUG
  558       /* XXX lprintf isn't valid here since there is no scu. */
  559       printf("asc%d.open: unconfigured unit number (max %d)\n", unit, NASC);
  560 #endif
  561       return ENXIO;
  562     }
  563   scu = unittab + unit;
  564   if ( !( scu->flags & ATTACHED ) )
  565     {
  566       lprintf("asc%d.open: unit was not attached successfully 0x%04x\n",
  567              unit, scu->flags);
  568       return ENXIO;
  569     }
  570 
  571   if ( minor(dev) & DBUG_MASK )
  572     scu->flags |= FLAG_DEBUG;
  573   else
  574     scu->flags &= ~FLAG_DEBUG;
  575 
  576   switch(minor(dev) & FRMT_MASK) {
  577   case FRMT_PBM:
  578     scu->flags |= PBM_MODE;
  579     lprintf("asc%d.open: pbm mode\n", unit);
  580     break;
  581   case FRMT_RAW:
  582     lprintf("asc%d.open: raw mode\n", unit);
  583     scu->flags &= ~PBM_MODE;
  584     break;
  585   default:
  586     lprintf("asc%d.open: gray maps are not yet supported", unit);
  587     return ENXIO;
  588   }
  589   
  590   lprintf("asc%d.open: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
  591 
  592   if ( scu->flags & OPEN ) {
  593       lprintf("asc%d.open: already open", unit);
  594       return EBUSY;
  595   }
  596   if (isa_dma_acquire(scu->dma_num))
  597       return(EBUSY);
  598 
  599   scu->flags = ATTACHED | OPEN;      
  600 
  601   asc_reset(scu);
  602   get_resolution(scu);
  603   return SUCCESS;
  604 }
  605 
  606 static int
  607 asc_startread(struct asc_unit *scu)
  608 {
  609     /*** from here on, things can be delayed to the first read/ioctl ***/
  610     /*** this was done in sub_12... ***/
  611   scu->cfg_byte= scu->cmd_byte=0;       /* init scanner */
  612   outb(ASC_CMD, scu->cmd_byte);
  613     /*** this was done in sub_16, set scan len... ***/
  614   outb(ASC_BOH, scu->portf_byte );
  615   if (geomtab[scu->geometry].g_res==0) {                /* color */
  616         scu->cmd_byte = 0x00 ;
  617   } else {
  618   scu->cmd_byte = 0x90 ;
  619   }
  620   outb(ASC_CMD, scu->cmd_byte);
  621   outb(ASC_LEN_L, scu->linesize & 0xff /* len_low */);
  622   outb(ASC_LEN_H, (scu->linesize >>8) & 0xff /* len_high */);
  623     /*** this was done in sub_21, config DMA ... ***/
  624   scu->cfg_byte |= scu->dma_byte;
  625   outb(ASC_CFG, scu->cfg_byte);
  626     /*** sub_22: enable int on the scanner ***/
  627   scu->cfg_byte |= scu->int_byte;
  628   outb(ASC_CFG, scu->cfg_byte);
  629     /*** sub_28: light on etc...***/
  630   scu->cmd_byte = ASC_STANDBY;
  631   outb(ASC_CMD, scu->cmd_byte);
  632   tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascstrd", hz/10); /* sleep .1 sec */
  633   return SUCCESS;
  634 }
  635 
  636 /**************************************************************************
  637  ***
  638  *** ascclose
  639  ***    turn off scanner, release the buffer
  640  ***    should probably terminate dma ops, release int and dma. lr 12mar95
  641  ***/
  642 
  643 STATIC int
  644 ascclose(dev_t dev, int flags, int fmt, struct proc *p)
  645 {
  646   int unit = UNIT(minor(dev));
  647   struct asc_unit *scu = unittab + unit;
  648 
  649   lprintf("asc%d.close: minor %d\n",
  650          unit, minor(dev));
  651 
  652   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
  653       lprintf("asc%d.close: unit was not attached successfully 0x%04x\n",
  654              unit, scu->flags);
  655       return ENXIO;
  656   }
  657     /* all this is in sub_29... */
  658   /* cli(); */
  659   outb(ASC_CFG, 0 ); /* don't save in CFG byte!!! */
  660   scu->cmd_byte &= ~ASC_LIGHT_ON;
  661   outb(ASC_CMD, scu->cmd_byte);/* light off */
  662   tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascclo", hz/2); /* sleep 1/2 sec */
  663   scu->cfg_byte &= ~ scu->dma_byte ; /* disable scanner dma */
  664   scu->cfg_byte &= ~ scu->int_byte ; /* disable scanner int */
  665   outb(ASC_CFG, scu->cfg_byte);
  666     /* --- disable dma controller ? --- */
  667   isa_dma_release(scu->dma_num);
  668     /* --- disable interrupts on the controller (sub_24) --- */
  669 
  670   scu->sbuf.size = INVALID;
  671   scu->sbuf.rptr  = INVALID;
  672 
  673   scu->flags &= ~(FLAG_DEBUG | OPEN | READING);
  674   
  675   return SUCCESS;
  676 }
  677 
  678 static void
  679 pbm_init(struct asc_unit *scu)
  680 {
  681     int width = geomtab[scu->geometry].dpl;
  682     int l= sprintf(scu->sbuf.base,"P4 %d %d\n", width, scu->height);
  683     char *p;
  684 
  685     scu->bcount = scu->height * width / 8 + l;
  686 
  687       /* move header to end of sbuf */
  688     scu->sbuf.rptr=scu->sbuf.size-l;
  689     bcopy(scu->sbuf.base, scu->sbuf.base+scu->sbuf.rptr,l);
  690     scu->sbuf.count = l;
  691     if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
  692     for(p = scu->sbuf.base + scu->sbuf.rptr; l; p++, l--)
  693         *p = ~*p;
  694 }
  695 }
  696 /**************************************************************************
  697  ***
  698  *** ascread
  699  ***/
  700 
  701 STATIC int
  702 ascread(dev_t dev, struct uio *uio, int ioflag)
  703 {
  704   int unit = UNIT(minor(dev));
  705   struct asc_unit *scu = unittab + unit;
  706   size_t nbytes;
  707   int sps, res;
  708   unsigned char *p;
  709   
  710   lprintf("asc%d.read: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
  711 
  712   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
  713       lprintf("asc%d.read: unit was not attached successfully 0x%04x\n",
  714              unit, scu->flags);
  715       return ENXIO;
  716   }
  717 
  718   if ( !(scu->flags & READING) ) { /*** first read... ***/
  719         /* allocate a buffer for reading data and init things */
  720       if ( (res = buffer_allocate(scu)) == SUCCESS ) scu->flags |= READING;
  721       else return res;
  722       asc_startread(scu);
  723       if ( scu->flags & PBM_MODE ) { /* initialize for pbm mode */
  724           pbm_init(scu);
  725       }
  726   }
  727   
  728   lprintf("asc%d.read(before): "
  729       "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
  730           unit, scu->sbuf.size, scu->sbuf.rptr,
  731           scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,
  732           scu->icnt);
  733 
  734   sps=spltty();
  735   if ( scu->sbuf.count == 0 ) { /* no data avail., must wait */
  736       if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
  737       scu->flags |= SLEEPING;
  738       res = tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascread", 0);
  739       scu->flags &= ~SLEEPING;
  740       if ( res == 0 ) res = SUCCESS;
  741   }
  742   splx(sps); /* lower priority... */
  743   if (scu->flags & FLAG_DEBUG)
  744       tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascdly",hz);
  745   lprintf("asc%d.read(after): "
  746       "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
  747           unit, scu->sbuf.size, scu->sbuf.rptr,
  748           scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,scu->icnt);
  749 
  750         /* first, not more than available... */
  751   nbytes = min( uio->uio_resid, scu->sbuf.count );
  752         /* second, contiguous data... */
  753   nbytes = min( nbytes, (scu->sbuf.size - scu->sbuf.rptr) );
  754         /* third, one line (will remove this later, XXX) */
  755   nbytes = min( nbytes, scu->linesize );
  756   if ( (scu->flags & PBM_MODE) )
  757       nbytes = min( nbytes, scu->bcount );
  758   lprintf("asc%d.read: transferring 0x%x bytes\n", unit, nbytes);
  759   if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
  760   lprintf("asc%d.read: invert buffer\n",unit);
  761   for(p = scu->sbuf.base + scu->sbuf.rptr, res=nbytes; res; p++, res--)
  762         *p = ~*p;
  763   }
  764   res = uiomove(scu->sbuf.base + scu->sbuf.rptr, nbytes, uio);
  765   if ( res != SUCCESS ) {
  766       lprintf("asc%d.read: uiomove failed %d", unit, res);
  767       return res;
  768   }
  769   
  770   sps=spltty();
  771   scu->sbuf.rptr += nbytes;
  772   if (scu->sbuf.rptr >= scu->sbuf.size) scu->sbuf.rptr=0;
  773   scu->sbuf.count -= nbytes;
  774         /* having moved some data, can read mode */
  775   if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
  776   splx(sps); /* lower priority... */
  777   if ( scu->flags & PBM_MODE ) scu->bcount -= nbytes;
  778   
  779   lprintf("asc%d.read: size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
  780           unit, scu->sbuf.size, scu->sbuf.rptr, scu->bcount);
  781   
  782   return SUCCESS;
  783 }
  784 
  785 /**************************************************************************
  786  ***
  787  *** ascioctl
  788  ***/
  789 
  790 STATIC int
  791 ascioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  792 {
  793   int unit = UNIT(minor(dev));
  794   struct asc_unit *scu = unittab + unit;
  795 
  796   lprintf("asc%d.ioctl: minor %d\n",
  797          unit, minor(dev));
  798 
  799   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
  800       lprintf("asc%d.ioctl: unit was not attached successfully 0x%04x\n",
  801              unit, scu->flags);
  802       return ENXIO;
  803   }
  804   switch(cmd) {
  805   case ASC_GRES:
  806     asc_reset(scu);
  807     get_resolution(scu);
  808     *(int *)data=geomtab[scu->geometry].dpi;
  809     lprintf("asc%d.ioctl:ASC_GRES %ddpi\n", unit, *(int *)data);
  810     return SUCCESS;    
  811   case ASC_GWIDTH:
  812     *(int *)data=geomtab[scu->geometry].dpl;
  813     lprintf("asc%d.ioctl:ASC_GWIDTH %d\n", unit, *(int *)data);
  814     return SUCCESS;    
  815   case ASC_GHEIGHT:
  816     *(int *)data=scu->height;
  817     lprintf("asc%d.ioctl:ASC_GHEIGHT %d\n", unit, *(int *)data);
  818     return SUCCESS;
  819   case ASC_SHEIGHT:
  820     lprintf("asc%d.ioctl:ASC_SHEIGHT %d\n", unit, *(int *)data);
  821     if ( scu->flags & READING ) { 
  822         lprintf("asc%d:ioctl on already reading unit\n", unit);
  823         return EBUSY;
  824     }
  825     scu->height=*(int *)data;
  826     return SUCCESS;
  827 #if 0  
  828   case ASC_GBLEN:
  829     *(int *)data=scu->blen;
  830     lprintf("asc%d.ioctl:ASC_GBLEN %d\n", unit, *(int *)data);
  831     return SUCCESS;
  832   case ASC_SBLEN:
  833     lprintf("asc%d.ioctl:ASC_SBLEN %d\n", unit, *(int *)data);
  834     if (*(int *)data * geomtab[scu->geometry].dpl / 8 > MAX_BUFSIZE)
  835       {
  836         lprintf("asc%d:ioctl buffer size too high\n", unit);
  837         return ENOMEM;
  838       }
  839     scu->blen=*(int *)data;
  840     return SUCCESS;
  841   case ASC_GBTIME:
  842     *(int *)data = scu->btime / hz;
  843     lprintf("asc%d.ioctl:ASC_GBTIME %d\n", unit, *(int *)data);
  844     return SUCCESS;
  845   case ASC_SBTIME:
  846     scu->btime = *(int *)data * hz;
  847     lprintf("asc%d.ioctl:ASC_SBTIME %d\n", unit, *(int *)data);
  848     return SUCCESS;
  849 #endif
  850   default: return ENOTTY;
  851   }
  852   return SUCCESS;
  853 }
  854 
  855 STATIC int
  856 ascpoll(dev_t dev, int events, struct proc *p)
  857 {
  858     int unit = UNIT(minor(dev));
  859     struct asc_unit *scu = unittab + unit;
  860     int sps;
  861     struct proc *p1;
  862     int revents = 0;
  863 
  864     sps=spltty();
  865 
  866     if (events & (POLLIN | POLLRDNORM))
  867         if (scu->sbuf.count >0)
  868             revents |= events & (POLLIN | POLLRDNORM);
  869         else {
  870             if (!(scu->flags & DMA_ACTIVE))
  871                 dma_restart(scu);
  872             
  873             if (scu->selp.si_pid && (p1=pfind(scu->selp.si_pid))
  874                     && p1->p_wchan == (caddr_t)&selwait)
  875                 scu->selp.si_flags = SI_COLL;
  876             else
  877                 scu->selp.si_pid = p->p_pid;
  878         }
  879 
  880     splx(sps);
  881     return 0;
  882 }
  883 
  884 
  885 static asc_devsw_installed = 0;
  886 
  887 static void 
  888 asc_drvinit(void *unused)
  889 {
  890         dev_t dev;
  891 
  892         if( ! asc_devsw_installed ) {
  893                 dev = makedev(CDEV_MAJOR,0);
  894                 cdevsw_add(&dev,&asc_cdevsw,NULL);
  895                 asc_devsw_installed = 1;
  896         }
  897 }
  898 
  899 SYSINIT(ascdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,asc_drvinit,NULL)
  900 
  901 
  902 #endif /* NASC > 0 */

Cache object: 201c10bca2a6ef66e55c9dcfb33c12fd


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