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

Cache object: 209ece99e5f742f0924e76f191da86cd


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