FreeBSD/Linux Kernel Cross Reference
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: releng/5.0/sys/i386/isa/asc.c 92252 2002-03-14 01:32:30Z alfred $
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
375 scu->base = isdp->id_iobase; /*** needed by the following macros ***/
376 scu->flags = FLAG_DEBUG;
377
378 if ( isdp->id_iobase < 0 ) {
379 lprintf("asc%d.probe: no iobase given\n", unit);
380 return PROBE_FAIL;
381 }
382
383 if ((stb=inb(ASC_PROBE)) != ASC_PROBE_VALUE) {
384 lprintf("asc%d.probe: failed, got 0x%02x instead of 0x%02x\n",
385 unit, stb, ASC_PROBE_VALUE);
386 return PROBE_FAIL;
387 }
388
389 /*
390 * NOTE NOTE NOTE
391 * the new AmiScan Color board uses int 10,11,12 instead of 3,5,10
392 * respectively. This means that the driver must act accordingly.
393 * Unfortunately there is no easy way of telling which board one has,
394 * other than trying to get an interrupt and noticing that it is
395 * missing. use "option ASC_NEW_BOARD" if you have a new board.
396 *
397 */
398
399 #if ASC_NEW_BOARD
400 #define ASC_IRQ_A 10
401 #define ASC_IRQ_B 11
402 #define ASC_IRQ_C 12
403 #else
404 #define ASC_IRQ_A 3
405 #define ASC_IRQ_B 5
406 #define ASC_IRQ_C 10
407 #endif
408
409 switch(ffs(isdp->id_irq) - 1) {
410 case ASC_IRQ_A :
411 scu->int_byte = ASC_CNF_IRQ3;
412 break;
413 case ASC_IRQ_B :
414 scu->int_byte = ASC_CNF_IRQ5;
415 break;
416 case ASC_IRQ_C :
417 scu->int_byte = ASC_CNF_IRQ10;
418 break;
419 #if 0
420 case -1:
421 scu->int_byte = 0;
422 lprintf("asc%d.probe: warning - going interruptless\n", unit);
423 break;
424 #endif
425 default:
426 lprintf("asc%d.probe: unsupported INT %d (only 3, 5, 10)\n",
427 unit, ffs(isdp->id_irq) - 1 );
428 return PROBE_FAIL;
429 }
430 scu->dma_num = isdp->id_drq;
431 switch(scu->dma_num) {
432 case 1:
433 scu->dma_byte = ASC_CNF_DMA1;
434 break;
435 case 3:
436 scu->dma_byte = ASC_CNF_DMA3;
437 break;
438 default:
439 lprintf("asc%d.probe: unsupported DMA %d (only 1 or 3)\n",
440 unit, scu->dma_num);
441 return PROBE_FAIL;
442 }
443 asc_reset(scu);
444 /* lprintf("asc%d.probe: ok\n", unit); */
445
446 scu->flags &= ~FLAG_DEBUG;
447 scu->icnt = 0;
448 return PROBE_SUCCESS;
449 }
450
451 /**************************************************************************
452 ***
453 *** ascattach
454 *** finish initialization of unit structure, get geometry value (?)
455 ***/
456
457 static int
458 ascattach(struct isa_device *isdp)
459 {
460 int unit = isdp->id_unit;
461 struct asc_unit *scu = unittab + unit;
462
463 isdp->id_ointr = ascintr;
464 scu->flags |= FLAG_DEBUG;
465 printf("asc%d: [GI1904/Trust Ami-Scan Grey/Color]\n", unit);
466
467 /*
468 * Initialize buffer structure.
469 * XXX this must be done early to give a good chance of getting a
470 * contiguous buffer. This wastes memory.
471 */
472 scu->sbuf.base = contigmalloc((unsigned long)MAX_BUFSIZE, M_DEVBUF, M_NOWAIT,
473 0ul, 0xfffffful, 1ul, 0x10000ul);
474 if ( scu->sbuf.base == NULL )
475 {
476 lprintf("asc%d.attach: buffer allocation failed\n", unit);
477 return ATTACH_FAIL; /* XXX attach must not fail */
478 }
479 scu->sbuf.size = INVALID;
480 scu->sbuf.rptr = INVALID;
481
482 scu->flags |= ATTACHED;
483 /* lprintf("asc%d.attach: ok\n", unit); */
484 scu->flags &= ~FLAG_DEBUG;
485
486 scu->selp.si_flags=0;
487 #define ASC_UID 0
488 #define ASC_GID 13
489 make_dev(&asc_cdevsw, unit<<6, ASC_UID, ASC_GID, 0666, "asc%d", unit);
490 make_dev(&asc_cdevsw, ((unit<<6) + FRMT_PBM),
491 ASC_UID, ASC_GID, 0666, "asc%dp", unit);
492 make_dev(&asc_cdevsw, ((unit<<6) + DBUG_MASK),
493 ASC_UID, ASC_GID, 0666, "asc%dd", unit);
494 make_dev(&asc_cdevsw, ((unit<<6) + DBUG_MASK+FRMT_PBM),
495 ASC_UID, ASC_GID, 0666, "asc%dpd", unit);
496 return ATTACH_SUCCESS;
497 }
498
499 /**************************************************************************
500 ***
501 *** ascintr
502 *** the interrupt routine, at the end of DMA...
503 ***/
504 static void
505 ascintr(int unit)
506 {
507 struct asc_unit *scu = unittab + unit;
508 int chan_bit = 0x01 << scu->dma_num;
509
510 scu->icnt++;
511 /* ignore stray interrupts... */
512 if ((scu->flags & (OPEN |READING)) != (OPEN | READING) ) {
513 /* must be after closing... */
514 scu->flags &= ~(OPEN | READING | DMA_ACTIVE | SLEEPING | SEL_COLL);
515 return;
516 }
517 if ( (scu->flags & DMA_ACTIVE) && (inb(DMA1_READY) & chan_bit) != 0) {
518 outb( ASC_CMD, ASC_STANDBY);
519 scu->flags &= ~DMA_ACTIVE;
520 /* bounce buffers... */
521 isa_dmadone(ISADMA_READ, scu->sbuf.base+scu->sbuf.wptr,
522 scu->linesize, scu->dma_num);
523 scu->sbuf.wptr += scu->linesize;
524 if (scu->sbuf.wptr >= scu->sbuf.size) scu->sbuf.wptr=0;
525 scu->sbuf.count += scu->linesize;
526 if (scu->flags & SLEEPING) {
527 scu->flags &= ~SLEEPING;
528 wakeup((caddr_t)scu);
529 }
530 if (scu->sbuf.size - scu->sbuf.count >= scu->linesize) {
531 dma_restart(scu);
532 }
533 if (SEL_WAITING(&scu->selp)) {
534 selwakeup(&scu->selp);
535 }
536 }
537 }
538
539 /**************************************************************************
540 ***
541 *** ascopen
542 *** set open flag, set modes according to minor number
543 *** FOR RELEASE:
544 *** don't switch scanner on, wait until first read or ioctls go before
545 ***/
546
547 STATIC int
548 ascopen(dev_t dev, int flags, int fmt, struct thread *td)
549 {
550 struct asc_unit *scu;
551 int unit;
552
553 unit = UNIT(minor(dev)) & UNIT_MASK;
554 if ( unit >= NASC )
555 {
556 #ifdef ASCDEBUG
557 /* XXX lprintf isn't valid here since there is no scu. */
558 printf("asc%d.open: unconfigured unit number (max %d)\n", unit, NASC);
559 #endif
560 return ENXIO;
561 }
562 scu = unittab + unit;
563 if ( !( scu->flags & ATTACHED ) )
564 {
565 lprintf("asc%d.open: unit was not attached successfully 0x%04x\n",
566 unit, scu->flags);
567 return ENXIO;
568 }
569
570 if ( minor(dev) & DBUG_MASK )
571 scu->flags |= FLAG_DEBUG;
572 else
573 scu->flags &= ~FLAG_DEBUG;
574
575 switch(minor(dev) & FRMT_MASK) {
576 case FRMT_PBM:
577 scu->flags |= PBM_MODE;
578 lprintf("asc%d.open: pbm mode\n", unit);
579 break;
580 case FRMT_RAW:
581 lprintf("asc%d.open: raw mode\n", unit);
582 scu->flags &= ~PBM_MODE;
583 break;
584 default:
585 lprintf("asc%d.open: gray maps are not yet supported", unit);
586 return ENXIO;
587 }
588
589 lprintf("asc%d.open: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
590
591 if ( scu->flags & OPEN ) {
592 lprintf("asc%d.open: already open", unit);
593 return EBUSY;
594 }
595 if (isa_dma_acquire(scu->dma_num))
596 return(EBUSY);
597
598 scu->flags = ATTACHED | OPEN;
599
600 asc_reset(scu);
601 get_resolution(scu);
602 return SUCCESS;
603 }
604
605 static int
606 asc_startread(struct asc_unit *scu)
607 {
608 /*** from here on, things can be delayed to the first read/ioctl ***/
609 /*** this was done in sub_12... ***/
610 scu->cfg_byte= scu->cmd_byte=0; /* init scanner */
611 outb(ASC_CMD, scu->cmd_byte);
612 /*** this was done in sub_16, set scan len... ***/
613 outb(ASC_BOH, scu->portf_byte );
614 if (geomtab[scu->geometry].g_res==0) { /* color */
615 scu->cmd_byte = 0x00 ;
616 } else {
617 scu->cmd_byte = 0x90 ;
618 }
619 outb(ASC_CMD, scu->cmd_byte);
620 outb(ASC_LEN_L, scu->linesize & 0xff /* len_low */);
621 outb(ASC_LEN_H, (scu->linesize >>8) & 0xff /* len_high */);
622 /*** this was done in sub_21, config DMA ... ***/
623 scu->cfg_byte |= scu->dma_byte;
624 outb(ASC_CFG, scu->cfg_byte);
625 /*** sub_22: enable int on the scanner ***/
626 scu->cfg_byte |= scu->int_byte;
627 outb(ASC_CFG, scu->cfg_byte);
628 /*** sub_28: light on etc...***/
629 scu->cmd_byte = ASC_STANDBY;
630 outb(ASC_CMD, scu->cmd_byte);
631 tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascstrd", hz/10); /* sleep .1 sec */
632 return SUCCESS;
633 }
634
635 /**************************************************************************
636 ***
637 *** ascclose
638 *** turn off scanner, release the buffer
639 *** should probably terminate dma ops, release int and dma. lr 12mar95
640 ***/
641
642 STATIC int
643 ascclose(dev_t dev, int flags, int fmt, struct thread *td)
644 {
645 int unit = UNIT(minor(dev));
646 struct asc_unit *scu = unittab + unit;
647
648 lprintf("asc%d.close: minor %d\n",
649 unit, minor(dev));
650
651 if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
652 lprintf("asc%d.close: unit was not attached successfully 0x%04x\n",
653 unit, scu->flags);
654 return ENXIO;
655 }
656 /* all this is in sub_29... */
657 /* cli(); */
658 outb(ASC_CFG, 0 ); /* don't save in CFG byte!!! */
659 scu->cmd_byte &= ~ASC_LIGHT_ON;
660 outb(ASC_CMD, scu->cmd_byte);/* light off */
661 tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascclo", hz/2); /* sleep 1/2 sec */
662 scu->cfg_byte &= ~ scu->dma_byte ; /* disable scanner dma */
663 scu->cfg_byte &= ~ scu->int_byte ; /* disable scanner int */
664 outb(ASC_CFG, scu->cfg_byte);
665 /* --- disable dma controller ? --- */
666 isa_dma_release(scu->dma_num);
667 /* --- disable interrupts on the controller (sub_24) --- */
668
669 scu->sbuf.size = INVALID;
670 scu->sbuf.rptr = INVALID;
671
672 scu->flags &= ~(FLAG_DEBUG | OPEN | READING);
673
674 return SUCCESS;
675 }
676
677 static void
678 pbm_init(struct asc_unit *scu)
679 {
680 int width = geomtab[scu->geometry].dpl;
681 int l= sprintf(scu->sbuf.base,"P4 %d %d\n", width, scu->height);
682 char *p;
683
684 scu->bcount = scu->height * width / 8 + l;
685
686 /* move header to end of sbuf */
687 scu->sbuf.rptr=scu->sbuf.size-l;
688 bcopy(scu->sbuf.base, scu->sbuf.base+scu->sbuf.rptr,l);
689 scu->sbuf.count = l;
690 if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
691 for(p = scu->sbuf.base + scu->sbuf.rptr; l; p++, l--)
692 *p = ~*p;
693 }
694 }
695 /**************************************************************************
696 ***
697 *** ascread
698 ***/
699
700 STATIC int
701 ascread(dev_t dev, struct uio *uio, int ioflag)
702 {
703 int unit = UNIT(minor(dev));
704 struct asc_unit *scu = unittab + unit;
705 size_t nbytes;
706 int sps, res;
707 unsigned char *p;
708
709 lprintf("asc%d.read: minor %d icnt %ld\n", unit, minor(dev), scu->icnt);
710
711 if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
712 lprintf("asc%d.read: unit was not attached successfully 0x%04x\n",
713 unit, scu->flags);
714 return ENXIO;
715 }
716
717 if ( !(scu->flags & READING) ) { /*** first read... ***/
718 /* allocate a buffer for reading data and init things */
719 if ( (res = buffer_allocate(scu)) == SUCCESS ) scu->flags |= READING;
720 else return res;
721 asc_startread(scu);
722 if ( scu->flags & PBM_MODE ) { /* initialize for pbm mode */
723 pbm_init(scu);
724 }
725 }
726
727 lprintf("asc%d.read(before): "
728 "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
729 unit, scu->sbuf.size, scu->sbuf.rptr,
730 scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,
731 scu->icnt);
732
733 sps=spltty();
734 if ( scu->sbuf.count == 0 ) { /* no data avail., must wait */
735 if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
736 scu->flags |= SLEEPING;
737 res = tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascread", 0);
738 scu->flags &= ~SLEEPING;
739 if ( res == 0 ) res = SUCCESS;
740 }
741 splx(sps); /* lower priority... */
742 if (scu->flags & FLAG_DEBUG)
743 tsleep((caddr_t)scu, ASCPRI | PCATCH, "ascdly",hz);
744 lprintf("asc%d.read(after): "
745 "sz 0x%x, rptr 0x%x, wptr 0x%x, cnt 0x%x bcnt 0x%x flags 0x%x icnt %ld\n",
746 unit, scu->sbuf.size, scu->sbuf.rptr,
747 scu->sbuf.wptr, scu->sbuf.count, scu->bcount,scu->flags,scu->icnt);
748
749 /* first, not more than available... */
750 nbytes = min( uio->uio_resid, scu->sbuf.count );
751 /* second, contiguous data... */
752 nbytes = min( nbytes, (scu->sbuf.size - scu->sbuf.rptr) );
753 /* third, one line (will remove this later, XXX) */
754 nbytes = min( nbytes, scu->linesize );
755 if ( (scu->flags & PBM_MODE) )
756 nbytes = min( nbytes, scu->bcount );
757 lprintf("asc%d.read: transferring 0x%x bytes\n", unit, nbytes);
758 if (geomtab[scu->geometry].g_res!=0) { /* BW scanner */
759 lprintf("asc%d.read: invert buffer\n",unit);
760 for(p = scu->sbuf.base + scu->sbuf.rptr, res=nbytes; res; p++, res--)
761 *p = ~*p;
762 }
763 res = uiomove(scu->sbuf.base + scu->sbuf.rptr, nbytes, uio);
764 if ( res != SUCCESS ) {
765 lprintf("asc%d.read: uiomove failed %d", unit, res);
766 return res;
767 }
768
769 sps=spltty();
770 scu->sbuf.rptr += nbytes;
771 if (scu->sbuf.rptr >= scu->sbuf.size) scu->sbuf.rptr=0;
772 scu->sbuf.count -= nbytes;
773 /* having moved some data, can read mode */
774 if (!(scu->flags & DMA_ACTIVE)) dma_restart(scu);
775 splx(sps); /* lower priority... */
776 if ( scu->flags & PBM_MODE ) scu->bcount -= nbytes;
777
778 lprintf("asc%d.read: size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
779 unit, scu->sbuf.size, scu->sbuf.rptr, scu->bcount);
780
781 return SUCCESS;
782 }
783
784 /**************************************************************************
785 ***
786 *** ascioctl
787 ***/
788
789 STATIC int
790 ascioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
791 {
792 int unit = UNIT(minor(dev));
793 struct asc_unit *scu = unittab + unit;
794
795 lprintf("asc%d.ioctl: minor %d\n",
796 unit, minor(dev));
797
798 if ( unit >= NASC || !( scu->flags & ATTACHED ) ) {
799 lprintf("asc%d.ioctl: unit was not attached successfully 0x%04x\n",
800 unit, scu->flags);
801 return ENXIO;
802 }
803 switch(cmd) {
804 case ASC_GRES:
805 asc_reset(scu);
806 get_resolution(scu);
807 *(int *)data=geomtab[scu->geometry].dpi;
808 lprintf("asc%d.ioctl:ASC_GRES %ddpi\n", unit, *(int *)data);
809 return SUCCESS;
810 case ASC_GWIDTH:
811 *(int *)data=geomtab[scu->geometry].dpl;
812 lprintf("asc%d.ioctl:ASC_GWIDTH %d\n", unit, *(int *)data);
813 return SUCCESS;
814 case ASC_GHEIGHT:
815 *(int *)data=scu->height;
816 lprintf("asc%d.ioctl:ASC_GHEIGHT %d\n", unit, *(int *)data);
817 return SUCCESS;
818 case ASC_SHEIGHT:
819 lprintf("asc%d.ioctl:ASC_SHEIGHT %d\n", unit, *(int *)data);
820 if ( scu->flags & READING ) {
821 lprintf("asc%d:ioctl on already reading unit\n", unit);
822 return EBUSY;
823 }
824 scu->height=*(int *)data;
825 return SUCCESS;
826 #if 0
827 case ASC_GBLEN:
828 *(int *)data=scu->blen;
829 lprintf("asc%d.ioctl:ASC_GBLEN %d\n", unit, *(int *)data);
830 return SUCCESS;
831 case ASC_SBLEN:
832 lprintf("asc%d.ioctl:ASC_SBLEN %d\n", unit, *(int *)data);
833 if (*(int *)data * geomtab[scu->geometry].dpl / 8 > MAX_BUFSIZE)
834 {
835 lprintf("asc%d:ioctl buffer size too high\n", unit);
836 return ENOMEM;
837 }
838 scu->blen=*(int *)data;
839 return SUCCESS;
840 case ASC_GBTIME:
841 *(int *)data = scu->btime / hz;
842 lprintf("asc%d.ioctl:ASC_GBTIME %d\n", unit, *(int *)data);
843 return SUCCESS;
844 case ASC_SBTIME:
845 scu->btime = *(int *)data * hz;
846 lprintf("asc%d.ioctl:ASC_SBTIME %d\n", unit, *(int *)data);
847 return SUCCESS;
848 #endif
849 default: return ENOTTY;
850 }
851 return SUCCESS;
852 }
853
854 STATIC int
855 ascpoll(dev_t dev, int events, struct thread *td)
856 {
857 int unit = UNIT(minor(dev));
858 struct asc_unit *scu = unittab + unit;
859 int sps;
860 int revents = 0;
861
862 sps=spltty();
863
864 if (events & (POLLIN | POLLRDNORM)) {
865 if (scu->sbuf.count >0)
866 revents |= events & (POLLIN | POLLRDNORM);
867 else {
868 if (!(scu->flags & DMA_ACTIVE))
869 dma_restart(scu);
870
871 selrecord(td, &scu->selp);
872 }
873 }
874 splx(sps);
875 return (revents);
876 }
Cache object: e99e50ae54adbc9c5793627b8aa43c31
|