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