]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/pc98/cbus/olpt.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / pc98 / cbus / olpt.c
1 /*-
2  * Copyright (c) 1990 William F. Jolitz, TeleMuse
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This software is a component of "386BSD" developed by
16  *      William F. Jolitz, TeleMuse.
17  * 4. Neither the name of the developer nor the name "386BSD"
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
22  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
23  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
24  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
25  * NOT MAKE USE OF THIS WORK.
26  *
27  * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
28  * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
29  * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
30  * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
31  * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
32  * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
33  * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
34  * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
37  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  *
48  *      from: unknown origin, 386BSD 0.1
49  * $FreeBSD$
50  */
51
52 /*
53  * Device Driver for AT parallel printer port
54  * Written by William Jolitz 12/18/90
55  */
56
57 /*
58  * Parallel port TCP/IP interfaces added.  I looked at the driver from
59  * MACH but this is a complete rewrite, and btw. incompatible, and it
60  * should perform better too.  I have never run the MACH driver though.
61  *
62  * This driver sends two bytes (0x08, 0x00) in front of each packet,
63  * to allow us to distinguish another format later.
64  *
65  * Now added a Linux/Crynwr compatibility mode which is enabled using
66  * IF_LINK0 - Tim Wilkinson.
67  *
68  * TODO:
69  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
70  *
71  * Connect the two computers using a Laplink parallel cable to use this
72  * feature:
73  *
74  *      +----------------------------------------+
75  *      |A-name A-End   B-End   Descr.  Port/Bit |
76  *      +----------------------------------------+
77  *      |DATA0  2       15      Data    0/0x01   |
78  *      |-ERROR 15      2               1/0x08   |
79  *      +----------------------------------------+
80  *      |DATA1  3       13      Data    0/0x02   |
81  *      |+SLCT  13      3               1/0x10   |
82  *      +----------------------------------------+
83  *      |DATA2  4       12      Data    0/0x04   |
84  *      |+PE    12      4               1/0x20   |
85  *      +----------------------------------------+
86  *      |DATA3  5       10      Strobe  0/0x08   |
87  *      |-ACK   10      5               1/0x40   |
88  *      +----------------------------------------+
89  *      |DATA4  6       11      Data    0/0x10   |
90  *      |BUSY   11      6               1/~0x80  |
91  *      +----------------------------------------+
92  *      |GND    18-25   18-25   GND     -        |
93  *      +----------------------------------------+
94  *
95  * Expect transfer-rates up to 75 kbyte/sec.
96  *
97  * If GCC could correctly grok
98  *      register int port asm("edx")
99  * the code would be cleaner
100  *
101  * Poul-Henning Kamp <phk@freebsd.org>
102  */
103
104 #include <sys/param.h>
105 #include <sys/systm.h>
106 #include <sys/conf.h>
107 #include <sys/bus.h>
108 #include <sys/kernel.h>
109 #include <sys/module.h>
110 #include <sys/uio.h>
111 #include <sys/syslog.h>
112 #include <sys/malloc.h>
113
114 #include <machine/bus.h>
115 #include <machine/resource.h>
116 #include <sys/rman.h>
117
118 #include <isa/isavar.h>
119
120 #include <pc98/cbus/olptreg.h>
121 #include <dev/ppbus/lptio.h>
122
123 #define LPINITRDY       4       /* wait up to 4 seconds for a ready */
124 #define LPTOUTINITIAL   10      /* initial timeout to wait for ready 1/10 s */
125 #define LPTOUTMAX       1       /* maximal timeout 1 s */
126 #define LPPRI           (PZERO+8)
127 #define BUFSIZE         1024
128
129 #ifndef DEBUG
130 #define lprintf(args)
131 #else
132 #define lprintf(args)   do {                            \
133                                 if (lptflag)            \
134                                         printf args;    \
135                         } while (0)
136 static int volatile lptflag = 1;
137 #endif
138
139 struct lpt_softc {
140         struct resource *res_port;
141         struct resource *res_irq;
142         void *sc_ih;
143
144         int     sc_port;
145         short   sc_state;
146         /* default case: negative prime, negative ack, handshake strobe,
147            prime once */
148         u_char  sc_control;
149         char    sc_flags;
150 #define LP_POS_INIT     0x04    /* if we are a postive init signal */
151 #define LP_POS_ACK      0x08    /* if we are a positive going ack */
152 #define LP_NO_PRIME     0x10    /* don't prime the printer at all */
153 #define LP_PRIMEOPEN    0x20    /* prime on every open */
154 #define LP_AUTOLF       0x40    /* tell printer to do an automatic lf */
155 #define LP_BYPASS       0x80    /* bypass  printer ready checks */
156         void    *sc_inbuf;
157         short   sc_xfercnt ;
158         char    sc_primed;
159         char    *sc_cp ;
160         u_char  sc_irq ;        /* IRQ status of port */
161 #define LP_HAS_IRQ      0x01    /* we have an irq available */
162 #define LP_USE_IRQ      0x02    /* we are using our irq */
163 #define LP_ENABLE_IRQ   0x04    /* enable IRQ on open */
164         u_char  sc_backoff ;    /* time to call lptout() again */
165 };
166
167 /* bits for state */
168 #define OPEN            (1<<0)  /* device is open */
169 #define ASLP            (1<<1)  /* awaiting draining of printer */
170 #define ERROR           (1<<2)  /* error was received from printer */
171 #define OBUSY           (1<<3)  /* printer is busy doing output */
172 #define LPTOUT          (1<<4)  /* timeout while not selected */
173 #define TOUT            (1<<5)  /* timeout while not selected */
174 #define INIT            (1<<6)  /* waiting to initialize for open */
175 #define INTERRUPTED     (1<<7)  /* write call was interrupted */
176
177
178 /* status masks to interrogate printer status */
179 #define RDY_MASK        (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)     /* ready ? */
180 #define LP_READY        (LPS_SEL|LPS_NBSY|LPS_NERR)
181
182 /* Printer Ready condition  - from lpa.c */
183 /* Only used in polling code */
184 #define NOT_READY(x)    ((inb(x) & LPS_NBSY) != LPS_NBSY)
185
186 #define MAX_SLEEP       (hz*5)  /* Timeout while waiting for device ready */
187 #define MAX_SPIN        20      /* Max delay for device ready in usecs */
188
189 static timeout_t lptout;
190 static int lpt_probe(device_t);
191 static int lpt_attach(device_t);
192 static void lpt_intr(void *);
193
194 static devclass_t olpt_devclass;
195
196 static device_method_t olpt_methods[] = {
197         DEVMETHOD(device_probe,         lpt_probe),
198         DEVMETHOD(device_attach,        lpt_attach),
199         { 0, 0 }
200 };
201
202 static driver_t olpt_driver = {
203         "olpt",
204         olpt_methods,
205         sizeof (struct lpt_softc),
206 };
207
208 DRIVER_MODULE(olpt, isa, olpt_driver, olpt_devclass, 0, 0);
209
210 static  d_open_t        lptopen;
211 static  d_close_t       lptclose;
212 static  d_write_t       lptwrite;
213 static  d_ioctl_t       lptioctl;
214
215 static struct cdevsw lpt_cdevsw = {
216         .d_version =    D_VERSION,
217         .d_flags =      D_NEEDGIANT,
218         .d_open =       lptopen,
219         .d_close =      lptclose,
220         .d_write =      lptwrite,
221         .d_ioctl =      lptioctl,
222         .d_name =       "lpt",
223 };
224
225 static bus_addr_t lpt_iat[] = {0, 2, 4, 6};
226
227 /*
228  * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
229  * Based partially on Rod Grimes' printer probe
230  *
231  * Logic:
232  *      1) If no port address was given, use the bios detected ports
233  *         and autodetect what ports the printers are on.
234  *      2) Otherwise, probe the data port at the address given,
235  *         using the method in Rod Grimes' port probe.
236  *         (Much code ripped off directly from Rod's probe.)
237  *
238  * Comments from Rod's probe:
239  * Logic:
240  *      1) You should be able to write to and read back the same value
241  *         to the data port.  Do an alternating zeros, alternating ones,
242  *         walking zero, and walking one test to check for stuck bits.
243  *
244  *      2) You should be able to write to and read back the same value
245  *         to the control port lower 5 bits, the upper 3 bits are reserved
246  *         per the IBM PC technical reference manauls and different boards
247  *         do different things with them.  Do an alternating zeros, alternating
248  *         ones, walking zero, and walking one test to check for stuck bits.
249  *
250  *         Some printers drag the strobe line down when the are powered off
251  *         so this bit has been masked out of the control port test.
252  *
253  *         XXX Some printers may not like a fast pulse on init or strobe, I
254  *         don't know at this point, if that becomes a problem these bits
255  *         should be turned off in the mask byte for the control port test.
256  *
257  *         We are finally left with a mask of 0x14, due to some printers
258  *         being adamant about holding other bits high ........
259  *
260  *         Before probing the control port, we write a 0 to the data port -
261  *         If not, some printers chuck out garbage when the strobe line
262  *         gets toggled.
263  *
264  *      3) Set the data and control ports to a value of 0
265  *
266  *      This probe routine has been tested on Epson Lx-800, HP LJ3P,
267  *      Epson FX-1170 and C.Itoh 8510RM
268  *      printers.
269  *      Quick exit on fail added.
270  */
271
272 int
273 lpt_probe(device_t dev)
274 {
275 #define PC98_OLD_LPT 0x40
276 #define PC98_IEEE_1284_FUNCTION 0x149
277         int rid;
278         struct resource *res;
279
280         /* Check isapnp ids */
281         if (isa_get_vendorid(dev))
282                 return ENXIO;
283
284         rid = 0;
285         res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, lpt_iat, 4,
286                                   RF_ACTIVE);
287         if (res == NULL)
288                 return ENXIO;
289         isa_load_resourcev(res, lpt_iat, 4);
290
291         if (isa_get_port(dev) == PC98_OLD_LPT) {
292                 unsigned int pc98_ieee_mode, tmp;
293
294                 tmp = inb(PC98_IEEE_1284_FUNCTION);
295                 pc98_ieee_mode = tmp;
296                 if ((tmp & 0x10) == 0x10) {
297                         outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10);
298                         tmp = inb(PC98_IEEE_1284_FUNCTION);
299                         if ((tmp & 0x10) != 0x10) {
300                                 outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode);
301                                 bus_release_resource(dev, SYS_RES_IOPORT, rid,
302                                                      res);
303                                 return ENXIO;
304                         }
305                 }
306         }
307
308         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
309         return 0;
310 }
311
312 /* XXX Todo - try and detect if interrupt is working */
313 int
314 lpt_attach(device_t dev)
315 {
316         int     rid, unit;
317         struct  lpt_softc       *sc;
318         struct  cdev            *cdev;
319
320         unit = device_get_unit(dev);
321         sc = device_get_softc(dev);
322
323         rid = 0;
324         sc->res_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
325                                            lpt_iat, 4, RF_ACTIVE);
326         if (sc->res_port == NULL)
327                 return ENXIO;
328         isa_load_resourcev(sc->res_port, lpt_iat, 4);
329
330         sc->sc_port = rman_get_start(sc->res_port);
331         sc->sc_primed = 0;      /* not primed yet */
332
333         outb(sc->sc_port+lpt_pstb_ctrl, LPC_DIS_PSTB);  /* PSTB disable */
334         outb(sc->sc_port+lpt_control,   LPC_MODE8255);  /* 8255 mode set */
335         outb(sc->sc_port+lpt_control,   LPC_NIRQ8);     /* IRQ8 inactive */
336         outb(sc->sc_port+lpt_control,   LPC_NPSTB);     /* PSTB inactive */
337         outb(sc->sc_port+lpt_pstb_ctrl, LPC_EN_PSTB);   /* PSTB enable */
338
339         sc->sc_irq = 0;
340         if (isa_get_irq(dev) != -1) {
341                 rid = 0;
342                 sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
343                                                      RF_ACTIVE);
344                 if (sc->res_irq == NULL) {
345                         bus_release_resource(dev, SYS_RES_IOPORT, 0,
346                                              sc->res_port);
347                         return ENXIO;
348                 }
349                 if (bus_setup_intr(dev, sc->res_irq, INTR_TYPE_TTY, NULL, lpt_intr,
350                                    sc, &sc->sc_ih)) {
351                         bus_release_resource(dev, SYS_RES_IOPORT, 0,
352                                              sc->res_port);
353                         bus_release_resource(dev, SYS_RES_IRQ, 0,
354                                              sc->res_irq);
355                         return ENXIO;
356                 }
357                 sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
358                 device_printf(dev, "Interrupt-driven port");
359         }
360
361         cdev = make_dev(&lpt_cdevsw, 0,
362                         UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit);
363         cdev->si_drv1 = sc;
364         cdev = make_dev(&lpt_cdevsw, LP_BYPASS,
365                         UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
366         cdev->si_drv1 = sc;
367
368         return 0;
369 }
370
371 /*
372  * lptopen -- reset the printer, then wait until it's selected and not busy.
373  *      If LP_BYPASS flag is selected, then we do not try to select the
374  *      printer -- this is just used for passing ioctls.
375  */
376
377 static  int
378 lptopen (struct cdev *dev, int flags, int fmt, struct thread *td)
379 {
380         struct lpt_softc *sc = dev->si_drv1;
381         int s;
382         int port;
383
384         if (sc->sc_port == 0)
385                 return (ENXIO);
386
387         if (sc->sc_state) {
388                 lprintf(("lp: still open %x\n", sc->sc_state));
389                 return(EBUSY);
390         } else
391                 sc->sc_state |= INIT;
392
393         sc->sc_flags = dev2unit(dev);
394
395         /* Check for open with BYPASS flag set. */
396         if (sc->sc_flags & LP_BYPASS) {
397                 sc->sc_state = OPEN;
398                 return(0);
399         }
400
401         s = spltty();
402         lprintf(("lp flags 0x%x\n", sc->sc_flags));
403         port = sc->sc_port;
404
405         /* set IRQ status according to ENABLE_IRQ flag */
406         if (sc->sc_irq & LP_ENABLE_IRQ)
407                 sc->sc_irq |= LP_USE_IRQ;
408         else
409                 sc->sc_irq &= ~LP_USE_IRQ;
410
411         /* init printer */
412         sc->sc_state = OPEN;
413         sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
414         sc->sc_xfercnt = 0;
415         splx(s);
416
417         /* only use timeout if using interrupt */
418         lprintf(("irq %x\n", sc->sc_irq));
419         if (sc->sc_irq & LP_USE_IRQ) {
420                 sc->sc_state |= TOUT;
421                 timeout (lptout, (caddr_t)sc,
422                          (sc->sc_backoff = hz/LPTOUTINITIAL));
423         }
424
425         lprintf(("opened.\n"));
426         return(0);
427 }
428
429 static void
430 lptout (void *arg)
431 {
432         struct lpt_softc *sc = arg;
433         int pl;
434
435         lprintf(("T %x ", inb(sc->sc_port+lpt_status)));
436         if (sc->sc_state & OPEN) {
437                 sc->sc_backoff++;
438                 if (sc->sc_backoff > hz/LPTOUTMAX)
439                         sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
440                 timeout (lptout, (caddr_t)sc, sc->sc_backoff);
441         } else
442                 sc->sc_state &= ~TOUT;
443
444         if (sc->sc_state & ERROR)
445                 sc->sc_state &= ~ERROR;
446
447         /*
448          * Avoid possible hangs do to missed interrupts
449          */
450         if (sc->sc_xfercnt) {
451                 pl = spltty();
452                 lpt_intr(sc);
453                 splx(pl);
454         } else {
455                 sc->sc_state &= ~OBUSY;
456                 wakeup(sc);
457         }
458 }
459
460 /*
461  * lptclose -- close the device, free the local line buffer.
462  *
463  * Check for interrupted write call added.
464  */
465
466 static  int
467 lptclose(struct cdev *dev, int flags, int fmt, struct thread *td)
468 {
469         struct lpt_softc *sc = dev->si_drv1;
470
471         if(sc->sc_flags & LP_BYPASS)
472                 goto end_close;
473
474         sc->sc_state &= ~OPEN;
475         free(sc->sc_inbuf, M_DEVBUF);
476
477 end_close:
478         sc->sc_state = 0;
479         sc->sc_xfercnt = 0;
480         lprintf(("closed.\n"));
481         return(0);
482 }
483
484 /*
485  * pushbytes()
486  *      Workhorse for actually spinning and writing bytes to printer
487  *      Derived from lpa.c
488  *      Originally by ?
489  *
490  *      This code is only used when we are polling the port
491  */
492 static int
493 pushbytes(struct lpt_softc * sc)
494 {
495         int spin, err, tic;
496         char ch;
497         int port = sc->sc_port;
498
499         lprintf(("p"));
500         /* loop for every character .. */
501         while (sc->sc_xfercnt > 0) {
502                 /* printer data */
503                 ch = *(sc->sc_cp);
504                 sc->sc_cp++;
505                 sc->sc_xfercnt--;
506
507                 /*
508                  * Wait for printer ready.
509                  * Loop 20 usecs testing BUSY bit, then sleep
510                  * for exponentially increasing timeout. (vak)
511                  */
512                 for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
513                         DELAY(1);       /* XXX delay is NOT this accurate! */
514                 if (spin >= MAX_SPIN) {
515                         tic = 0;
516                         while (NOT_READY(port+lpt_status)) {
517                                 /*
518                                  * Now sleep, every cycle a
519                                  * little longer ..
520                                  */
521                                 tic = tic + tic + 1;
522                                 /*
523                                  * But no more than 10 seconds. (vak)
524                                  */
525                                 if (tic > MAX_SLEEP)
526                                         tic = MAX_SLEEP;
527                                 err = tsleep(sc, LPPRI,
528                                         "lptpoll", tic);
529                                 if (err != EWOULDBLOCK) {
530                                         return (err);
531                                 }
532                         }
533                 }
534
535                 /* output data */
536                 outb(port+lpt_data, ch);
537                 DELAY(1);
538                 outb(port+lpt_control, LPC_PSTB);
539                 DELAY(1);
540                 outb(port+lpt_control, LPC_NPSTB);
541         }
542         return(0);
543 }
544
545 /*
546  * lptwrite --copy a line from user space to a local buffer, then call
547  * putc to get the chars moved to the output queue.
548  *
549  * Flagging of interrupted write added.
550  */
551
552 static  int
553 lptwrite(struct cdev *dev, struct uio * uio, int ioflag)
554 {
555         register unsigned n;
556         int pl, err;
557         struct lpt_softc *sc = dev->si_drv1;
558
559         if(sc->sc_flags & LP_BYPASS) {
560                 /* we can't do writes in bypass mode */
561                 return(EPERM);
562         }
563
564         sc->sc_state &= ~INTERRUPTED;
565         while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
566                 sc->sc_cp = sc->sc_inbuf;
567                 uiomove(sc->sc_cp, n, uio);
568                 sc->sc_xfercnt = n ;
569                 while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
570                         lprintf(("i"));
571                         /* if the printer is ready for a char, */
572                         /* give it one */
573                         if ((sc->sc_state & OBUSY) == 0){
574                                 lprintf(("\nC %d. ", sc->sc_xfercnt));
575                                 pl = spltty();
576                                 lpt_intr(sc);
577                                 (void) splx(pl);
578                         }
579                         lprintf(("W "));
580                         if (sc->sc_state & OBUSY)
581                                 if ((err = tsleep (sc,
582                                          LPPRI|PCATCH, "lpwrite", 0))) {
583                                         sc->sc_state |= INTERRUPTED;
584                                         return(err);
585                                 }
586                 }
587                 /* check to see if we must do a polled write */
588                 if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
589                         lprintf(("p"));
590                         if((err = pushbytes(sc)))
591                                 return(err);
592                 }
593         }
594         return(0);
595 }
596
597 /*
598  * lptintr -- handle printer interrupts which occur when the printer is
599  * ready to accept another char.
600  *
601  * do checking for interrupted write call.
602  */
603
604 static void
605 lpt_intr(void *arg)
606 {
607 }
608
609 static  int
610 lptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
611 {
612         int     error = 0;
613         struct lpt_softc *sc = dev->si_drv1;
614         u_char  old_sc_irq;     /* old printer IRQ status */
615
616         switch (cmd) {
617         case LPT_IRQ :
618                 if(sc->sc_irq & LP_HAS_IRQ) {
619                         /*
620                          * NOTE:
621                          * If the IRQ status is changed,
622                          * this will only be visible on the
623                          * next open.
624                          *
625                          * If interrupt status changes,
626                          * this gets syslog'd.
627                          */
628                         old_sc_irq = sc->sc_irq;
629                         if(*(int*)data == 0)
630                                 sc->sc_irq &= (~LP_ENABLE_IRQ);
631                         else
632                                 sc->sc_irq |= LP_ENABLE_IRQ;
633                         if (old_sc_irq != sc->sc_irq )
634                                 log(LOG_NOTICE, "%s switched to %s mode\n",
635                                         devtoname(dev),
636                                         (sc->sc_irq & LP_ENABLE_IRQ)?
637                                         "interrupt-driven":"polled");
638                 } else /* polled port */
639                         error = EOPNOTSUPP;
640                 break;
641         default:
642                 error = ENODEV;
643         }
644
645         return(error);
646 }