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 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/conf.h>
   44 #include <sys/proc.h>
   45 #include <sys/buf.h>
   46 #include <sys/malloc.h>
   47 #include <sys/kernel.h>
   48 #include <sys/poll.h>
   49 #include <sys/select.h>
   50 #include <sys/uio.h>
   51 
   52 #include <machine/asc_ioctl.h>
   53 
   54 #include <i386/isa/isa.h>
   55 #include <i386/isa/isa_device.h>
   56 #include <i386/isa/ascreg.h>
   57 
   58 /***
   59  *** CONSTANTS & DEFINES
   60  ***
   61  ***/
   62 
   63 #define PROBE_FAIL    0
   64 #define PROBE_SUCCESS IO_ASCSIZE
   65 #define ATTACH_FAIL   0
   66 #define ATTACH_SUCCESS 1
   67 #define SUCCESS       0
   68 #define FAIL         -1
   69 #define INVALID       FAIL
   70 
   71 #define DMA1_READY  0x08
   72 #define ASCDEBUG
   73 #ifdef ASCDEBUG
   74 #       define lprintf if(scu->flags & FLAG_DEBUG) printf
   75 #else
   76 #       define lprintf (void)
   77 #endif
   78 
   79 #define TIMEOUT (hz*15)  /* timeout while reading a buffer - default value */
   80 #define ASCPRI  PRIBIO   /* priority while reading a buffer */
   81 
   82 /***
   83  *** LAYOUT OF THE MINOR NUMBER
   84  ***/
   85 
   86 #define UNIT_MASK 0xc0    /* unit asc0 .. asc3 */
   87 #define UNIT(x)   (x >> 6)
   88 #define DBUG_MASK 0x20
   89 #define FRMT_MASK 0x18    /* output format */
   90 #define FRMT_RAW  0x00    /* output bits as read from scanner */
   91 #define FRMT_GRAY 0x1     /* output gray mode for color scanner */
   92 #define FRMT_PBM  0x08    /* output pbm format */
   93 #define FRMT_PGM  0x18
   94 
   95 /***
   96  *** THE GEMOMETRY TABLE
   97  ***/
   98 
   99 #define GREY_LINE 826 /* 825, or 826 , or 550 ??? */
  100 static const struct asc_geom {
  101   int dpi;     /* dots per inch */
  102   int dpl;     /* dots per line */
  103   int bpl;     /* bytes per line */
  104   int g_res;   /* get resolution value (ASC_STAT) */
  105 } geomtab[] = {
  106   { 800, 3312, 414, ASC_RES_800},
  107   { 700, 2896, 362, ASC_RES_700},
  108   { 600, 2480, 310, ASC_RES_600},
  109   { 500, 1656, 258, ASC_RES_500},
  110   { 400, 1656, 207, ASC_RES_400},
  111   { 300, 1240, 155, ASC_RES_300},
  112   { 200, 832, 104, ASC_RES_200},
  113   { 100, 416, 52, ASC_RES_100},
  114   { 200, 3*GREY_LINE, 3*GREY_LINE, 0 /* returned by color scanner */},
  115   { 200, GREY_LINE, GREY_LINE, 0 /* color scanner, grey mode */},
  116   { INVALID, 416, 52, INVALID } /* terminator */
  117 };
  118 
  119 /***
  120  *** THE TABLE OF UNITS
  121  ***/
  122 
  123 struct _sbuf {
  124   size_t  size;
  125   size_t  rptr;
  126   size_t  wptr; /* only changed in ascintr */
  127   size_t  count;
  128   char   *base;
  129 };
  130 
  131 struct asc_unit {
  132   long thedev;  /* XXX */
  133   int base;             /* base address */
  134   int dma_num;          /* dma number */
  135   char    dma_byte;       /* mask of byte for setting DMA value */
  136   char    int_byte;       /* mask of byte for setting int value */
  137   char    cfg_byte;       /* mirror of byte written to config reg (ASC_CFG). */
  138   char    cmd_byte;       /* mirror of byte written to cmd port (ASC_CMD)*/
  139   char   portf_byte;
  140   int flags;
  141 #define ATTACHED        0x01
  142 #define OPEN            0x02
  143 #define READING         0x04
  144 #define DMA_ACTIVE      0x08
  145 #define SLEEPING        0x10
  146 #define SEL_COLL        0x20
  147 #define PBM_MODE        0x40
  148 #define FLAG_DEBUG      0x80
  149   int     geometry;       /* resolution as geomtab index */
  150   int     linesize;       /* length of one scan line (from geom.table) */
  151   int     blen;           /* length of buffer in lines */
  152   int     btime;          /* timeout of buffer in seconds/hz */
  153   struct  _sbuf sbuf;
  154   long    icnt;         /* interrupt count XXX for debugging */
  155   struct selinfo selp;
  156   int     height;         /* height, for pnm modes */
  157   size_t  bcount;         /* bytes to read, for pnm modes */
  158 };
  159 
  160 static struct asc_unit unittab[NASC];                                 
  161 
  162 /*** I could not find a reasonable buffer size limit other than by
  163  *** experiments. MAXPHYS is obviously too much, while DEV_BSIZE and
  164  *** PAGE_SIZE are really too small. There must be something wrong
  165  *** with isa_dmastart/isa_dmarangecheck HELP!!!
  166  ***
  167  *** Note, must be DEFAULT_BLEN * samples_per_line <= MAX_BUFSIZE
  168  ***/
  169 #define MAX_BUFSIZE 0xb000 /* XXX was 0x3000 */
  170 #define DEFAULT_BLEN 16
  171 
  172 /***
  173  *** THE PER-DRIVER RECORD FOR ISA.C
  174  ***/
  175 static int ascprobe (struct isa_device *isdp);
  176 static int ascattach(struct isa_device *isdp);
  177 struct isa_driver ascdriver = { ascprobe, ascattach, "asc" };
  178 
  179 static ointhand2_t      ascintr;
  180 
  181 static d_open_t         ascopen;
  182 static d_close_t        ascclose;
  183 static d_read_t         ascread;
  184 static d_ioctl_t        ascioctl;
  185 static d_poll_t         ascpoll;
  186 
  187 #define CDEV_MAJOR 71
  188 
  189 static struct cdevsw asc_cdevsw = {
  190         /* open */      ascopen,
  191         /* close */     ascclose,
  192         /* read */      ascread,
  193         /* write */     nowrite,
  194         /* ioctl */     ascioctl,
  195         /* poll */      ascpoll,
  196         /* mmap */      nommap,
  197         /* strategy */  nostrategy,
  198         /* name */      "asc",
  199         /* maj */       CDEV_MAJOR,
  200         /* dump */      nodump,
  201         /* psize */     nopsize,
  202         /* flags */     0,
  203         /* bmaj */      -1
  204 };
  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(ISADMA_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(ISADMA_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   static int once;
  365 
  366   if (!once++)
  367       cdevsw_add(&asc_cdevsw);
  368 
  369   scu->base = isdp->id_iobase; /*** needed by the following macros ***/
  370   scu->flags = FLAG_DEBUG;
  371 
  372   if ( isdp->id_iobase < 0 ) {
  373       lprintf("asc%d.probe: no iobase given\n", unit);
  374       return PROBE_FAIL;
  375   }
  376 
  377   if ((stb=inb(ASC_PROBE)) != ASC_PROBE_VALUE) {
  378       lprintf("asc%d.probe: failed, got 0x%02x instead of 0x%02x\n",
  379           unit, stb, ASC_PROBE_VALUE);
  380       return PROBE_FAIL;
  381   }
  382 
  383 /*
  384  * NOTE NOTE NOTE
  385  * the new AmiScan Color board uses int 10,11,12 instead of 3,5,10
  386  * respectively. This means that the driver must act accordingly.
  387  * Unfortunately there is no easy way of telling which board one has,
  388  * other than trying to get an interrupt and noticing that it is
  389  * missing. use "option ASC_NEW_BOARD" if you have a new board.
  390  *
  391  */
  392 
  393 #if ASC_NEW_BOARD
  394 #define ASC_IRQ_A       10
  395 #define ASC_IRQ_B       11
  396 #define ASC_IRQ_C       12
  397 #else
  398 #define ASC_IRQ_A       3
  399 #define ASC_IRQ_B       5
  400 #define ASC_IRQ_C       10
  401 #endif
  402 
  403   switch(ffs(isdp->id_irq) - 1) {
  404     case ASC_IRQ_A :
  405       scu->int_byte = ASC_CNF_IRQ3;
  406       break;
  407     case ASC_IRQ_B :
  408       scu->int_byte = ASC_CNF_IRQ5;
  409       break;
  410     case ASC_IRQ_C :
  411       scu->int_byte = ASC_CNF_IRQ10;
  412       break;
  413 #if 0
  414     case -1:
  415       scu->int_byte = 0;
  416       lprintf("asc%d.probe: warning - going interruptless\n", unit);
  417       break;
  418 #endif
  419     default:
  420       lprintf("asc%d.probe: unsupported INT %d (only 3, 5, 10)\n",
  421                 unit, ffs(isdp->id_irq) - 1 );
  422       return PROBE_FAIL;
  423   }
  424   scu->dma_num = isdp->id_drq;
  425   switch(scu->dma_num) {
  426     case 1:
  427       scu->dma_byte = ASC_CNF_DMA1;
  428       break;
  429     case 3:
  430       scu->dma_byte = ASC_CNF_DMA3;
  431       break;
  432     default:
  433       lprintf("asc%d.probe: unsupported DMA %d (only 1 or 3)\n", 
  434                 unit, scu->dma_num);
  435       return PROBE_FAIL;
  436   }
  437   asc_reset(scu);
  438 /*  lprintf("asc%d.probe: ok\n", unit); */
  439 
  440   scu->flags &= ~FLAG_DEBUG;
  441   scu->icnt = 0;
  442   return PROBE_SUCCESS;
  443 }
  444 
  445 /**************************************************************************
  446  ***
  447  *** ascattach
  448  ***    finish initialization of unit structure, get geometry value (?)
  449  ***/
  450 
  451 static int
  452 ascattach(struct isa_device *isdp)
  453 {
  454   int unit = isdp->id_unit;
  455   struct asc_unit *scu = unittab + unit;
  456 
  457   isdp->id_ointr = ascintr;
  458   scu->flags |= FLAG_DEBUG;
  459   printf("asc%d: [GI1904/Trust Ami-Scan Grey/Color]\n", unit);
  460 
  461   /*
  462    * Initialize buffer structure.
  463    * XXX this must be done early to give a good chance of getting a
  464    * contiguous buffer.  This wastes memory.
  465    */
  466   scu->sbuf.base = contigmalloc((unsigned long)MAX_BUFSIZE, M_DEVBUF, M_NOWAIT,
  467                                 0ul, 0xfffffful, 1ul, 0x10000ul);
  468   if ( scu->sbuf.base == NULL )
  469     {
  470       lprintf("asc%d.attach: buffer allocation failed\n", unit);
  471       return ATTACH_FAIL;       /* XXX attach must not fail */
  472     }
  473   scu->sbuf.size = INVALID;
  474   scu->sbuf.rptr  = INVALID;
  475 
  476   scu->flags |= ATTACHED;
  477 /*  lprintf("asc%d.attach: ok\n", unit); */
  478   scu->flags &= ~FLAG_DEBUG;
  479 
  480     scu->selp.si_flags=0;
  481     scu->selp.si_pid=(pid_t)0;
  482 #define ASC_UID 0
  483 #define ASC_GID 13
  484   make_dev(&asc_cdevsw, unit<<6, ASC_UID, ASC_GID, 0666, "asc%d", unit);
  485   make_dev(&asc_cdevsw, ((unit<<6) + FRMT_PBM),
  486     ASC_UID,  ASC_GID, 0666, "asc%dp", unit);
  487   make_dev(&asc_cdevsw, ((unit<<6) + DBUG_MASK),
  488     ASC_UID,  ASC_GID, 0666, "asc%dd", unit);
  489   make_dev(&asc_cdevsw, ((unit<<6) + DBUG_MASK+FRMT_PBM), 
  490     ASC_UID, ASC_GID, 0666, "asc%dpd", unit);
  491   return ATTACH_SUCCESS;
  492 }
  493 
  494 /**************************************************************************
  495  ***
  496  *** ascintr
  497  ***    the interrupt routine, at the end of DMA...
  498  ***/
  499 static void
  500 ascintr(int unit)
  501 {
  502     struct asc_unit *scu = unittab + unit;
  503     int chan_bit = 0x01 << scu->dma_num;
  504 
  505     scu->icnt++;
  506     /* ignore stray interrupts... */
  507     if ((scu->flags & (OPEN |READING)) != (OPEN | READING) ) {
  508         /* must be after closing... */
  509         scu->flags &= ~(OPEN | READING | DMA_ACTIVE | SLEEPING | SEL_COLL);
  510         return;
  511     }
  512     if ( (scu->flags & DMA_ACTIVE) && (inb(DMA1_READY) & chan_bit) != 0) {
  513         outb( ASC_CMD, ASC_STANDBY);
  514         scu->flags &= ~DMA_ACTIVE;
  515                 /* bounce buffers... */
  516         isa_dmadone(ISADMA_READ, scu->sbuf.base+scu->sbuf.wptr,
  517             scu->linesize, scu->dma_num);
  518         scu->sbuf.wptr += scu->linesize;
  519         if (scu->sbuf.wptr >= scu->sbuf.size) scu->sbuf.wptr=0;
  520         scu->sbuf.count += scu->linesize;
  521         if (scu->flags & SLEEPING) {
  522             scu->flags &= ~SLEEPING;
  523             wakeup((caddr_t)scu);
  524         }
  525         if (scu->sbuf.size - scu->sbuf.count >= scu->linesize) {
  526             dma_restart(scu);
  527         }
  528         if (scu->selp.si_pid) {
  529             selwakeup(&scu->selp);
  530             scu->selp.si_pid=(pid_t)0;
  531             scu->selp.si_flags = 0;
  532         }
  533     }
  534 }
  535 
  536 /**************************************************************************
  537  ***
  538  *** ascopen
  539  ***    set open flag, set modes according to minor number
  540  ***    FOR RELEASE:
  541  ***    don't switch scanner on, wait until first read or ioctls go before
  542  ***/
  543 
  544 STATIC int
  545 ascopen(dev_t dev, int flags, int fmt, struct proc *p)
  546 {
  547   struct asc_unit *scu;
  548   int unit;
  549 
  550   unit = UNIT(minor(dev)) & UNIT_MASK;
  551   if ( unit >= NASC )
  552     {
  553 #ifdef ASCDEBUG
  554       /* XXX lprintf isn't valid here since there is no scu. */
  555       printf("asc%d.open: unconfigured unit number (max %d)\n", unit, NASC);
  556 #endif
  557       return ENXIO;
  558     }
  559   scu = unittab + unit;
  560   if ( !( scu->flags & ATTACHED ) )
  561     {
  562       lprintf("asc%d.open: unit was not attached successfully 0x%04x\n",
  563              unit, scu->flags);
  564       return ENXIO;
  565     }
  566 
  567   if ( minor(dev) & DBUG_MASK )
  568     scu->flags |= FLAG_DEBUG;
  569   else
  570     scu->flags &= ~FLAG_DEBUG;
  571 
  572   switch(minor(dev) & FRMT_MASK) {
  573   case FRMT_PBM:
  574     scu->flags |= PBM_MODE;
  575     lprintf("asc%d.open: pbm mode\n", unit);
  576     break;
  577   case FRMT_RAW:
  578     lprintf("asc%d.open: raw mode\n", unit);
  579     scu->flags &= ~PBM_MODE;
  580     break;
  581   default:
  582     lprintf("asc%d.open: gray maps are not yet supported", unit);
  583     return ENXIO;
  584   }
  585   
  586   lprintf("asc%d.open: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
  587 
  588   if ( scu->flags & OPEN ) {
  589       lprintf("asc%d.open: already open", unit);
  590       return EBUSY;
  591   }
  592   if (isa_dma_acquire(scu->dma_num))
  593       return(EBUSY);
  594 
  595   scu->flags = ATTACHED | OPEN;      
  596 
  597   asc_reset(scu);
  598   get_resolution(scu);
  599   return SUCCESS;
  600 }
  601 
  602 static int
  603 asc_startread(struct asc_unit *scu)
  604 {
  605     /*** from here on, things can be delayed to the first read/ioctl ***/
  606     /*** this was done in sub_12... ***/
  607   scu->cfg_byte= scu->cmd_byte=0;       /* init scanner */
  608   outb(ASC_CMD, scu->cmd_byte);
  609     /*** this was done in sub_16, set scan len... ***/
  610   outb(ASC_BOH, scu->portf_byte );
  611   if (geomtab[scu->geometry].g_res==0) {                /* color */
  612         scu->cmd_byte = 0x00 ;
  613   } else {
  614   scu->cmd_byte = 0x90 ;
  615   }
  616   outb(ASC_CMD, scu->cmd_byte);
  617   outb(ASC_LEN_L, scu->linesize & 0xff /* len_low */);
  618   outb(ASC_LEN_H, (scu->linesize >>8) & 0xff /* len_high */);
  619     /*** this was done in sub_21, config DMA ... ***/
  620   scu->cfg_byte |= scu->dma_byte;
  621   outb(ASC_CFG, scu->cfg_byte);
  622     /*** sub_22: enable int on the scanner ***/
  623   scu->cfg_byte |= scu->int_byte;
  624   outb(ASC_CFG, scu->cfg_byte);
  625     /*** sub_28: light on etc...***/
  626   scu->cmd_byte = ASC_STANDBY;
  627   outb(ASC_CMD, scu->cmd_byte);
  628   tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascstrd", hz/10); /* sleep .1 sec */
  629   return SUCCESS;
  630 }
  631 
  632 /**************************************************************************
  633  ***
  634  *** ascclose
  635  ***    turn off scanner, release the buffer
  636  ***    should probably terminate dma ops, release int and dma. lr 12mar95
  637  ***/
  638 
  639 STATIC int
  640 ascclose(dev_t dev, int flags, int fmt, struct proc *p)
  641 {
  642   int unit = UNIT(minor(dev));
  643   struct asc_unit *scu = unittab + unit;
  644 
  645   lprintf("asc%d.close: minor %d\n",
  646          unit, minor(dev));
  647 
  648   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
  649       lprintf("asc%d.close: unit was not attached successfully 0x%04x\n",
  650              unit, scu->flags);
  651       return ENXIO;
  652   }
  653     /* all this is in sub_29... */
  654   /* cli(); */
  655   outb(ASC_CFG, 0 ); /* don't save in CFG byte!!! */
  656   scu->cmd_byte &= ~ASC_LIGHT_ON;
  657   outb(ASC_CMD, scu->cmd_byte);/* light off */
  658   tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascclo", hz/2); /* sleep 1/2 sec */
  659   scu->cfg_byte &= ~ scu->dma_byte ; /* disable scanner dma */
  660   scu->cfg_byte &= ~ scu->int_byte ; /* disable scanner int */
  661   outb(ASC_CFG, scu->cfg_byte);
  662     /* --- disable dma controller ? --- */
  663   isa_dma_release(scu->dma_num);
  664     /* --- disable interrupts on the controller (sub_24) --- */
  665 
  666   scu->sbuf.size = INVALID;
  667   scu->sbuf.rptr  = INVALID;
  668 
  669   scu->flags &= ~(FLAG_DEBUG | OPEN | READING);
  670   
  671   return SUCCESS;
  672 }
  673 
  674 static void
  675 pbm_init(struct asc_unit *scu)
  676 {
  677     int width = geomtab[scu->geometry].dpl;
  678     int l= sprintf(scu->sbuf.base,"P4 %d %d\n", width, scu->height);
  679     char *p;
  680 
  681     scu->bcount = scu->height * width / 8 + l;
  682 
  683       /* move header to end of sbuf */
  684     scu->sbuf.rptr=scu->sbuf.size-l;
  685     bcopy(scu->sbuf.base, scu->sbuf.base+scu->sbuf.rptr,l);
  686     scu->sbuf.count = l;
  687     if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
  688     for(p = scu->sbuf.base + scu->sbuf.rptr; l; p++, l--)
  689         *p = ~*p;
  690 }
  691 }
  692 /**************************************************************************
  693  ***
  694  *** ascread
  695  ***/
  696 
  697 STATIC int
  698 ascread(dev_t dev, struct uio *uio, int ioflag)
  699 {
  700   int unit = UNIT(minor(dev));
  701   struct asc_unit *scu = unittab + unit;
  702   size_t nbytes;
  703   int sps, res;
  704   unsigned char *p;
  705   
  706   lprintf("asc%d.read: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
  707 
  708   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
  709       lprintf("asc%d.read: unit was not attached successfully 0x%04x\n",
  710              unit, scu->flags);
  711       return ENXIO;
  712   }
  713 
  714   if ( !(scu->flags & READING) ) { /*** first read... ***/
  715         /* allocate a buffer for reading data and init things */
  716       if ( (res = buffer_allocate(scu)) == SUCCESS ) scu->flags |= READING;
  717       else return res;
  718       asc_startread(scu);
  719       if ( scu->flags & PBM_MODE ) { /* initialize for pbm mode */
  720           pbm_init(scu);
  721       }
  722   }
  723   
  724   lprintf("asc%d.read(before): "
  725       "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
  726           unit, scu->sbuf.size, scu->sbuf.rptr,
  727           scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,
  728           scu->icnt);
  729 
  730   sps=spltty();
  731   if ( scu->sbuf.count == 0 ) { /* no data avail., must wait */
  732       if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
  733       scu->flags |= SLEEPING;
  734       res = tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascread", 0);
  735       scu->flags &= ~SLEEPING;
  736       if ( res == 0 ) res = SUCCESS;
  737   }
  738   splx(sps); /* lower priority... */
  739   if (scu->flags & FLAG_DEBUG)
  740       tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascdly",hz);
  741   lprintf("asc%d.read(after): "
  742       "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
  743           unit, scu->sbuf.size, scu->sbuf.rptr,
  744           scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,scu->icnt);
  745 
  746         /* first, not more than available... */
  747   nbytes = min( uio->uio_resid, scu->sbuf.count );
  748         /* second, contiguous data... */
  749   nbytes = min( nbytes, (scu->sbuf.size - scu->sbuf.rptr) );
  750         /* third, one line (will remove this later, XXX) */
  751   nbytes = min( nbytes, scu->linesize );
  752   if ( (scu->flags & PBM_MODE) )
  753       nbytes = min( nbytes, scu->bcount );
  754   lprintf("asc%d.read: transferring 0x%x bytes\n", unit, nbytes);
  755   if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
  756   lprintf("asc%d.read: invert buffer\n",unit);
  757   for(p = scu->sbuf.base + scu->sbuf.rptr, res=nbytes; res; p++, res--)
  758         *p = ~*p;
  759   }
  760   res = uiomove(scu->sbuf.base + scu->sbuf.rptr, nbytes, uio);
  761   if ( res != SUCCESS ) {
  762       lprintf("asc%d.read: uiomove failed %d", unit, res);
  763       return res;
  764   }
  765   
  766   sps=spltty();
  767   scu->sbuf.rptr += nbytes;
  768   if (scu->sbuf.rptr >= scu->sbuf.size) scu->sbuf.rptr=0;
  769   scu->sbuf.count -= nbytes;
  770         /* having moved some data, can read mode */
  771   if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
  772   splx(sps); /* lower priority... */
  773   if ( scu->flags & PBM_MODE ) scu->bcount -= nbytes;
  774   
  775   lprintf("asc%d.read: size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
  776           unit, scu->sbuf.size, scu->sbuf.rptr, scu->bcount);
  777   
  778   return SUCCESS;
  779 }
  780 
  781 /**************************************************************************
  782  ***
  783  *** ascioctl
  784  ***/
  785 
  786 STATIC int
  787 ascioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  788 {
  789   int unit = UNIT(minor(dev));
  790   struct asc_unit *scu = unittab + unit;
  791 
  792   lprintf("asc%d.ioctl: minor %d\n",
  793          unit, minor(dev));
  794 
  795   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
  796       lprintf("asc%d.ioctl: unit was not attached successfully 0x%04x\n",
  797              unit, scu->flags);
  798       return ENXIO;
  799   }
  800   switch(cmd) {
  801   case ASC_GRES:
  802     asc_reset(scu);
  803     get_resolution(scu);
  804     *(int *)data=geomtab[scu->geometry].dpi;
  805     lprintf("asc%d.ioctl:ASC_GRES %ddpi\n", unit, *(int *)data);
  806     return SUCCESS;    
  807   case ASC_GWIDTH:
  808     *(int *)data=geomtab[scu->geometry].dpl;
  809     lprintf("asc%d.ioctl:ASC_GWIDTH %d\n", unit, *(int *)data);
  810     return SUCCESS;    
  811   case ASC_GHEIGHT:
  812     *(int *)data=scu->height;
  813     lprintf("asc%d.ioctl:ASC_GHEIGHT %d\n", unit, *(int *)data);
  814     return SUCCESS;
  815   case ASC_SHEIGHT:
  816     lprintf("asc%d.ioctl:ASC_SHEIGHT %d\n", unit, *(int *)data);
  817     if ( scu->flags & READING ) { 
  818         lprintf("asc%d:ioctl on already reading unit\n", unit);
  819         return EBUSY;
  820     }
  821     scu->height=*(int *)data;
  822     return SUCCESS;
  823 #if 0  
  824   case ASC_GBLEN:
  825     *(int *)data=scu->blen;
  826     lprintf("asc%d.ioctl:ASC_GBLEN %d\n", unit, *(int *)data);
  827     return SUCCESS;
  828   case ASC_SBLEN:
  829     lprintf("asc%d.ioctl:ASC_SBLEN %d\n", unit, *(int *)data);
  830     if (*(int *)data * geomtab[scu->geometry].dpl / 8 > MAX_BUFSIZE)
  831       {
  832         lprintf("asc%d:ioctl buffer size too high\n", unit);
  833         return ENOMEM;
  834       }
  835     scu->blen=*(int *)data;
  836     return SUCCESS;
  837   case ASC_GBTIME:
  838     *(int *)data = scu->btime / hz;
  839     lprintf("asc%d.ioctl:ASC_GBTIME %d\n", unit, *(int *)data);
  840     return SUCCESS;
  841   case ASC_SBTIME:
  842     scu->btime = *(int *)data * hz;
  843     lprintf("asc%d.ioctl:ASC_SBTIME %d\n", unit, *(int *)data);
  844     return SUCCESS;
  845 #endif
  846   default: return ENOTTY;
  847   }
  848   return SUCCESS;
  849 }
  850 
  851 STATIC int
  852 ascpoll(dev_t dev, int events, struct proc *p)
  853 {
  854     int unit = UNIT(minor(dev));
  855     struct asc_unit *scu = unittab + unit;
  856     int sps;
  857     struct proc *p1;
  858     int revents = 0;
  859 
  860     sps=spltty();
  861 
  862     if (events & (POLLIN | POLLRDNORM)) {
  863         if (scu->sbuf.count >0)
  864             revents |= events & (POLLIN | POLLRDNORM);
  865         else {
  866             if (!(scu->flags & DMA_ACTIVE))
  867                 dma_restart(scu);
  868             
  869             if (scu->selp.si_pid && (p1=pfind(scu->selp.si_pid))
  870                     && p1->p_wchan == (caddr_t)&selwait)
  871                 scu->selp.si_flags = SI_COLL;
  872             else
  873                 scu->selp.si_pid = p->p_pid;
  874         }
  875     }
  876     splx(sps);
  877     return (revents);
  878 }

Cache object: 7d0da9a894f90c7752551e1316123078


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