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