dc48b88a040b2a9698a1fc4e28fac286bea52359
[dragonfly.git] / sys / platform / pc32 / 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  * $FreeBSD: src/sys/i386/isa/asc.c,v 1.42.2.2 2001/03/01 03:22:39 jlemon Exp $
38  * $DragonFly: src/sys/platform/pc32/isa/asc.c,v 1.21 2008/08/02 01:14:43 dillon Exp $
39  */
40
41 #include "use_asc.h"
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/event.h>
51 #include <sys/selinfo.h>
52 #include <sys/uio.h>
53 #include <sys/thread2.h>
54 #include <sys/bus.h>
55
56 #include <machine/asc_ioctl.h>
57
58 #include <bus/isa/isa.h>
59 #include <bus/isa/isa_device.h>
60 #include <bus/isa/isavar.h>
61 #include "ascreg.h"
62
63 /***
64  *** CONSTANTS & DEFINES
65  ***
66  ***/
67
68 #define PROBE_FAIL    0
69 #define PROBE_SUCCESS IO_ASCSIZE
70 #define ATTACH_FAIL   0
71 #define ATTACH_SUCCESS 1
72 #define SUCCESS       0
73 #define FAIL         -1
74 #define INVALID       FAIL
75
76 #define DMA1_READY  0x08
77 #define ASCDEBUG
78 #ifdef ASCDEBUG
79 #       define lprintf if(scu->flags & FLAG_DEBUG) kprintf
80 #else
81 #       define lprintf (void)
82 #endif
83
84 #define TIMEOUT (hz*15)  /* timeout while reading a buffer - default value */
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 struct isa_driver ascdriver = { ascprobe, ascattach, "asc" };
182
183 static void             ascintr(void *);
184
185 static d_open_t         ascopen;
186 static d_close_t        ascclose;
187 static d_read_t         ascread;
188 static d_ioctl_t        ascioctl;
189 static d_poll_t         ascpoll;
190 static d_kqfilter_t     asckqfilter;
191
192 static void ascfilter_detach(struct knote *kn);
193 static int ascfilter(struct knote *kn, long hint);
194
195 #define CDEV_MAJOR 71
196
197 static struct dev_ops asc_ops = {
198         { "asc", CDEV_MAJOR, D_KQFILTER },
199         .d_open =       ascopen,
200         .d_close =      ascclose,
201         .d_read =       ascread,
202         .d_ioctl =      ascioctl,
203         .d_poll =       ascpoll,
204         .d_kqfilter =   asckqfilter
205 };
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, PCATCH, "ascres", hz/10);
227     for(delay= 100; (res=inb(ASC_STAT)) & ASC_RDY_FLAG; delay--)
228     {
229         i = tsleep((caddr_t)scu, 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(BUF_CMD_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(BUF_CMD_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, 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_intr = (inthand2_t *)ascintr;
455   scu->flags |= FLAG_DEBUG;
456   kprintf("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 #define ASC_UID 0
480 #define ASC_GID 13
481   make_dev(&asc_ops, unit<<6, ASC_UID, ASC_GID, 0666, "asc%d", unit);
482   make_dev(&asc_ops, ((unit<<6) + FRMT_PBM),
483            ASC_UID,  ASC_GID, 0666, "asc%dp", unit);
484   make_dev(&asc_ops, ((unit<<6) + DBUG_MASK),
485            ASC_UID,  ASC_GID, 0666, "asc%dd", unit);
486   make_dev(&asc_ops, ((unit<<6) + DBUG_MASK+FRMT_PBM), 
487            ASC_UID, ASC_GID, 0666, "asc%dpd", unit);
488   return ATTACH_SUCCESS;
489 }
490
491 /**************************************************************************
492  ***
493  *** ascintr
494  ***    the interrupt routine, at the end of DMA...
495  ***/
496 static void
497 ascintr(void *arg)
498 {
499     int unit = (int)arg;
500     struct asc_unit *scu = unittab + unit;
501     int chan_bit = 0x01 << scu->dma_num;
502
503     scu->icnt++;
504     /* ignore stray interrupts... */
505     if ((scu->flags & (OPEN |READING)) != (OPEN | READING) ) {
506         /* must be after closing... */
507         scu->flags &= ~(OPEN | READING | DMA_ACTIVE | SLEEPING | SEL_COLL);
508         return;
509     }
510     if ( (scu->flags & DMA_ACTIVE) && (inb(DMA1_READY) & chan_bit) != 0) {
511         outb( ASC_CMD, ASC_STANDBY);
512         scu->flags &= ~DMA_ACTIVE;
513                 /* bounce buffers... */
514         isa_dmadone(BUF_CMD_READ, scu->sbuf.base+scu->sbuf.wptr,
515             scu->linesize, scu->dma_num);
516         scu->sbuf.wptr += scu->linesize;
517         if (scu->sbuf.wptr >= scu->sbuf.size) scu->sbuf.wptr=0;
518         scu->sbuf.count += scu->linesize;
519         if (scu->flags & SLEEPING) {
520             scu->flags &= ~SLEEPING;
521             wakeup((caddr_t)scu);
522         }
523         if (scu->sbuf.size - scu->sbuf.count >= scu->linesize) {
524             dma_restart(scu);
525         }
526         if (scu->selp.si_pid) {
527             selwakeup(&scu->selp);
528             scu->selp.si_pid=(pid_t)0;
529             scu->selp.si_flags = 0;
530         }
531     }
532 }
533
534 /**************************************************************************
535  ***
536  *** ascopen
537  ***    set open flag, set modes according to minor number
538  ***    FOR RELEASE:
539  ***    don't switch scanner on, wait until first read or ioctls go before
540  ***/
541
542 STATIC int
543 ascopen(struct dev_open_args *ap)
544 {
545   cdev_t dev = ap->a_head.a_dev;
546   struct asc_unit *scu;
547   int unit;
548
549   unit = UNIT(minor(dev)) & UNIT_MASK;
550   if ( unit >= NASC )
551     {
552 #ifdef ASCDEBUG
553       /* XXX lprintf isn't valid here since there is no scu. */
554       kprintf("asc%d.open: unconfigured unit number (max %d)\n", unit, NASC);
555 #endif
556       return ENXIO;
557     }
558   scu = unittab + unit;
559   if ( !( scu->flags & ATTACHED ) )
560     {
561       lprintf("asc%d.open: unit was not attached successfully 0x%04x\n",
562              unit, scu->flags);
563       return ENXIO;
564     }
565
566   if ( minor(dev) & DBUG_MASK )
567     scu->flags |= FLAG_DEBUG;
568   else
569     scu->flags &= ~FLAG_DEBUG;
570
571   switch(minor(dev) & FRMT_MASK) {
572   case FRMT_PBM:
573     scu->flags |= PBM_MODE;
574     lprintf("asc%d.open: pbm mode\n", unit);
575     break;
576   case FRMT_RAW:
577     lprintf("asc%d.open: raw mode\n", unit);
578     scu->flags &= ~PBM_MODE;
579     break;
580   default:
581     lprintf("asc%d.open: gray maps are not yet supported", unit);
582     return ENXIO;
583   }
584   
585   lprintf("asc%d.open: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
586
587   if ( scu->flags & OPEN ) {
588       lprintf("asc%d.open: already open", unit);
589       return EBUSY;
590   }
591   if (isa_dma_acquire(scu->dma_num))
592       return(EBUSY);
593
594   scu->flags = ATTACHED | OPEN;      
595
596   asc_reset(scu);
597   get_resolution(scu);
598   return SUCCESS;
599 }
600
601 static int
602 asc_startread(struct asc_unit *scu)
603 {
604     /*** from here on, things can be delayed to the first read/ioctl ***/
605     /*** this was done in sub_12... ***/
606   scu->cfg_byte= scu->cmd_byte=0;       /* init scanner */
607   outb(ASC_CMD, scu->cmd_byte);
608     /*** this was done in sub_16, set scan len... ***/
609   outb(ASC_BOH, scu->portf_byte );
610   if (geomtab[scu->geometry].g_res==0) {                /* color */
611         scu->cmd_byte = 0x00 ;
612   } else {
613   scu->cmd_byte = 0x90 ;
614   }
615   outb(ASC_CMD, scu->cmd_byte);
616   outb(ASC_LEN_L, scu->linesize & 0xff /* len_low */);
617   outb(ASC_LEN_H, (scu->linesize >>8) & 0xff /* len_high */);
618     /*** this was done in sub_21, config DMA ... ***/
619   scu->cfg_byte |= scu->dma_byte;
620   outb(ASC_CFG, scu->cfg_byte);
621     /*** sub_22: enable int on the scanner ***/
622   scu->cfg_byte |= scu->int_byte;
623   outb(ASC_CFG, scu->cfg_byte);
624     /*** sub_28: light on etc...***/
625   scu->cmd_byte = ASC_STANDBY;
626   outb(ASC_CMD, scu->cmd_byte);
627   tsleep((caddr_t)scu, PCATCH, "ascstrd", hz/10); /* sleep .1 sec */
628   return SUCCESS;
629 }
630
631 /**************************************************************************
632  ***
633  *** ascclose
634  ***    turn off scanner, release the buffer
635  ***    should probably terminate dma ops, release int and dma. lr 12mar95
636  ***/
637
638 STATIC int
639 ascclose(struct dev_close_args *ap)
640 {
641   cdev_t dev = ap->a_head.a_dev;
642   int unit = UNIT(minor(dev));
643   struct asc_unit *scu = unittab + unit;
644
645   lprintf("asc%d.close: minor %d\n",
646          unit, minor(dev));
647
648   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
649       lprintf("asc%d.close: unit was not attached successfully 0x%04x\n",
650              unit, scu->flags);
651       return ENXIO;
652   }
653     /* all this is in sub_29... */
654   /* cli(); */
655   outb(ASC_CFG, 0 ); /* don't save in CFG byte!!! */
656   scu->cmd_byte &= ~ASC_LIGHT_ON;
657   outb(ASC_CMD, scu->cmd_byte);/* light off */
658   tsleep((caddr_t)scu, PCATCH, "ascclo", hz/2); /* sleep 1/2 sec */
659   scu->cfg_byte &= ~ scu->dma_byte ; /* disable scanner dma */
660   scu->cfg_byte &= ~ scu->int_byte ; /* disable scanner int */
661   outb(ASC_CFG, scu->cfg_byte);
662     /* --- disable dma controller ? --- */
663   isa_dma_release(scu->dma_num);
664     /* --- disable interrupts on the controller (sub_24) --- */
665
666   scu->sbuf.size = INVALID;
667   scu->sbuf.rptr  = INVALID;
668
669   scu->flags &= ~(FLAG_DEBUG | OPEN | READING);
670   
671   return SUCCESS;
672 }
673
674 static void
675 pbm_init(struct asc_unit *scu)
676 {
677     int width = geomtab[scu->geometry].dpl;
678     int l= ksprintf(scu->sbuf.base,"P4 %d %d\n", width, scu->height);
679     char *p;
680
681     scu->bcount = scu->height * width / 8 + l;
682
683       /* move header to end of sbuf */
684     scu->sbuf.rptr=scu->sbuf.size-l;
685     bcopy(scu->sbuf.base, scu->sbuf.base+scu->sbuf.rptr,l);
686     scu->sbuf.count = l;
687     if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
688     for(p = scu->sbuf.base + scu->sbuf.rptr; l; p++, l--)
689         *p = ~*p;
690 }
691 }
692 /**************************************************************************
693  ***
694  *** ascread
695  ***/
696
697 STATIC int
698 ascread(struct dev_read_args *ap)
699 {
700   cdev_t dev = ap->a_head.a_dev;
701   struct uio *uio = ap->a_uio;
702   int unit = UNIT(minor(dev));
703   struct asc_unit *scu = unittab + unit;
704   size_t nbytes;
705   int res;
706   unsigned char *p;
707   
708   lprintf("asc%d.read: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
709
710   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
711       lprintf("asc%d.read: unit was not attached successfully 0x%04x\n",
712              unit, scu->flags);
713       return ENXIO;
714   }
715
716   if ( !(scu->flags & READING) ) { /*** first read... ***/
717         /* allocate a buffer for reading data and init things */
718       if ( (res = buffer_allocate(scu)) == SUCCESS ) scu->flags |= READING;
719       else return res;
720       asc_startread(scu);
721       if ( scu->flags & PBM_MODE ) { /* initialize for pbm mode */
722           pbm_init(scu);
723       }
724   }
725   
726   lprintf("asc%d.read(before): "
727       "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
728           unit, scu->sbuf.size, scu->sbuf.rptr,
729           scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,
730           scu->icnt);
731
732   crit_enter();
733   if ( scu->sbuf.count == 0 ) { /* no data avail., must wait */
734       if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
735       scu->flags |= SLEEPING;
736       res = tsleep((caddr_t)scu, PCATCH, "ascread", 0);
737       scu->flags &= ~SLEEPING;
738       if ( res == 0 ) res = SUCCESS;
739   }
740   crit_exit();
741   if (scu->flags & FLAG_DEBUG)
742       tsleep((caddr_t)scu, PCATCH, "ascdly",hz);
743   lprintf("asc%d.read(after): "
744       "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
745           unit, scu->sbuf.size, scu->sbuf.rptr,
746           scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,scu->icnt);
747
748         /* first, not more than available... */
749   nbytes = szmin(uio->uio_resid, scu->sbuf.count);
750         /* second, contiguous data... */
751   nbytes = szmin( nbytes, (scu->sbuf.size - scu->sbuf.rptr) );
752         /* third, one line (will remove this later, XXX) */
753   nbytes = szmin( nbytes, scu->linesize );
754   if ( (scu->flags & PBM_MODE) )
755       nbytes = szmin( nbytes, scu->bcount );
756   lprintf("asc%d.read: transferring 0x%x bytes\n", unit, nbytes);
757   if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
758   lprintf("asc%d.read: invert buffer\n",unit);
759   for(p = scu->sbuf.base + scu->sbuf.rptr, res=nbytes; res; p++, res--)
760         *p = ~*p;
761   }
762   res = uiomove(scu->sbuf.base + scu->sbuf.rptr, nbytes, uio);
763   if ( res != SUCCESS ) {
764       lprintf("asc%d.read: uiomove failed %d", unit, res);
765       return res;
766   }
767   
768   crit_enter();
769   scu->sbuf.rptr += nbytes;
770   if (scu->sbuf.rptr >= scu->sbuf.size) scu->sbuf.rptr=0;
771   scu->sbuf.count -= nbytes;
772         /* having moved some data, can read mode */
773   if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
774   crit_exit();
775   if ( scu->flags & PBM_MODE ) scu->bcount -= nbytes;
776   
777   lprintf("asc%d.read: size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
778           unit, scu->sbuf.size, scu->sbuf.rptr, scu->bcount);
779   
780   return SUCCESS;
781 }
782
783 /**************************************************************************
784  ***
785  *** ascioctl
786  ***/
787
788 STATIC int
789 ascioctl(struct dev_ioctl_args *ap)
790 {
791   cdev_t dev = ap->a_head.a_dev;
792   caddr_t data = ap->a_data;
793   int unit = UNIT(minor(dev));
794   struct asc_unit *scu = unittab + unit;
795
796   lprintf("asc%d.ioctl: minor %d\n",
797          unit, minor(dev));
798
799   if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
800       lprintf("asc%d.ioctl: unit was not attached successfully 0x%04x\n",
801              unit, scu->flags);
802       return ENXIO;
803   }
804   switch(ap->a_cmd) {
805   case ASC_GRES:
806     asc_reset(scu);
807     get_resolution(scu);
808     *(int *)data=geomtab[scu->geometry].dpi;
809     lprintf("asc%d.ioctl:ASC_GRES %ddpi\n", unit, *(int *)data);
810     return SUCCESS;    
811   case ASC_GWIDTH:
812     *(int *)data=geomtab[scu->geometry].dpl;
813     lprintf("asc%d.ioctl:ASC_GWIDTH %d\n", unit, *(int *)data);
814     return SUCCESS;    
815   case ASC_GHEIGHT:
816     *(int *)data=scu->height;
817     lprintf("asc%d.ioctl:ASC_GHEIGHT %d\n", unit, *(int *)data);
818     return SUCCESS;
819   case ASC_SHEIGHT:
820     lprintf("asc%d.ioctl:ASC_SHEIGHT %d\n", unit, *(int *)data);
821     if ( scu->flags & READING ) { 
822         lprintf("asc%d:ioctl on already reading unit\n", unit);
823         return EBUSY;
824     }
825     scu->height=*(int *)data;
826     return SUCCESS;
827 #if 0  
828   case ASC_GBLEN:
829     *(int *)data=scu->blen;
830     lprintf("asc%d.ioctl:ASC_GBLEN %d\n", unit, *(int *)data);
831     return SUCCESS;
832   case ASC_SBLEN:
833     lprintf("asc%d.ioctl:ASC_SBLEN %d\n", unit, *(int *)data);
834     if (*(int *)data * geomtab[scu->geometry].dpl / 8 > MAX_BUFSIZE)
835       {
836         lprintf("asc%d:ioctl buffer size too high\n", unit);
837         return ENOMEM;
838       }
839     scu->blen=*(int *)data;
840     return SUCCESS;
841   case ASC_GBTIME:
842     *(int *)data = scu->btime / hz;
843     lprintf("asc%d.ioctl:ASC_GBTIME %d\n", unit, *(int *)data);
844     return SUCCESS;
845   case ASC_SBTIME:
846     scu->btime = *(int *)data * hz;
847     lprintf("asc%d.ioctl:ASC_SBTIME %d\n", unit, *(int *)data);
848     return SUCCESS;
849 #endif
850   default: return ENOTTY;
851   }
852   return SUCCESS;
853 }
854
855 STATIC int
856 ascpoll(struct dev_poll_args *ap)
857 {
858     cdev_t dev = ap->a_head.a_dev;
859     int unit = UNIT(minor(dev));
860     struct asc_unit *scu = unittab + unit;
861     int revents = 0;
862
863     crit_enter();
864
865     if (ap->a_events & (POLLIN | POLLRDNORM)) {
866         if (scu->sbuf.count >0)
867             revents |= ap->a_events & (POLLIN | POLLRDNORM);
868         else {
869             if (!(scu->flags & DMA_ACTIVE))
870                 dma_restart(scu);
871
872             selrecord(curthread, &scu->selp);
873         }
874     }
875     crit_exit();
876     ap->a_events = revents;
877     return (0);
878 }
879
880 static struct filterops ascfiltops =
881     { 1, NULL, ascfilter_detach, ascfilter };
882
883 STATIC int
884 asckqfilter(struct dev_kqfilter_args *ap)
885 {
886     cdev_t dev = ap->a_head.a_dev;
887     int unit = UNIT(minor(dev));
888     struct asc_unit *scu = unittab + unit;
889     struct knote *kn = ap->a_kn;
890     struct klist *klist;
891
892     ap->a_result = 0;
893
894     switch (kn->kn_filter) {
895     case EVFILT_READ:
896         kn->kn_fop = &ascfiltops;
897         kn->kn_hook = (caddr_t)scu;
898         break;
899     default:
900         ap->a_result = 1;
901         return (0);
902     }
903
904     crit_enter();
905     klist = &scu->selp.si_note;
906     SLIST_INSERT_HEAD(klist, kn, kn_selnext);
907     crit_exit();
908
909     return (0);
910 }
911
912 STATIC void
913 ascfilter_detach(struct knote *kn)
914 {
915     struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
916     struct klist *klist;
917
918     crit_enter();
919     klist = &scu->selp.si_note;
920     SLIST_REMOVE(klist, kn, knote, kn_selnext);
921     crit_exit();
922 }
923
924 STATIC int
925 ascfilter(struct knote *kn, long hint)
926 {
927     struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
928     int ready = 0;
929
930     crit_enter();
931     if (scu->sbuf.count >0)
932         ready = 1;
933     else {
934         if (!(scu->flags & DMA_ACTIVE))
935             dma_restart(scu);
936     }
937     crit_exit();
938
939     return (ready);
940 }