lpt.c revision 1.29 1 /* $NetBSD: lpt.c,v 1.29 2014/03/16 05:20:28 dholland 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.29 2014/03/16 05:20:28 dholland 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, cfdata_t, 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_NEW(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 .d_open = lptopen,
114 .d_close = lptclose,
115 .d_read = lptread,
116 .d_write = lptwrite,
117 .d_ioctl = lptioctl,
118 .d_stop = nostop,
119 .d_tty = notty,
120 .d_poll = nopoll,
121 .d_mmap = nommap,
122 .d_kqfilter = nokqfilter,
123 .d_flag = D_OTHER
124 };
125
126
127 /* Function prototypes */
128 static int lpt_detect(device_t);
129 static int lpt_request_ppbus(struct lpt_softc *, int);
130 static int lpt_release_ppbus(struct lpt_softc *, int);
131 static int lpt_logstatus(const device_t, const unsigned char);
132
133 /*
134 * lpt_probe()
135 */
136 static int
137 lpt_probe(device_t parent, cfdata_t match, void *aux)
138 {
139 /* Test ppbus's capability */
140 return lpt_detect(parent);
141 }
142
143 static void
144 lpt_attach(device_t parent, device_t self, void *aux)
145 {
146 struct lpt_softc * sc = device_private(self);
147 struct ppbus_device_softc * ppbdev = &(sc->ppbus_dev);
148 struct ppbus_attach_args * args = aux;
149 char buf[64];
150 int error;
151
152 ppbdev->sc_dev = self;
153
154 error = lpt_request_ppbus(sc, 0);
155 if(error) {
156 printf("%s(%s): error (%d) requesting bus(%s). Device not "
157 "properly attached.\n", __func__, device_xname(self),
158 error, device_xname(parent));
159 return;
160 }
161
162 /* Record capabilities */
163 ppbdev->capabilities = args->capabilities;
164
165 /* Allocate memory buffers */
166 if(ppbdev->capabilities & PPBUS_HAS_DMA) {
167 if(ppbus_dma_malloc(parent, &(sc->sc_inbuf),
168 &(sc->sc_in_baddr), BUFSIZE)) {
169
170 printf(" : cannot allocate input DMA buffer. Device "
171 "not properly attached!\n");
172 return;
173 }
174 if(ppbus_dma_malloc(parent, &(sc->sc_outbuf),
175 &(sc->sc_out_baddr), BUFSIZE)) {
176
177 ppbus_dma_free(parent, &(sc->sc_inbuf),
178 &(sc->sc_in_baddr), BUFSIZE);
179 printf(" : cannot allocate output DMA buffer. Device "
180 "not properly attached!\n");
181 return;
182 }
183 } else {
184 sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
185 sc->sc_outbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
186 }
187
188 /* Print out mode */
189 ppbdev->ctx.mode = ppbus_get_mode(parent);
190 snprintb(buf, sizeof(buf),
191 "\20\1COMPATIBLE\2NIBBLE\3PS2\4EPP\5ECP\6FAST_CENTR",
192 ppbdev->ctx.mode);
193 printf(": port mode = %s\n", buf);
194
195 /* Initialize the device on open by default */
196 sc->sc_flags = LPT_PRIME;
197
198 lpt_release_ppbus(sc, 0);
199 }
200
201 static int
202 lpt_detach(device_t self, int flags)
203 {
204 struct lpt_softc * lpt = device_private(self);
205 struct ppbus_device_softc * ppbdev = (struct ppbus_device_softc *) lpt;
206 int err;
207
208 if(lpt->sc_state & HAVEBUS) {
209 err = lpt_release_ppbus(lpt, 0);
210 if(err) {
211 printf("%s error (%d) while releasing bus",
212 device_xname(self), err);
213 if(flags & DETACH_FORCE) {
214 printf(", continuing (DETACH_FORCE)!\n");
215 }
216 else {
217 printf(", terminating!\n");
218 return 0;
219 }
220 }
221 lpt->sc_state &= ~HAVEBUS;
222 }
223
224 ppbdev->ctx.valid = 0;
225
226 /* Free memory buffers */
227 if(ppbdev->capabilities & PPBUS_HAS_DMA) {
228 ppbus_dma_free(device_parent(self), &(lpt->sc_inbuf),
229 &(lpt->sc_in_baddr), BUFSIZE);
230 ppbus_dma_free(device_parent(self), &(lpt->sc_outbuf),
231 &(lpt->sc_out_baddr), BUFSIZE);
232 } else {
233 free(lpt->sc_inbuf, M_DEVBUF);
234 free(lpt->sc_outbuf, M_DEVBUF);
235 }
236
237 return 1;
238 }
239
240 /* Grab bus for lpt device */
241 static int
242 lpt_request_ppbus(struct lpt_softc * lpt, int how)
243 {
244 device_t dev = lpt->ppbus_dev.sc_dev;
245 int error;
246
247 error = ppbus_request_bus(device_parent(dev), dev, how, (hz));
248 if (!(error)) {
249 lpt->sc_state |= HAVEBUS;
250 }
251 else {
252 LPT_DPRINTF(("%s(%s): error %d requesting bus.\n", __func__,
253 device_xname(dev), error));
254 }
255
256 return error;
257 }
258
259 /* Release ppbus to enable other devices to use it. */
260 static int
261 lpt_release_ppbus(struct lpt_softc * lpt, int how)
262 {
263 device_t dev = lpt->ppbus_dev.sc_dev;
264 int error;
265
266 if(lpt->sc_state & HAVEBUS) {
267 error = ppbus_release_bus(device_parent(dev), dev, how, (hz));
268 if(!(error))
269 lpt->sc_state &= ~HAVEBUS;
270 else {
271 LPT_DPRINTF(("%s(%s): error releasing bus.\n", __func__,
272 device_xname(dev)));
273 }
274 }
275 else {
276 error = EINVAL;
277 LPT_DPRINTF(("%s(%s): device does not own bus.\n", __func__,
278 device_xname(dev)));
279 }
280
281 return error;
282 }
283
284
285 /*
286 * Probe simplified by replacing multiple loops with a hardcoded
287 * test pattern - 1999/02/08 des (at) freebsd.org
288 *
289 * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
290 * Based partially on Rod Grimes' printer probe
291 *
292 * Logic:
293 * 1) If no port address was given, use the bios detected ports
294 * and autodetect what ports the printers are on.
295 * 2) Otherwise, probe the data port at the address given,
296 * using the method in Rod Grimes' port probe.
297 * (Much code ripped off directly from Rod's probe.)
298 *
299 * Comments from Rod's probe:
300 * Logic:
301 * 1) You should be able to write to and read back the same value
302 * to the data port. Do an alternating zeros, alternating ones,
303 * walking zero, and walking one test to check for stuck bits.
304 *
305 * 2) You should be able to write to and read back the same value
306 * to the control port lower 5 bits, the upper 3 bits are reserved
307 * per the IBM PC technical reference manauls and different boards
308 * do different things with them. Do an alternating zeros, alternating
309 * ones, walking zero, and walking one test to check for stuck bits.
310 *
311 * Some printers drag the strobe line down when the are powered off
312 * so this bit has been masked out of the control port test.
313 *
314 * XXX Some printers may not like a fast pulse on init or strobe, I
315 * don't know at this point, if that becomes a problem these bits
316 * should be turned off in the mask byte for the control port test.
317 *
318 * We are finally left with a mask of 0x14, due to some printers
319 * being adamant about holding other bits high ........
320 *
321 * Before probing the control port, we write a 0 to the data port -
322 * If not, some printers chuck out garbage when the strobe line
323 * gets toggled.
324 *
325 * 3) Set the data and control ports to a value of 0
326 *
327 * This probe routine has been tested on Epson Lx-800, HP LJ3P,
328 * Epson FX-1170 and C.Itoh 8510RM
329 * printers.
330 * Quick exit on fail added.
331 */
332 static int
333 lpt_detect(device_t dev)
334 {
335 static const u_char testbyte[18] = {
336 0x55, /* alternating zeros */
337 0xaa, /* alternating ones */
338 0xfe, 0xfd, 0xfb, 0xf7,
339 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */
340 0x01, 0x02, 0x04, 0x08,
341 0x10, 0x20, 0x40, 0x80 /* walking one */
342 };
343 int i, status;
344 u_char dtr, ctr, str, var;
345
346 /* Save register contents */
347 dtr = ppbus_rdtr(dev);
348 ctr = ppbus_rctr(dev);
349 str = ppbus_rstr(dev);
350
351 status = 1; /* assume success */
352
353 /* Test data port */
354 for(i = 0; i < 18; i++) {
355 ppbus_wdtr(dev, testbyte[i]);
356 if((var = ppbus_rdtr(dev)) != testbyte[i]) {
357 status = 0;
358 LPT_DPRINTF(("%s(%s): byte value %x cannot be written "
359 "and read from data port (got %x instead).\n",
360 __func__, device_xname(dev), testbyte[i], var));
361 goto end;
362 }
363 }
364
365 /* Test control port */
366 ppbus_wdtr(dev, 0);
367 for(i = 0; i < 18; i++) {
368 ppbus_wctr(dev, (testbyte[i] & 0x14));
369 if(((var = ppbus_rctr(dev)) & 0x14) != (testbyte[i] & 0x14)) {
370 status = 0;
371 LPT_DPRINTF(("%s(%s): byte value %x (unmasked value "
372 "%x) cannot be written and read from control "
373 "port (got %x instead).\n", __func__,
374 device_xname(dev), (testbyte[i] & 0x14),
375 testbyte[i], (var & 0x14)));
376 break;
377 }
378 }
379
380 end:
381 /* Restore contents of registers */
382 ppbus_wdtr(dev, dtr);
383 ppbus_wctr(dev, ctr);
384 ppbus_wstr(dev, str);
385
386 return status;
387 }
388
389 /* Log status of status register for printer port */
390 static int
391 lpt_logstatus(const device_t dev, const unsigned char status)
392 {
393 int err;
394
395 err = EIO;
396 if(!(status & LPS_SEL)) {
397 log(LOG_ERR, "%s: offline.", device_xname(dev));
398 }
399 else if(!(status & LPS_NBSY)) {
400 log(LOG_ERR, "%s: busy.", device_xname(dev));
401 }
402 else if(status & LPS_OUT) {
403 log(LOG_ERR, "%s: out of paper.", device_xname(dev));
404 err = EAGAIN;
405 }
406 else if(!(status & LPS_NERR)) {
407 log(LOG_ERR, "%s: output error.", device_xname(dev));
408 }
409 else {
410 log(LOG_ERR, "%s: no error indication.", device_xname(dev));
411 err = 0;
412 }
413
414 return err;
415 }
416
417 /*
418 * lptopen -- reset the printer, then wait until it's selected and not busy.
419 */
420 int
421 lptopen(dev_t dev_id, int flags, int fmt, struct lwp *l)
422 {
423 int trys, err;
424 u_int8_t status;
425 device_t dev;
426 struct lpt_softc * lpt;
427 struct ppbus_device_softc * ppbus_dev;
428 device_t ppbus;
429
430 dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
431 if(!dev) {
432 LPT_DPRINTF(("%s(): device not configured.\n", __func__));
433 return ENXIO;
434 }
435
436 lpt = device_private(dev);
437
438 ppbus = device_parent(dev);
439 ppbus_dev = &(lpt->ppbus_dev);
440
441 /* Request the ppbus */
442 err = lpt_request_ppbus(lpt, PPBUS_WAIT|PPBUS_INTR);
443 if(err) {
444 LPT_DPRINTF(("%s(%s): error (%d) while requesting bus.\n",
445 __func__, device_xname(dev), err));
446 return (err);
447 }
448
449 /* Update bus mode */
450 ppbus_dev->ctx.mode = ppbus_get_mode(ppbus);
451
452 /* init printer */
453 if ((lpt->sc_flags & LPT_PRIME) && !LPTCTL(dev_id)) {
454 LPT_VPRINTF(("%s(%s): initializing printer.\n", __func__,
455 device_xname(dev)));
456 lpt->sc_state |= LPTINIT;
457 ppbus_wctr(ppbus, LPC_SEL | LPC_NINIT);
458
459 /* wait till ready (printer running diagnostics) */
460 for(trys = 0, status = ppbus_rstr(ppbus); (status & RDY_MASK)
461 != LP_READY; trys += LPT_STEP, status =
462 ppbus_rstr(ppbus)) {
463
464 /* Time up waiting for the printer */
465 if(trys >= LPT_TIMEOUT)
466 break;
467 /* wait LPT_STEP ticks, give up if we get a signal */
468 else {
469 err = tsleep((void *)lpt, LPPRI|PCATCH,
470 "lptinit", LPT_STEP);
471 if((err) && (err != EWOULDBLOCK)) {
472 lpt->sc_state &= ~LPTINIT;
473 LPT_DPRINTF(("%s(%s): interrupted "
474 "during initialization.\n", __func__,
475 device_xname(dev)));
476 lpt_release_ppbus(lpt, PPBUS_WAIT);
477 return (err);
478 }
479 }
480 }
481
482 lpt->sc_state &= ~LPTINIT;
483 if(trys >= LPT_TIMEOUT) {
484 LPT_DPRINTF(("%s(%s): timed out while initializing "
485 "printer. [status %x]\n", __func__,
486 device_xname(dev), status));
487 err = lpt_logstatus(dev, status);
488 lpt_release_ppbus(lpt, PPBUS_WAIT);
489 return (err);
490 }
491 else {
492 LPT_VPRINTF(("%s(%s): printer ready.\n", __func__,
493 device_xname(dev)));
494 }
495 }
496
497 /* Set autolinefeed if requested */
498 if (lpt->sc_flags & LPT_AUTOLF)
499 ppbus_wctr(ppbus, LPC_AUTOL);
500 else
501 ppbus_wctr(ppbus, 0);
502
503 /* ready now */
504 lpt->sc_state |= OPEN;
505
506 return 0;
507 }
508
509 /*
510 * lptclose -- close the device, free the local line buffer.
511 *
512 * Check for interrupted write call added.
513 */
514 int
515 lptclose(dev_t dev_id, int flags, int fmt, struct lwp *l)
516 {
517 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
518 struct lpt_softc *sc = device_private(dev);
519 int err;
520
521 err = lpt_release_ppbus(sc, PPBUS_WAIT|PPBUS_INTR);
522 if(err) {
523 LPT_DPRINTF(("%s(%s): error (%d) while releasing ppbus.\n",
524 __func__, device_xname(dev), err));
525 }
526
527 sc->sc_state = 0;
528
529 return err;
530 }
531
532 /*
533 * lptread --retrieve printer status in IEEE1284 NIBBLE mode
534 */
535 int
536 lptread(dev_t dev_id, struct uio *uio, int ioflag)
537 {
538 size_t len = 0;
539 int error = 0;
540 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
541 struct lpt_softc *sc = device_private(dev);
542
543 if(!(sc->sc_state & HAVEBUS)) {
544 LPT_DPRINTF(("%s(%s): attempt to read using device which does "
545 "not own the bus(%s).\n", __func__, device_xname(dev),
546 device_xname(device_parent(dev))));
547 return (ENODEV);
548 }
549
550 sc->sc_state &= ~INTERRUPTED;
551 while (uio->uio_resid) {
552 error = ppbus_read(device_parent(dev), sc->sc_outbuf,
553 min(BUFSIZE, uio->uio_resid), 0, &len);
554
555 /* If error or no more data, stop */
556 if (error) {
557 if (error != EWOULDBLOCK)
558 sc->sc_state |= INTERRUPTED;
559 break;
560 }
561 if (len == 0)
562 break;
563
564 if ((error = uiomove(sc->sc_outbuf, len, uio)))
565 break;
566 }
567
568 return error;
569 }
570
571 /*
572 * lptwrite --copy a line from user space to a local buffer, then call
573 * putc to get the chars moved to the output queue.
574 *
575 * Flagging of interrupted write added.
576 */
577 int
578 lptwrite(dev_t dev_id, struct uio * uio, int ioflag)
579 {
580 int error=0;
581 size_t n, cnt;
582 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
583 struct lpt_softc * sc = device_private(dev);
584
585 /* Check state and flags */
586 if(!(sc->sc_state & HAVEBUS)) {
587 LPT_DPRINTF(("%s(%s): attempt to write using device which does "
588 "not own the bus(%s).\n", __func__, device_xname(dev),
589 device_xname(device_parent(dev))));
590 return EINVAL;
591 }
592
593 LPT_VPRINTF(("%s(%s): writing %zu bytes\n", __func__,
594 device_xname(dev), uio->uio_resid));
595
596 /* Write the data */
597 sc->sc_state &= ~INTERRUPTED;
598 while (uio->uio_resid) {
599 n = MIN(BUFSIZE, uio->uio_resid);
600 error = uiomove(sc->sc_inbuf, n, uio);
601 if (error)
602 break;
603
604 error = ppbus_write(device_parent(dev), sc->sc_inbuf, n, ioflag,
605 &cnt);
606 if (error) {
607 if (error != EWOULDBLOCK)
608 sc->sc_state |= INTERRUPTED;
609 break;
610 }
611 }
612
613 LPT_VPRINTF(("%s(%s): transfer finished, error %d.\n", __func__,
614 device_xname(dev), error));
615
616 return error;
617 }
618
619 /* Printer ioctl */
620 int
621 lptioctl(dev_t dev_id, u_long cmd, void *data, int flags, struct lwp *l)
622 {
623 device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
624 struct lpt_softc *sc = device_private(dev);
625 int val, fl;
626 int error=0;
627
628 if(!(sc->sc_state & HAVEBUS)) {
629 LPT_DPRINTF(("%s(%s): attempt to perform ioctl on device which "
630 "does not own the bus(%s).\n", __func__, device_xname(dev),
631 device_xname(device_parent(dev))));
632 return EBUSY;
633 }
634
635 switch (cmd) {
636 case LPTGMODE:
637 switch (ppbus_get_mode(device_parent(dev))) {
638 case PPBUS_COMPATIBLE:
639 val = mode_standard;
640 break;
641 case PPBUS_NIBBLE:
642 val = mode_nibble;
643 break;
644 case PPBUS_PS2:
645 val = mode_ps2;
646 break;
647 case PPBUS_FAST:
648 val = mode_fast;
649 break;
650 case PPBUS_EPP:
651 val = mode_epp;
652 break;
653 case PPBUS_ECP:
654 val = mode_ecp;
655 break;
656 default:
657 error = EINVAL;
658 val = mode_unknown;
659 break;
660 }
661 *(int *)data = val;
662 break;
663
664 case LPTSMODE:
665 switch (*(int *)data) {
666 case mode_standard:
667 val = PPBUS_COMPATIBLE;
668 break;
669 case mode_nibble:
670 val = PPBUS_NIBBLE;
671 break;
672 case mode_ps2:
673 val = PPBUS_PS2;
674 break;
675 case mode_fast:
676 val = PPBUS_FAST;
677 break;
678 case mode_epp:
679 val = PPBUS_EPP;
680 break;
681 case mode_ecp:
682 val = PPBUS_ECP;
683 break;
684 default:
685 error = EINVAL;
686 val = mode_unknown;
687 break;
688 }
689
690 if (!error)
691 error = ppbus_set_mode(device_parent(dev), val, 0);
692
693 break;
694
695 case LPTGFLAGS:
696 fl = 0;
697
698 /* DMA */
699 error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val);
700 if (error)
701 break;
702 if (val)
703 fl |= LPT_DMA;
704
705 /* IEEE mode negotiation */
706 error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val);
707 if (error)
708 break;
709 if (val)
710 fl |= LPT_IEEE;
711
712 /* interrupts */
713 error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val);
714 if (error)
715 break;
716 if (val)
717 fl |= LPT_INTR;
718
719 /* lpt-only flags */
720 fl |= sc->sc_flags;
721
722 *(int *)data = fl;
723 break;
724
725 case LPTSFLAGS:
726 fl = *(int *)data;
727
728 /* DMA */
729 val = (fl & LPT_DMA);
730 error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val);
731 if (error)
732 break;
733
734 /* IEEE mode negotiation */
735 val = (fl & LPT_IEEE);
736 error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val);
737 if (error)
738 break;
739
740 /* interrupts */
741 val = (fl & LPT_INTR);
742 error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val);
743 if (error)
744 break;
745
746 /* lpt-only flags */
747 sc->sc_flags = fl & (LPT_PRIME|LPT_AUTOLF);
748
749 break;
750
751 default:
752 error = EINVAL;
753 break;
754 }
755
756 return error;
757 }
758
759