Merge from vendor branch BIND:
[dragonfly.git] / sys / dev / video / gsc / gsc.c
1 /* gsc.c - device driver for handy scanners
2  *
3  * Current version supports:
4  *
5  *      - Genius GS-4500
6  *
7  * Copyright (c) 1995 Gunther Schadow.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gunther Schadow.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $FreeBSD: src/sys/i386/isa/gsc.c,v 1.35.2.1 2000/08/08 19:49:53 peter Exp $
35  * $DragonFly: src/sys/dev/video/gsc/gsc.c,v 1.13 2006/09/10 01:26:38 dillon Exp $
36  *
37  */
38
39 #include "use_gsc.h"
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/conf.h>
43 #include <sys/buf.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <sys/uio.h>
47 #include <sys/thread2.h>
48
49 #include <machine/gsc.h>
50
51 #include <bus/isa/i386/isa.h>
52 #include <bus/isa/i386/isa_device.h>
53 #include "gscreg.h"
54
55 /***********************************************************************
56  *
57  * CONSTANTS & DEFINES
58  *
59  ***********************************************************************/
60
61 #define PROBE_FAIL    0
62 #define PROBE_SUCCESS IO_GSCSIZE
63 #define ATTACH_FAIL   0
64 #define ATTACH_SUCCESS 1
65 #define SUCCESS       0
66 #define FAIL         -1
67 #define INVALID       FAIL
68
69 #define DMA1_READY  0x08
70
71 #ifdef GSCDEBUG
72 #define lprintf(args)                                           \
73                 do {                                            \
74                         if (scu->flags & FLAG_DEBUG)            \
75                                 printf args;                    \
76                 } while (0)
77 #else
78 #define lprintf(args)
79 #endif
80
81 #define TIMEOUT (hz*15)  /* timeout while reading a buffer - default value */
82 #define LONG    (hz/60)  /* timesteps while reading a buffer */
83
84 /***********************************************************************
85  *
86  * LAYOUT OF THE MINOR NUMBER
87  *
88  ***********************************************************************/
89
90 #define UNIT_MASK 0xc0    /* unit gsc0 .. gsc3 */
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 0x10    /* output graymap (not implemented yet) */
96 #define FRMT_PBM  0x08    /* output pbm format */
97 #define FRMT_PGM  0x18
98
99 /***********************************************************************
100  *
101  * THE GEMOMETRY TABLE
102  *
103  ***********************************************************************/
104
105 #define GEOMTAB_SIZE 7
106
107 static const struct gsc_geom {
108   int dpi;     /* dots per inch */
109   int dpl;     /* dots per line */
110   int g_res;   /* get resolution value (status flag) */
111   int s_res;   /* set resolution value (control register) */
112 } geomtab[GEOMTAB_SIZE] = {
113   { 100,  424, GSC_RES_100, GSC_CNT_424},
114   { 200,  840, GSC_RES_200, GSC_CNT_840},
115   { 300, 1264, GSC_RES_300, GSC_CNT_1264},
116   { 400, 1648, GSC_RES_400, GSC_CNT_1648},
117   {  -1, 1696,          -1, GSC_CNT_1696},
118   {  -2, 2644,          -2, GSC_CNT_2544},
119   {  -3, 3648,          -3, GSC_CNT_3648},
120 };
121
122 #define NEW_GEOM { INVALID, INVALID, INVALID, INVALID }
123
124 /***********************************************************************
125  *
126  * THE TABLE OF UNITS
127  *
128  ***********************************************************************/
129
130 struct _sbuf {
131   size_t  size;
132   size_t  poi;
133   char   *base;
134 };
135
136 struct gsc_unit {
137   int channel;            /* DMA channel */
138   int data;               /* - video port */
139   int stat;               /* - status port */
140   int ctrl;               /* - control port */
141   int clrp;               /* - clear port */
142   int flags;
143 #define ATTACHED 0x01
144 #define OPEN     0x02
145 #define READING  0x04
146 #define EOF      0x08
147 #define FLAG_DEBUG  0x10
148 #define PBM_MODE 0x20
149   int     geometry;       /* resolution as geomtab index */
150   int     blen;           /* length of buffer in lines */
151   int     btime;          /* timeout of buffer in seconds/hz */
152   struct  _sbuf sbuf;
153   char    ctrl_byte;      /* the byte actually written to ctrl port */
154   int     height;         /* height, for pnm modes */
155   size_t  bcount;         /* bytes to read, for pnm modes */
156   struct  _sbuf hbuf;     /* buffer for pnm header data */
157 };
158
159 static struct gsc_unit unittab[NGSC];
160
161 /* I could not find a reasonable buffer size limit other than by
162  * experiments. MAXPHYS is obviously too much, while DEV_BSIZE and
163  * PAGE_SIZE are really too small. There must be something wrong
164  * with isa_dmastart/isa_dmarangecheck HELP!!!
165  */
166 #define MAX_BUFSIZE 0x3000
167 #define DEFAULT_BLEN 59
168
169 /***********************************************************************
170  *
171  * THE PER-DRIVER RECORD FOR ISA.C
172  *
173  ***********************************************************************/
174
175 static  int gscprobe (struct isa_device *isdp);
176 static  int gscattach(struct isa_device *isdp);
177
178 struct isa_driver gscdriver = { gscprobe, gscattach, "gsc" };
179
180 static  d_open_t        gscopen;
181 static  d_close_t       gscclose;
182 static  d_read_t        gscread;
183 static  d_ioctl_t       gscioctl;
184
185 #define CDEV_MAJOR 47
186 static struct dev_ops gsc_ops = {
187         { "gsc", CDEV_MAJOR, 0 },
188         .d_open =       gscopen,
189         .d_close =      gscclose,
190         .d_read =       gscread,
191         .d_ioctl =      gscioctl,
192 };
193
194
195 /***********************************************************************
196  *
197  * LOCALLY USED SUBROUTINES
198  *
199  ***********************************************************************/
200
201 /***********************************************************************
202  *
203  * lookup_geometry -- lookup a record in the geometry table by pattern
204  *
205  * The caller supplies a geometry record pattern, where INVALID
206  * matches anything. Returns the index in the table or INVALID if
207  * lookup fails.
208  */
209
210 static int
211 lookup_geometry(struct gsc_geom geom, const struct gsc_unit *scu)
212 {
213   struct gsc_geom tab;
214   int i;
215
216   for(i=0; i<GEOMTAB_SIZE; i++)
217     {
218       tab = geomtab[i];
219
220       if ( ( ( geom.dpi   != INVALID ) && ( tab.dpi   == geom.dpi   ) ) ||
221            ( ( geom.dpl   != INVALID ) && ( tab.dpl   == geom.dpl   ) ) ||
222            ( ( geom.g_res != INVALID ) && ( tab.g_res == geom.g_res ) ) ||
223            ( ( geom.s_res != INVALID ) && ( tab.s_res == geom.s_res ) ) )
224         {
225           lprintf(("gsc.lookup_geometry: "
226                  "geometry lookup found: %ddpi, %ddpl\n",
227                  tab.dpi, tab.dpl));
228           return i;
229         }
230     }
231
232   lprintf(("gsc.lookup_geometry: "
233          "geometry lookup failed on {%d, %d, 0x%02x, 0x%02x}\n",
234          geom.dpi, geom.dpl, geom.g_res, geom.s_res));
235
236   return INVALID;
237 }
238
239 /***********************************************************************
240  *
241  * get_geometry -- read geometry from status port
242  *
243  * Returns the index into geometry table or INVALID if it fails to
244  * either read the status byte or lookup the record.
245  */
246
247 static int
248 get_geometry(const struct gsc_unit *scu)
249 {
250   struct gsc_geom geom = NEW_GEOM;
251
252   lprintf(("gsc.get_geometry: get geometry at 0x%03x\n", scu->stat));
253
254   if ( ( geom.g_res = inb(scu->stat) ) == FAIL )
255     return INVALID;
256
257   geom.g_res &= GSC_RES_MASK;
258
259   return lookup_geometry(geom, scu);
260 }
261
262 /***********************************************************************
263  *
264  * buffer_allocate -- allocate/reallocate a buffer
265  * Now just checks that the preallocated buffer is large enough.
266  */
267
268 static int
269 buffer_allocate(struct gsc_unit *scu)
270 {
271   size_t size;
272
273   size = scu->blen * geomtab[scu->geometry].dpl / 8;
274
275   lprintf(("gsc.buffer_allocate: need 0x%x bytes\n", size));
276
277   if ( size > MAX_BUFSIZE )
278     {
279       lprintf(("gsc.buffer_allocate: 0x%x bytes are too much\n", size));
280       return ENOMEM;
281     }
282
283   scu->sbuf.size = size;
284   scu->sbuf.poi  = size;
285
286   lprintf(("gsc.buffer_allocate: ok\n"));
287
288   return SUCCESS;
289 }
290
291 /***********************************************************************
292  *
293  * buffer_read -- scan a buffer
294  */
295
296 static int
297 buffer_read(struct gsc_unit *scu)
298 {
299   int stb;
300   int res = SUCCESS;
301   int chan_bit;
302   char *p;
303   int delay;
304
305   lprintf(("gsc.buffer_read: begin\n"));
306
307   if (scu->ctrl_byte == INVALID)
308     {
309       lprintf(("gsc.buffer_read: invalid ctrl_byte\n"));
310       return EIO;
311     }
312
313   crit_enter();
314
315   outb( scu->ctrl, scu->ctrl_byte | GSC_POWER_ON );
316   outb( scu->clrp, 0 );
317   stb = inb( scu->stat );
318
319   isa_dmastart(BUF_CMD_READ, 0, scu->sbuf.base, scu->sbuf.size, scu->channel);
320
321   chan_bit = 0x01 << scu->channel;
322
323   for(delay=0; !(inb(DMA1_READY) & 0x01 << scu->channel); delay += LONG)
324     {
325       if(delay >= scu->btime)
326         {
327           crit_exit();
328           lprintf(("gsc.buffer_read: timeout\n"));
329           res = EWOULDBLOCK;
330           break;
331         }
332       res = tsleep((caddr_t)scu, PCATCH, "gscread", LONG);
333       if ( ( res == 0 ) || ( res == EWOULDBLOCK ) )
334         res = SUCCESS;
335       else
336         break;
337     }
338   crit_exit();
339   isa_dmadone(BUF_CMD_READ, 0, scu->sbuf.base, scu->sbuf.size, scu->channel);
340   outb( scu->clrp, 0 );
341
342   if(res != SUCCESS)
343     {
344       lprintf(("gsc.buffer_read: aborted with %d\n", res));
345       return res;
346     }
347
348   lprintf(("gsc.buffer_read: invert buffer\n"));
349   for(p = scu->sbuf.base + scu->sbuf.size - 1; p >= scu->sbuf.base; p--)
350     *p = ~*p;
351
352   scu->sbuf.poi = 0;
353   lprintf(("gsc.buffer_read: ok\n"));
354   return SUCCESS;
355 }
356
357 /***********************************************************************
358  *
359  * the main functions
360  *
361  ***********************************************************************/
362
363 /***********************************************************************
364  *
365  * gscprobe
366  *
367  * read status port and check for proper configuration:
368  *  - if address group matches (status byte has reasonable value)
369  *  - if DMA channel matches   (status byte has correct value)
370  */
371
372 static int
373 gscprobe (struct isa_device *isdp)
374 {
375   int unit = isdp->id_unit;
376   struct gsc_unit *scu = unittab + unit;
377   int stb;
378   struct gsc_geom geom = NEW_GEOM;
379
380   scu->flags = FLAG_DEBUG;
381
382   lprintf(("gsc%d.probe "
383          "on iobase 0x%03x, irq %d, drq %d, addr %p, size %d\n",
384          unit,
385          isdp->id_iobase,
386          isdp->id_irq,
387          isdp->id_drq,
388          isdp->id_maddr,
389          isdp->id_msize));
390
391   if ( isdp->id_iobase < 0 )
392     {
393       lprintf(("gsc%d.probe: no iobase given\n", unit));
394       return PROBE_FAIL;
395     }
396
397   stb = inb( GSC_STAT(isdp->id_iobase) );
398   if (stb == FAIL)
399     {
400       lprintf(("gsc%d.probe: get status byte failed\n", unit));
401       return PROBE_FAIL;
402     }
403
404   scu->data = GSC_DATA(isdp->id_iobase);
405   scu->stat = GSC_STAT(isdp->id_iobase);
406   scu->ctrl = GSC_CTRL(isdp->id_iobase);
407   scu->clrp = GSC_CLRP(isdp->id_iobase);
408
409   outb(scu->clrp,stb);
410   stb = inb(scu->stat);
411
412   switch(stb & GSC_CNF_MASK) {
413   case GSC_CNF_DMA1:
414     lprintf(("gsc%d.probe: DMA 1\n", unit));
415     scu->channel = 1;
416     break;
417
418   case GSC_CNF_DMA3:
419     lprintf(("gsc%d.probe: DMA 3\n", unit));
420     scu->channel = 3;
421     break;
422
423   case GSC_CNF_IRQ3:
424     lprintf(("gsc%d.probe: IRQ 3\n", unit));
425     goto probe_noirq;
426   case GSC_CNF_IRQ5:
427     lprintf(("gsc%d.probe: IRQ 5\n", unit));
428   probe_noirq:
429     lprintf(("gsc%d.probe: sorry, can't use IRQ yet\n", unit));
430     return PROBE_FAIL;
431   default:
432     lprintf(("gsc%d.probe: invalid status byte 0x%02x\n", unit, (u_char) stb));
433     return PROBE_FAIL;
434   }
435
436   if (isdp->id_drq < 0)
437     isdp->id_drq = scu->channel;
438   if (scu->channel != isdp->id_drq)
439     {
440       lprintf(("gsc%d.probe: drq mismatch: config: %d; hardware: %d\n",
441               unit, isdp->id_drq, scu->channel));
442       return PROBE_FAIL;
443     }
444
445   geom.g_res = stb & GSC_RES_MASK;
446   scu->geometry = lookup_geometry(geom, scu);
447   if (scu->geometry == INVALID)
448     {
449       lprintf(("gsc%d.probe: geometry lookup failed\n", unit));
450       return PROBE_FAIL;
451     }
452   else
453     {
454       scu->ctrl_byte = geomtab[scu->geometry].s_res;
455       outb(scu->ctrl, scu->ctrl_byte | GSC_POWER_ON);
456
457       lprintf(("gsc%d.probe: status 0x%02x, %ddpi\n",
458              unit, stb, geomtab[scu->geometry].dpi));
459
460       outb(scu->ctrl, scu->ctrl_byte & ~GSC_POWER_ON);
461     }
462
463   lprintf(("gsc%d.probe: ok\n", unit));
464
465   scu->flags &= ~FLAG_DEBUG;
466
467   return PROBE_SUCCESS;
468 }
469
470 /***********************************************************************
471  *
472  * gscattach
473  *
474  * finish initialization of unit structure
475  * get geometry value
476  */
477
478 static int
479 gscattach(struct isa_device *isdp)
480 {
481   int unit = isdp->id_unit;
482   struct gsc_unit *scu = unittab + unit;
483
484   scu->flags |= FLAG_DEBUG;
485
486   lprintf(("gsc%d.attach: "
487          "iobase 0x%03x, irq %d, drq %d, addr %p, size %d\n",
488          unit,
489          isdp->id_iobase,
490          isdp->id_irq,
491          isdp->id_drq,
492          isdp->id_maddr,
493          isdp->id_msize));
494
495   printf("gsc%d: GeniScan GS-4500 at %ddpi\n",
496          unit, geomtab[scu->geometry].dpi);
497
498   /*
499    * Initialize buffer structure.
500    * XXX this must be done early to give a good chance of getting a
501    * contiguous buffer.  This wastes memory.
502    */
503   scu->sbuf.base = contigmalloc((unsigned long)MAX_BUFSIZE, M_DEVBUF, M_NOWAIT,
504                                 0ul, 0xfffffful, 1ul, 0x10000ul);
505   if ( scu->sbuf.base == NULL )
506     {
507       lprintf(("gsc%d.attach: buffer allocation failed\n", unit));
508       return ATTACH_FAIL;       /* XXX attach must not fail */
509     }
510   scu->sbuf.size = INVALID;
511   scu->sbuf.poi  = INVALID;
512
513   scu->blen = DEFAULT_BLEN;
514   scu->btime = TIMEOUT;
515
516   scu->flags |= ATTACHED;
517   lprintf(("gsc%d.attach: ok\n", unit));
518   scu->flags &= ~FLAG_DEBUG;
519 #define GSC_UID 0
520 #define GSC_GID 13
521   dev_ops_add(&gsc_ops, 0xc0, unit << 6);
522   make_dev(&gsc_ops, unit<<6, GSC_UID, GSC_GID, 0666, "gsc%d", unit);
523   make_dev(&gsc_ops, ((unit<<6) + FRMT_PBM),
524      GSC_UID,  GSC_GID, 0666, "gsc%dp", unit);
525   make_dev(&gsc_ops, ((unit<<6) + DBUG_MASK),
526      GSC_UID,  GSC_GID, 0666, "gsc%dd", unit);
527   make_dev(&gsc_ops, ((unit<<6) + DBUG_MASK+FRMT_PBM),
528      GSC_UID,  GSC_GID, 0666, "gsc%dpd", unit);
529
530   return ATTACH_SUCCESS;
531 }
532
533 /***********************************************************************
534  *
535  * gscopen
536  *
537  * set open flag
538  * set modes according to minor number
539  * don't switch scanner on, wait until first read ioctls go before
540  */
541
542 static  int
543 gscopen  (struct dev_open_args *ap)
544 {
545   cdev_t dev = ap->a_head.a_dev;
546   struct gsc_unit *scu;
547   int unit;
548
549   unit = UNIT(minor(dev)) & UNIT_MASK;
550   if ( unit >= NGSC )
551     {
552 #ifdef GSCDEBUG
553       /* XXX lprintf isn't valid here since there is no scu. */
554       printf("gsc%d.open: unconfigured unit number (max %d)\n", unit, NGSC);
555 #endif
556       return ENXIO;
557     }
558   scu = unittab + unit;
559   if ( !( scu->flags & ATTACHED ) )
560     {
561       lprintf(("gsc%d.open: unit was not attached successfully 0x%04x\n",
562              unit, scu->flags));
563       return ENXIO;
564     }
565
566   if ( minor(dev) & DBUG_MASK )
567     scu->flags |= FLAG_DEBUG;
568   else
569     scu->flags &= ~FLAG_DEBUG;
570
571   switch(minor(dev) & FRMT_MASK) {
572   case FRMT_PBM:
573     scu->flags |= PBM_MODE;
574     lprintf(("gsc%d.open: pbm mode\n", unit));
575     break;
576   case FRMT_RAW:
577     lprintf(("gsc%d.open: raw mode\n", unit));
578     scu->flags &= ~PBM_MODE;
579     break;
580   default:
581     lprintf(("gsc%d.open: gray maps are not yet supported", unit));
582     return ENXIO;
583   }
584
585   lprintf(("gsc%d.open: minor %d\n",
586          unit, minor(dev)));
587
588   if ( scu->flags & OPEN )
589     {
590       lprintf(("gsc%d.open: already open", unit));
591       return EBUSY;
592     }
593
594   if (isa_dma_acquire(scu->channel))
595       return(EBUSY);
596
597   scu->flags |= OPEN;
598
599   return SUCCESS;
600 }
601
602 /***********************************************************************
603  *
604  * gscclose
605  *
606  * turn off scanner
607  * release the buffer
608  */
609
610 static  int
611 gscclose (struct dev_close_args *ap)
612 {
613   cdev_t dev = ap->a_head.a_dev;
614   int unit = UNIT(minor(dev));
615   struct gsc_unit *scu = unittab + unit;
616
617   lprintf(("gsc%d.close: minor %d\n",
618          unit, minor(dev)));
619
620   if ( unit >= NGSC || !( scu->flags & ATTACHED ) )
621     {
622       lprintf(("gsc%d.read: unit was not attached successfully 0x%04x\n",
623              unit, scu->flags));
624       return ENXIO;
625     }
626
627   outb(scu->ctrl, scu->ctrl_byte & ~GSC_POWER_ON);
628
629   scu->sbuf.size = INVALID;
630   scu->sbuf.poi  = INVALID;
631
632   isa_dma_release(scu->channel);
633
634   scu->flags &= ~(FLAG_DEBUG | OPEN | READING);
635
636   return SUCCESS;
637 }
638
639 /***********************************************************************
640  *
641  * gscread
642  */
643
644 static  int
645 gscread  (struct dev_read_args *ap)
646 {
647   cdev_t dev = ap->a_head.a_dev;
648   struct uio *uio = ap->a_uio;
649   int unit = UNIT(minor(dev));
650   struct gsc_unit *scu = unittab + unit;
651   size_t nbytes;
652   int res;
653
654   lprintf(("gsc%d.read: minor %d\n", unit, minor(dev)));
655
656   if ( unit >= NGSC || !( scu->flags & ATTACHED ) )
657     {
658       lprintf(("gsc%d.read: unit was not attached successfully 0x%04x\n",
659              unit, scu->flags));
660       return ENXIO;
661     }
662
663   if ( !(scu->flags & READING) )
664     {
665       res = buffer_allocate(scu);
666       if ( res == SUCCESS )
667         scu->flags |= READING;
668       else
669         return res;
670
671       scu->ctrl_byte = geomtab[scu->geometry].s_res;
672
673       /* initialize for pbm mode */
674       if ( scu->flags & PBM_MODE )
675         {
676           char *p;
677           int width = geomtab[scu->geometry].dpl;
678
679           sprintf(scu->sbuf.base,"P4 %d %d\n", width, scu->height);
680           scu->bcount = scu->height * width / 8;
681
682           lprintf(("gsc%d.read: initializing pbm mode: `%s', bcount: 0x%x\n",
683                   unit, scu->sbuf.base, scu->bcount));
684
685           /* move header to end of sbuf */
686           for(p=scu->sbuf.base; *p; p++);
687           while(--p >= scu->sbuf.base)
688             {
689               *(char *)(scu->sbuf.base + --scu->sbuf.poi) = *p;
690               scu->bcount++;
691             }
692         }
693     }
694
695   lprintf(("gsc%d.read(before buffer_read): "
696           "size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
697           unit, scu->sbuf.size, scu->sbuf.poi, scu->bcount));
698
699   if ( scu->sbuf.poi == scu->sbuf.size )
700     if ( (res = buffer_read(scu)) != SUCCESS )
701       return res;
702
703   lprintf(("gsc%d.read(after buffer_read): "
704           "size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
705           unit, scu->sbuf.size, scu->sbuf.poi, scu->bcount));
706
707   nbytes = MIN( uio->uio_resid, scu->sbuf.size - scu->sbuf.poi );
708
709   if ( (scu->flags & PBM_MODE) )
710     nbytes = MIN( nbytes, scu->bcount );
711
712   lprintf(("gsc%d.read: transferring 0x%x bytes", unit, nbytes));
713
714   res = uiomove(scu->sbuf.base + scu->sbuf.poi, nbytes, uio);
715   if ( res != SUCCESS )
716     {
717       lprintf(("gsc%d.read: uiomove failed %d", unit, res));
718       return res;
719     }
720
721   scu->sbuf.poi += nbytes;
722   if ( scu->flags & PBM_MODE ) scu->bcount -= nbytes;
723
724   lprintf(("gsc%d.read: size 0x%x, pointer 0x%x, bcount 0x%x, ok\n",
725           unit, scu->sbuf.size, scu->sbuf.poi, scu->bcount));
726
727   return SUCCESS;
728 }
729
730 /***********************************************************************
731  *
732  * gscioctl
733  *
734  */
735
736 static  int
737 gscioctl (struct dev_ioctl_args *ap)
738 {
739   cdev_t dev = ap->a_head.a_dev;
740   caddr_t data = ap->a_data;
741   int unit = UNIT(minor(dev));
742   struct gsc_unit *scu = unittab + unit;
743
744   lprintf(("gsc%d.ioctl: minor %d\n",
745          unit, minor(dev)));
746
747   if ( unit >= NGSC || !( scu->flags & ATTACHED ) )
748     {
749       lprintf(("gsc%d.ioctl: unit was not attached successfully 0x%04x\n",
750              unit, scu->flags));
751       return ENXIO;
752     }
753
754   switch(ap->a_cmd) {
755   case GSC_SRESSW:
756     lprintf(("gsc%d.ioctl:GSC_SRESSW\n", unit));
757     if ( scu->flags & READING )
758       {
759         lprintf(("gsc%d:ioctl on already reading unit\n", unit));
760         return EBUSY;
761       }
762     scu->geometry = get_geometry(scu);
763     return SUCCESS;
764   case GSC_GRES:
765     *(int *)data=geomtab[scu->geometry].dpi;
766     lprintf(("gsc%d.ioctl:GSC_GRES %ddpi\n", unit, *(int *)data));
767     return SUCCESS;
768   case GSC_GWIDTH:
769     *(int *)data=geomtab[scu->geometry].dpl;
770     lprintf(("gsc%d.ioctl:GSC_GWIDTH %d\n", unit, *(int *)data));
771     return SUCCESS;
772   case GSC_SRES:
773   case GSC_SWIDTH:
774     lprintf(("gsc%d.ioctl:GSC_SRES or GSC_SWIDTH %d\n",
775            unit, *(int *)data));
776     { int g;
777       struct gsc_geom geom = NEW_GEOM;
778       if ( ap->a_cmd == GSC_SRES )
779         geom.dpi = *(int *)data;
780       else
781         geom.dpl = *(int *)data;
782       if ( ( g = lookup_geometry(geom, scu) ) == INVALID )
783         return EINVAL;
784       scu->geometry = g;
785       return SUCCESS;
786     }
787   case GSC_GHEIGHT:
788     *(int *)data=scu->height;
789     lprintf(("gsc%d.ioctl:GSC_GHEIGHT %d\n", unit, *(int *)data));
790     return SUCCESS;
791   case GSC_SHEIGHT:
792     lprintf(("gsc%d.ioctl:GSC_SHEIGHT %d\n", unit, *(int *)data));
793     if ( scu->flags & READING )
794       {
795         lprintf(("gsc%d:ioctl on already reading unit\n", unit));
796         return EBUSY;
797       }
798     scu->height=*(int *)data;
799     return SUCCESS;
800   case GSC_GBLEN:
801     *(int *)data=scu->blen;
802     lprintf(("gsc%d.ioctl:GSC_GBLEN %d\n", unit, *(int *)data));
803     return SUCCESS;
804   case GSC_SBLEN:
805     lprintf(("gsc%d.ioctl:GSC_SBLEN %d\n", unit, *(int *)data));
806     if (*(int *)data * geomtab[scu->geometry].dpl / 8 > MAX_BUFSIZE)
807       {
808         lprintf(("gsc%d:ioctl buffer size too high\n", unit));
809         return ENOMEM;
810       }
811     scu->blen=*(int *)data;
812     return SUCCESS;
813   case GSC_GBTIME:
814     *(int *)data = scu->btime / hz;
815     lprintf(("gsc%d.ioctl:GSC_GBTIME %d\n", unit, *(int *)data));
816     return SUCCESS;
817   case GSC_SBTIME:
818     scu->btime = *(int *)data * hz;
819     lprintf(("gsc%d.ioctl:GSC_SBTIME %d\n", unit, *(int *)data));
820     return SUCCESS;
821   default: return ENOTTY;
822   }
823 }