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