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