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

Cache object: e99e50ae54adbc9c5793627b8aa43c31


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