kernel - Remove D_KQFILTER flag
[dragonfly.git] / sys / platform / pc64 / isa / asc.c
CommitLineData
c8fe38ae
MD
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>
429483fc 50#include <sys/event.h>
c8fe38ae
MD
51#include <sys/uio.h>
52#include <sys/thread2.h>
53
54#include <machine/asc_ioctl.h>
55
0855a2af
JG
56#include <bus/isa/isa.h>
57#include <bus/isa/isa_device.h>
c8fe38ae
MD
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 ??? */
101static 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
124struct _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
132struct 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 */
5b22f1a7 156 struct kqinfo kqp;
c8fe38ae
MD
157 int height; /* height, for pnm modes */
158 size_t bcount; /* bytes to read, for pnm modes */
159};
160
161static 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 ***/
176static int ascprobe (struct isa_device *isdp);
177static int ascattach(struct isa_device *isdp);
178struct isa_driver ascdriver = { ascprobe, ascattach, "asc" };
179
180static void ascintr(void *);
181
182static d_open_t ascopen;
183static d_close_t ascclose;
184static d_read_t ascread;
185static d_ioctl_t ascioctl;
429483fc
SG
186static d_kqfilter_t asckqfilter;
187
188static void ascfilter_detach(struct knote *kn);
189static int ascfilter(struct knote *kn, long hint);
c8fe38ae
MD
190
191#define CDEV_MAJOR 71
192
193static struct dev_ops asc_ops = {
d4b8aec4 194 { "asc", CDEV_MAJOR, 0 },
c8fe38ae
MD
195 .d_open = ascopen,
196 .d_close = ascclose,
197 .d_read = ascread,
198 .d_ioctl = ascioctl,
429483fc 199 .d_kqfilter = asckqfilter
c8fe38ae
MD
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 ***/
213static void
214get_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
262static int
263buffer_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 ***/
292static void
293dma_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 ***/
333static void
334asc_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 ***/
354static int
355ascprobe (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
443static int
444ascattach(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
c8fe38ae
MD
472#define ASC_UID 0
473#define ASC_GID 13
c8fe38ae
MD
474 make_dev(&asc_ops, unit<<6, ASC_UID, ASC_GID, 0666, "asc%d", unit);
475 make_dev(&asc_ops, ((unit<<6) + FRMT_PBM),
3e82b46c 476 ASC_UID, ASC_GID, 0666, "asc%dp", unit);
c8fe38ae 477 make_dev(&asc_ops, ((unit<<6) + DBUG_MASK),
3e82b46c 478 ASC_UID, ASC_GID, 0666, "asc%dd", unit);
c8fe38ae 479 make_dev(&asc_ops, ((unit<<6) + DBUG_MASK+FRMT_PBM),
3e82b46c 480 ASC_UID, ASC_GID, 0666, "asc%dpd", unit);
c8fe38ae
MD
481 return ATTACH_SUCCESS;
482}
483
484/**************************************************************************
485 ***
486 *** ascintr
487 *** the interrupt routine, at the end of DMA...
488 ***/
489static void
490ascintr(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 }
5b22f1a7 519 KNOTE(&scu->kqp.ki_note, 0);
c8fe38ae
MD
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
531STATIC int
532ascopen(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
590static int
591asc_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
627STATIC int
628ascclose(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
663static void
664pbm_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
686STATIC int
687ascread(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... */
e54488bb 738 nbytes = szmin(uio->uio_resid, scu->sbuf.count);
c8fe38ae 739 /* second, contiguous data... */
e54488bb 740 nbytes = szmin(nbytes, (scu->sbuf.size - scu->sbuf.rptr));
c8fe38ae 741 /* third, one line (will remove this later, XXX) */
e54488bb 742 nbytes = szmin(nbytes, scu->linesize);
c8fe38ae 743 if ( (scu->flags & PBM_MODE) )
e54488bb 744 nbytes = szmin(nbytes, scu->bcount);
c8fe38ae
MD
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
777STATIC int
778ascioctl(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
429483fc 844static struct filterops ascfiltops =
4c91dbc9 845 { FILTEROP_ISFD, NULL, ascfilter_detach, ascfilter };
429483fc
SG
846
847STATIC int
848asckqfilter(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:
b287d649 864 ap->a_result = EOPNOTSUPP;
429483fc
SG
865 return (0);
866 }
867
5b22f1a7
SG
868 klist = &scu->kqp.ki_note;
869 knote_insert(klist, kn);
429483fc
SG
870
871 return (0);
872}
873
874STATIC void
875ascfilter_detach(struct knote *kn)
876{
877 struct asc_unit *scu = (struct asc_unit *)kn->kn_hook;
878 struct klist *klist;
879
5b22f1a7
SG
880 klist = &scu->kqp.ki_note;
881 knote_remove(klist, kn);
429483fc
SG
882}
883
884STATIC int
885ascfilter(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}