lpt.c revision 1.21 1 /* $NetBSD: lpt.c,v 1.21 2008/02/22 23:11:35 dyoung Exp $ */
2
3 /*
4 * Copyright (c) 1990 William F. Jolitz, TeleMuse
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This software is a component of "386BSD" developed by
18 * William F. Jolitz, TeleMuse.
19 * 4. Neither the name of the developer nor the name "386BSD"
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
24 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
25 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
26 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
27 * NOT MAKE USE OF THIS WORK.
28 *
29 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
30 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
31 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
32 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
33 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
34 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
35 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
36 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 *
50 * from: unknown origin, 386BSD 0.1
51 * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
52 * From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp
53 * FreeBSD: src/sys/dev/ppbus/lpt.c,v 1.15.2.3 2000/07/07 00:30:40 obrien Exp
54 */
55
56 /*
57 * Device Driver for AT parallel printer port
58 * Written by William Jolitz 12/18/90
59 */
60
61 /*
62 * Updated for ppbus by Nicolas Souchu
63 * [Mon Jul 28 1997]
64 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: lpt.c,v 1.21 2008/02/22 23:11:35 dyoung Exp $");
68
69 #include "opt_ppbus_lpt.h"
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/conf.h>
74 #include <sys/kernel.h>
75 #include <sys/proc.h>
76 #include <sys/malloc.h>
77 #include <sys/file.h>
78 #include <sys/uio.h>
79 #include <sys/ioctl.h>
80 #include <sys/types.h>
81 #include <sys/syslog.h>
82
83 #include <sys/bus.h>
84
85 #include <dev/ppbus/ppbus_1284.h>
86 #include <dev/ppbus/ppbus_base.h>
87 #include <dev/ppbus/ppbus_io.h>
88 #include <dev/ppbus/ppbus_msq.h>
89 #include <dev/ppbus/ppbus_var.h>
90
91 #include <dev/ppbus/lptvar.h>
92 #include <dev/ppbus/lptreg.h>
93 #include <dev/ppbus/lptio.h>
94
95 /* Autoconf functions */
96 static int lpt_probe(device_t, struct cfdata *, void *);
97 static void lpt_attach(device_t, device_t, void *);
98 static int lpt_detach(device_t, int);
99
100 /* Autoconf structure */
101 CFATTACH_DECL(lpt_ppbus, sizeof(struct lpt_softc), lpt_probe, lpt_attach,
102 lpt_detach, NULL);
103
104 extern struct cfdriver lpt_cd;
105
106 dev_type_open(lptopen);
107 dev_type_close(lptclose);
108 dev_type_read(lptread);
109 dev_type_write(lptwrite);
110 dev_type_ioctl(lptioctl);
111
112 const struct cdevsw lpt_cdevsw = {
113 lptopen, lptclose, lptread, lptwrite, lptioctl,
114 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
115 };
116
117
118 /* Function prototypes */
119 static int lpt_detect(device_t);
120 static int lpt_request_ppbus(struct lpt_softc *, int);
121 static int lpt_release_ppbus(struct lpt_softc *, int);
122 static int lpt_logstatus(const device_t, const unsigned char);
123
124 /*
125 * lpt_probe()
126 */
127 static int
128 lpt_probe(device_t parent, struct cfdata * match, void *aux)
129 {
130 /* Test ppbus's capability */
131 return lpt_detect(parent);
132 }
133
134 static void
135 lpt_attach(device_t parent, device_t self, void *aux)
136 {
137 struct lpt_softc * sc = device_private(self);
138 struct ppbus_device_softc * ppbdev = &(sc->ppbus_dev);
139 struct ppbus_attach_args * args = aux;
140 char buf[64];
141 int error;
142
143 error = lpt_request_ppbus(sc, 0);
144 if(error) {
145 printf("%s(%s): error (%d) requesting bus(%s). Device not "
146 "properly attached.\n", __func__, self->dv_xname,
147 error, parent->dv_xname);
148 return;
149 }
150
151 /* Record capabilities */
152 ppbdev->capabilities = args->capabilities;
153
154 /* Allocate memory buffers */
155 if(ppbdev->capabilities & PPBUS_HAS_DMA) {
156 if(ppbus_dma_malloc(parent, &(sc->sc_inbuf),
157 &(sc->sc_in_baddr), BUFSIZE)) {
158
159 printf(" : cannot allocate input DMA buffer. Device "
160 "not properly attached!\n");
161 return;
162 }
163 if(ppbus_dma_malloc(parent, &(sc->sc_outbuf),
164 &(sc->sc_out_baddr), BUFSIZE)) {
165
166 ppbus_dma_free(parent, &(sc->sc_inbuf),
167 &(sc->sc_in_baddr), BUFSIZE);
168 printf(" : cannot allocate output DMA buffer. Device "
169 "not properly attached!\n");
170 return;
171 }
172 } else {
173 sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
174 sc->sc_outbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
175 }
176
177 /* Print out mode */
178 ppbdev->ctx.mode = ppbus_get_mode(parent);
179 bitmask_snprintf(ppbdev->ctx.mode, "\20\1COMPATIBLE\2NIBBLE"
180 "\3PS2\4EPP\5ECP\6FAST_CENTR", buf, sizeof(buf));
181 printf(": port mode = %s\n", buf);
182
183 /* Initialize the device on open by default */
184 sc->sc_flags = LPT_PRIME;
185
186 lpt_release_ppbus(sc, 0);
187 }
188
189 static int
190 lpt_detach(device_t self, int flags)
191 {
192 struct lpt_softc * lpt = device_private(self);
193 struct ppbus_device_softc * ppbdev = (struct ppbus_device_softc *) lpt;
194 int err;
195
196 if(lpt->sc_state & HAVEBUS) {
197 err = lpt_release_ppbus(lpt, 0);
198 if(err) {
199 printf("%s error (%d) while releasing bus",
200 self->dv_xname, err);
201 if(flags & DETACH_FORCE) {
202 printf(", continuing (DETACH_FORCE)!\n");
203 }
204 else {
205 printf(", terminating!\n");
206 return 0;
207 }
208 }
209 lpt->sc_state &= ~HAVEBUS;
210 }
211
212 ppbdev->ctx.valid = 0;
213
214 /* Free memory buffers */
215 if(ppbdev->capabilities & PPBUS_HAS_DMA) {
216 ppbus_dma_free(device_parent(self), &(lpt->sc_inbuf),
217 &(lpt->sc_in_baddr), BUFSIZE);
218 ppbus_dma_free(device_parent(self), &(lpt->sc_outbuf),
219 &(lpt->sc_out_baddr), BUFSIZE);
220 } else {
221 free(lpt->sc_inbuf, M_DEVBUF);
222 free(lpt->sc_outbuf, M_DEVBUF);
223 }
224
225 return 1;
226 }
227
228 /* Grab bus for lpt device */
229 static int
230 lpt_request_ppbus(struct lpt_softc * lpt, int how)
231 {
232 device_t dev = &lpt->sc_dev;
233 int error;
234
235 error = ppbus_request_bus(device_parent(dev), dev, how, (hz));
236 if (!(error)) {
237 lpt->sc_state |= HAVEBUS;
238 }
239 else {
240 LPT_DPRINTF(("%s(%s): error %d requesting bus.\n", __func__,
241 dev->dv_xname, error));
242 }
243
244 return error;
245 }
246
247 /* Release ppbus to enable other devices to use it. */
248 static int
249 lpt_release_ppbus(struct lpt_softc * lpt, int how)
250 {
251 device_t dev = &lpt->sc_dev;
252 int error;
253
254 if(lpt->sc_state & HAVEBUS) {
255 error = ppbus_release_bus(device_parent(dev), dev, how, (hz));
256 if(!(error))
257 lpt->sc_state &= ~HAVEBUS;
258 else
259 LPT_DPRINTF(("%s(%s): error releasing bus.\n", __func__,
260 dev->dv_xname));
261 }
262 else {
263 error = EINVAL;
264 LPT_DPRINTF(("%s(%s): device does not own bus.\n", __func__,
265 dev->dv_xname));
266 }
267
268 return error;
269 }
270
271
272 /*
273 * Probe simplified by replacing multiple loops with a hardcoded
274 * test pattern - 1999/02/08 des (at) freebsd.org
275 *
276 * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
277 * Based partially on Rod Grimes' printer probe
278 *
279 * Logic:
280 * 1) If no port address was given, use the bios detected ports
281 * and autodetect what ports the printers are on.
282 * 2) Otherwise, probe the data port at the address given,
283 * using the method in Rod Grimes' port probe.
284 * (Much code ripped off directly from Rod's probe.)
285 *
286 * Comments from Rod's probe:
287 * Logic:
288 * 1) You should be able to write to and read back the same value
289 * to the data port. Do an alternating zeros, alternating ones,
290 * walking zero, and walking one test to check for stuck bits.
291 *
292 * 2) You should be able to write to and read back the same value
293 * to the control port lower 5 bits, the upper 3 bits are reserved
294 * per the IBM PC technical reference manauls and different boards
295 * do different things with them. Do an alternating zeros, alternating
296 * ones, walking zero, and walking one test to check for stuck bits.
297 *
298 * Some printers drag the strobe line down when the are powered off
299 * so this bit has been masked out of the control port test.
300 *
301 * XXX Some printers may not like a fast pulse on init or strobe, I
302 * don't know at this point, if that becomes a problem these bits
303 * should be turned off in the mask byte for the control port test.
304 *
305 * We are finally left with a mask of 0x14, due to some printers
306 * being adamant about holding other bits high ........
307 *
308 * Before probing the control port, we write a 0 to the data port -
309 * If not, some printers chuck out garbage when the strobe line
310 * gets toggled.
311 *
312 * 3) Set the data and control ports to a value of 0
313 *
314 * This probe routine has been tested on Epson Lx-800, HP LJ3P,
315 * Epson FX-1170 and C.Itoh 8510RM
316 * printers.
317 * Quick exit on fail added.
318 */
319 static int
320 lpt_detect(device_t dev)
321 {
322 static const u_char testbyte[18] = {
323 0x55, /* alternating zeros */
324 0xaa, /* alternating ones */
325 0xfe, 0xfd, 0xfb, 0xf7,
326 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */
327 0x01, 0x02, 0x04, 0x08,
328 0x10, 0x20, 0x40, 0x80 /* walking one */
329 };
330 int i, status;
331 u_char dtr, ctr, str, var;
332
333 /* Save register contents */
334 dtr = ppbus_rdtr(dev);
335 ctr = ppbus_rctr(dev);
336 str = ppbus_rstr(dev);
337
338 status = 1; /* assume success */
339
340 /* Test data port */
341 for(i = 0; i < 18; i++) {
342 ppbus_wdtr(dev, testbyte[i]);
343 if((var = ppbus_rdtr(dev)) != testbyte[i]) {
344 status = 0;
345 LPT_DPRINTF(("%s(%s): byte value %x cannot be written "
346 "and read from data port (got %x instead).\n",
347 __func__, dev->dv_xname, testbyte[i], var));
348 goto end;
349 }
350 }
351
352 /* Test control port */
353 ppbus_wdtr(dev, 0);
354 for(i = 0; i < 18; i++) {
355 ppbus_wctr(dev, (testbyte[i] & 0x14));
356 if(((var = ppbus_rctr(dev)) & 0x14) != (testbyte[i] & 0x14)) {
357 status = 0;
358 LPT_DPRINTF(("%s(%s): byte value %x (unmasked value "
359 "%x) cannot be written and read from control "
360 "port (got %x instead).\n", __func__,
361 dev->dv_xname, (testbyte[i] & 0x14),
362 testbyte[i], (var & 0x14)));
363 break;
364 }
365 }
366
367 end:
368 /* Restore contents of registers */
369 ppbus_wdtr(dev, dtr);
370 ppbus_wctr(dev, ctr);
371 ppbus_wstr(dev, str);
372
373 return status;
374 }
375
376 /* Log status of status register for printer port */
377 static int
378 lpt_logstatus(const device_t dev, const unsigned char status)
379 {
380 int err;
381
382 err = EIO;
383 if(!(status & LPS_SEL)) {
384 log(LOG_ERR, "%s: offline.", dev->dv_xname);
385 }
386 else if(!(status & LPS_NBSY)) {
387 log(LOG_ERR, "%s: busy.", dev->dv_xname);
388 }
389 else if(status & LPS_OUT) {
390 log(LOG_ERR, "%s: out of paper.", dev->dv_xname);
391 err = EAGAIN;
392 }
393 else if(!(status & LPS_NERR)) {
394 log(LOG_ERR, "%s: output error.", dev->dv_xname);
395 }
396 else {
397 log(LOG_ERR, "%s: no error indication.", dev->dv_xname);
398 err = 0;
399 }
400
401 return err;
402 }
403
404 /*
405 * lptopen -- reset the printer, then wait until it's selected and not busy.
406 */
407 int
408 lptopen(dev_t dev_id, int flags, int fmt, struct lwp *l)
409 {
410 int trys, err;
411 u_int8_t status;
412 device_t dev;
413 struct lpt_softc * lpt;
414 struct ppbus_device_softc * ppbus_dev;
415 device_t ppbus;
416
417 dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
418 if(!dev) {
419 LPT_DPRINTF(("%s(): device not configured.\n", __func__));
420 return ENXIO;
421 }
422
423 lpt = (struct lpt_softc *) dev;
424
425 ppbus = device_parent(dev);
426 ppbus_dev = &(lpt->ppbus_dev);
427
428 /* Request the ppbus */
429 err = lpt_request_ppbus(lpt, PPBUS_WAIT|PPBUS_INTR);
430 if(err) {
431 LPT_DPRINTF(("%s(%s): error (%d) while requesting bus.\n",
432 __func__, dev->dv_xname, err));
433 return (err);
434 }
435
436 /* Update bus mode */
437 ppbus_dev->ctx.mode = ppbus_get_mode(ppbus);
438
439 /* init printer */
440 if ((lpt->sc_flags & LPT_PRIME) && !LPTCTL(dev_id)) {
441 LPT_VPRINTF(("%s(%s): initializing printer.\n", __func__,
442 dev->dv_xname));
443 lpt->sc_state |= LPTINIT;
444 ppbus_wctr(ppbus, LPC_SEL | LPC_NINIT);
445
446 /* wait till ready (printer running diagnostics) */
447 for(trys = 0, status = ppbus_rstr(ppbus); (status & RDY_MASK)
448 != LP_READY; trys += LPT_STEP, status =
449 ppbus_rstr(ppbus)) {
450
451 /* Time up waiting for the printer */
452 if(trys >= LPT_TIMEOUT)
453 break;
454 /* wait LPT_STEP ticks, give up if we get a signal */
455 else {
456 err = tsleep((void *)lpt, LPPRI|PCATCH,
457 "lptinit", LPT_STEP);
458 if((err) && (err != EWOULDBLOCK)) {
459 lpt->sc_state &= ~LPTINIT;
460 LPT_DPRINTF(("%s(%s): interrupted "
461 "during initialization.\n", __func__,
462 dev->dv_xname));
463 lpt_release_ppbus(lpt, PPBUS_WAIT);
464 return (err);
465 }
466 }
467 }
468
469 lpt->sc_state &= ~LPTINIT;
470 if(trys >= LPT_TIMEOUT) {
471 LPT_DPRINTF(("%s(%s): timed out while initializing "
472 "printer. [status %x]\n", __func__,
473 dev->dv_xname, status));
474 err = lpt_logstatus(dev, status);
475 lpt_release_ppbus(lpt, PPBUS_WAIT);
476 return (err);
477 }
478 else
479 LPT_VPRINTF(("%s(%s): printer ready.\n", __func__,
480 dev->dv_xname));
481 }
482
483 /* Set autolinefeed if requested */
484 if (lpt->sc_flags & LPT_AUTOLF)
485 ppbus_wctr(ppbus, LPC_AUTOL);
486 else
487 ppbus_wctr(ppbus, 0);
488
489 /* ready now */
490 lpt->sc_state |= OPEN;
491
492 return 0;
493 }
494
495 /*
496 * lptclose -- close the device, free the local line buffer.
497 *
498 * Check for interrupted write call added.
499 */
500 int
501 lptclose(dev_t dev_id, int flags, int fmt, struct lwp *l)
502 {
503 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
504 struct lpt_softc *sc = device_private(dev);
505 int err;
506
507 err = lpt_release_ppbus(sc, PPBUS_WAIT|PPBUS_INTR);
508 if(err) {
509 LPT_DPRINTF(("%s(%s): error (%d) while releasing ppbus.\n",
510 __func__, dev->dv_xname, err));
511 }
512
513 sc->sc_state = 0;
514
515 return err;
516 }
517
518 /*
519 * lptread --retrieve printer status in IEEE1284 NIBBLE mode
520 */
521 int
522 lptread(dev_t dev_id, struct uio *uio, int ioflag)
523 {
524 size_t len = 0;
525 int error = 0;
526 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
527 struct lpt_softc *sc = device_private(dev);
528
529 if(!(sc->sc_state & HAVEBUS)) {
530 LPT_DPRINTF(("%s(%s): attempt to read using device which does "
531 "not own the bus(%s).\n", __func__, dev->dv_xname,
532 device_parent(dev)->dv_xname));
533 return (ENODEV);
534 }
535
536 sc->sc_state &= ~INTERRUPTED;
537 while (uio->uio_resid) {
538 error = ppbus_read(device_parent(dev), sc->sc_outbuf,
539 min(BUFSIZE, uio->uio_resid), 0, &len);
540
541 /* If error or no more data, stop */
542 if (error) {
543 if (error != EWOULDBLOCK)
544 sc->sc_state |= INTERRUPTED;
545 break;
546 }
547 if (len == 0)
548 break;
549
550 if ((error = uiomove(sc->sc_outbuf, len, uio)))
551 break;
552 }
553
554 return error;
555 }
556
557 /*
558 * lptwrite --copy a line from user space to a local buffer, then call
559 * putc to get the chars moved to the output queue.
560 *
561 * Flagging of interrupted write added.
562 */
563 int
564 lptwrite(dev_t dev_id, struct uio * uio, int ioflag)
565 {
566 int error=0;
567 size_t n, cnt;
568 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
569 struct lpt_softc * sc = device_private(dev);
570
571 /* Check state and flags */
572 if(!(sc->sc_state & HAVEBUS)) {
573 LPT_DPRINTF(("%s(%s): attempt to write using device which does "
574 "not own the bus(%s).\n", __func__, dev->dv_xname,
575 device_parent(dev)->dv_xname));
576 return EINVAL;
577 }
578
579 LPT_VPRINTF(("%s(%s): writing %d bytes\n", __func__,
580 dev->dv_xname, uio->uio_resid));
581
582 /* Write the data */
583 sc->sc_state &= ~INTERRUPTED;
584 while (uio->uio_resid) {
585 n = MIN(BUFSIZE, uio->uio_resid);
586 error = uiomove(sc->sc_inbuf, n, uio);
587 if (error)
588 break;
589
590 error = ppbus_write(device_parent(dev), sc->sc_inbuf, n, ioflag,
591 &cnt);
592 if (error) {
593 if (error != EWOULDBLOCK)
594 sc->sc_state |= INTERRUPTED;
595 break;
596 }
597 }
598
599 LPT_VPRINTF(("%s(%s): transfer finished, error %d.\n", __func__,
600 dev->dv_xname, error));
601
602 return error;
603 }
604
605 /* Printer ioctl */
606 int
607 lptioctl(dev_t dev_id, u_long cmd, void *data, int flags, struct lwp *l)
608 {
609 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
610 struct lpt_softc *sc = device_private(dev);
611 int val, fl;
612 int error=0;
613
614 if(!(sc->sc_state & HAVEBUS)) {
615 LPT_DPRINTF(("%s(%s): attempt to perform ioctl on device which "
616 "does not own the bus(%s).\n", __func__, dev->dv_xname,
617 device_parent(dev)->dv_xname));
618 return EBUSY;
619 }
620
621 switch (cmd) {
622 case LPTGMODE:
623 switch (ppbus_get_mode(device_parent(dev))) {
624 case PPBUS_COMPATIBLE:
625 val = mode_standard;
626 break;
627 case PPBUS_NIBBLE:
628 val = mode_nibble;
629 break;
630 case PPBUS_PS2:
631 val = mode_ps2;
632 break;
633 case PPBUS_FAST:
634 val = mode_fast;
635 break;
636 case PPBUS_EPP:
637 val = mode_epp;
638 break;
639 case PPBUS_ECP:
640 val = mode_ecp;
641 break;
642 default:
643 error = EINVAL;
644 val = mode_unknown;
645 break;
646 }
647 *(int *)data = val;
648 break;
649
650 case LPTSMODE:
651 switch (*(int *)data) {
652 case mode_standard:
653 val = PPBUS_COMPATIBLE;
654 break;
655 case mode_nibble:
656 val = PPBUS_NIBBLE;
657 break;
658 case mode_ps2:
659 val = PPBUS_PS2;
660 break;
661 case mode_fast:
662 val = PPBUS_FAST;
663 break;
664 case mode_epp:
665 val = PPBUS_EPP;
666 break;
667 case mode_ecp:
668 val = PPBUS_ECP;
669 break;
670 default:
671 error = EINVAL;
672 val = mode_unknown;
673 break;
674 }
675
676 if (!error)
677 error = ppbus_set_mode(device_parent(dev), val, 0);
678
679 break;
680
681 case LPTGFLAGS:
682 fl = 0;
683
684 /* DMA */
685 error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val);
686 if (error)
687 break;
688 if (val)
689 fl |= LPT_DMA;
690
691 /* IEEE mode negotiation */
692 error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val);
693 if (error)
694 break;
695 if (val)
696 fl |= LPT_IEEE;
697
698 /* interrupts */
699 error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val);
700 if (error)
701 break;
702 if (val)
703 fl |= LPT_INTR;
704
705 /* lpt-only flags */
706 fl |= sc->sc_flags;
707
708 *(int *)data = fl;
709 break;
710
711 case LPTSFLAGS:
712 fl = *(int *)data;
713
714 /* DMA */
715 val = (fl & LPT_DMA);
716 error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val);
717 if (error)
718 break;
719
720 /* IEEE mode negotiation */
721 val = (fl & LPT_IEEE);
722 error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val);
723 if (error)
724 break;
725
726 /* interrupts */
727 val = (fl & LPT_INTR);
728 error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val);
729 if (error)
730 break;
731
732 /* lpt-only flags */
733 sc->sc_flags = fl & (LPT_PRIME|LPT_AUTOLF);
734
735 break;
736
737 default:
738 error = EINVAL;
739 break;
740 }
741
742 return error;
743 }
744
745