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