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