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