Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Copyright (c) 1990 William F. Jolitz, TeleMuse | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This software is a component of "386BSD" developed by | |
16 | * William F. Jolitz, TeleMuse. | |
17 | * 4. Neither the name of the developer nor the name "386BSD" | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ | |
22 | * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS | |
23 | * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. | |
24 | * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT | |
25 | * NOT MAKE USE OF THIS WORK. | |
26 | * | |
27 | * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED | |
28 | * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN | |
29 | * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES | |
30 | * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING | |
31 | * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND | |
32 | * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE | |
33 | * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS | |
34 | * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. | |
35 | * | |
36 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND | |
37 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
38 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
39 | * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE | |
40 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
41 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
42 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
44 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
45 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
46 | * SUCH DAMAGE. | |
47 | * | |
48 | * from: unknown origin, 386BSD 0.1 | |
49 | * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp | |
50 | * From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp | |
51 | * $FreeBSD: src/sys/dev/ppbus/lpt.c,v 1.15.2.3 2000/07/07 00:30:40 obrien Exp $ | |
e3869ec7 | 52 | * $DragonFly: src/sys/dev/misc/lpt/lpt.c,v 1.19 2006/12/22 23:26:17 swildner Exp $ |
984263bc MD |
53 | */ |
54 | ||
55 | /* | |
56 | * Device Driver for AT parallel printer port | |
57 | * Written by William Jolitz 12/18/90 | |
58 | */ | |
59 | ||
60 | /* | |
61 | * Updated for ppbus by Nicolas Souchu | |
62 | * [Mon Jul 28 1997] | |
63 | */ | |
64 | ||
65 | #include "opt_lpt.h" | |
66 | ||
67 | #include <sys/param.h> | |
68 | #include <sys/systm.h> | |
69 | #include <sys/module.h> | |
70 | #include <sys/bus.h> | |
71 | #include <sys/conf.h> | |
fef8985e | 72 | #include <sys/device.h> |
984263bc MD |
73 | #include <sys/kernel.h> |
74 | #include <sys/uio.h> | |
75 | #include <sys/syslog.h> | |
b28b340f | 76 | #include <sys/thread2.h> |
984263bc | 77 | #include <sys/malloc.h> |
1f7ab7c9 | 78 | #include <sys/rman.h> |
984263bc MD |
79 | |
80 | #include <machine/clock.h> | |
984263bc | 81 | |
1f2de5d4 MD |
82 | #include "lptio.h" |
83 | #include <bus/ppbus/ppbconf.h> | |
84 | #include <bus/ppbus/ppb_1284.h> | |
85 | #include "lpt.h" | |
984263bc | 86 | #include "ppbus_if.h" |
1f2de5d4 | 87 | #include <bus/ppbus/ppbio.h> |
984263bc MD |
88 | |
89 | MALLOC_DEFINE(M_LPT, "lpt", "LPT buffers"); | |
90 | ||
91 | #ifndef LPT_DEBUG | |
92 | #define lprintf(args) | |
93 | #else | |
94 | #define lprintf(args) \ | |
95 | do { \ | |
96 | if (lptflag) \ | |
e3869ec7 | 97 | kprintf args; \ |
984263bc MD |
98 | } while (0) |
99 | static int volatile lptflag = 1; | |
100 | #endif | |
101 | ||
102 | #define LPINITRDY 4 /* wait up to 4 seconds for a ready */ | |
103 | #define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */ | |
104 | #define LPTOUTMAX 1 /* maximal timeout 1 s */ | |
984263bc MD |
105 | #define BUFSIZE 1024 |
106 | #define BUFSTATSIZE 32 | |
107 | ||
108 | #define LPTUNIT(s) ((s)&0x03) | |
109 | #define LPTFLAGS(s) ((s)&0xfc) | |
110 | ||
111 | struct lpt_data { | |
984263bc MD |
112 | short sc_state; |
113 | /* default case: negative prime, negative ack, handshake strobe, | |
114 | prime once */ | |
115 | u_char sc_control; | |
116 | char sc_flags; | |
e4c9c0c8 | 117 | #define LP_UNITMASK 0x03 /* up to 4 units */ |
984263bc MD |
118 | #define LP_POS_INIT 0x04 /* if we are a postive init signal */ |
119 | #define LP_POS_ACK 0x08 /* if we are a positive going ack */ | |
120 | #define LP_NO_PRIME 0x10 /* don't prime the printer at all */ | |
121 | #define LP_PRIMEOPEN 0x20 /* prime on every open */ | |
122 | #define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */ | |
123 | #define LP_BYPASS 0x80 /* bypass printer ready checks */ | |
124 | void *sc_inbuf; | |
125 | void *sc_statbuf; | |
126 | short sc_xfercnt ; | |
127 | char sc_primed; | |
128 | char *sc_cp ; | |
129 | u_short sc_irq ; /* IRQ status of port */ | |
130 | #define LP_HAS_IRQ 0x01 /* we have an irq available */ | |
131 | #define LP_USE_IRQ 0x02 /* we are using our irq */ | |
132 | #define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ | |
133 | #define LP_ENABLE_EXT 0x10 /* we shall use advanced mode when possible */ | |
134 | u_char sc_backoff ; /* time to call lptout() again */ | |
135 | ||
136 | struct resource *intr_resource; /* interrupt resource */ | |
137 | void *intr_cookie; /* interrupt registration cookie */ | |
6aed8a5b | 138 | struct callout sc_callout; |
984263bc MD |
139 | }; |
140 | ||
141 | #define LPT_NAME "lpt" /* our official name */ | |
142 | ||
143 | static timeout_t lptout; | |
144 | static int lpt_port_test(device_t dev, u_char data, u_char mask); | |
145 | static int lpt_detect(device_t dev); | |
146 | ||
147 | #define DEVTOSOFTC(dev) \ | |
148 | ((struct lpt_data *)device_get_softc(dev)) | |
149 | #define UNITOSOFTC(unit) \ | |
150 | ((struct lpt_data *)devclass_get_softc(lpt_devclass, (unit))) | |
151 | #define UNITODEVICE(unit) \ | |
152 | (devclass_get_device(lpt_devclass, (unit))) | |
153 | ||
154 | static void lptintr(device_t dev); | |
155 | static void lpt_intr(void *arg); /* without spls */ | |
156 | ||
157 | static devclass_t lpt_devclass; | |
158 | ||
159 | ||
160 | /* bits for state */ | |
161 | #define OPEN (1<<0) /* device is open */ | |
162 | #define ASLP (1<<1) /* awaiting draining of printer */ | |
163 | #define EERROR (1<<2) /* error was received from printer */ | |
164 | #define OBUSY (1<<3) /* printer is busy doing output */ | |
165 | #define LPTOUT (1<<4) /* timeout while not selected */ | |
166 | #define TOUT (1<<5) /* timeout while not selected */ | |
167 | #define LPTINIT (1<<6) /* waiting to initialize for open */ | |
168 | #define INTERRUPTED (1<<7) /* write call was interrupted */ | |
169 | ||
170 | #define HAVEBUS (1<<8) /* the driver owns the bus */ | |
171 | ||
172 | ||
173 | /* status masks to interrogate printer status */ | |
174 | #define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */ | |
175 | #define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR) | |
176 | ||
177 | /* Printer Ready condition - from lpa.c */ | |
178 | /* Only used in polling code */ | |
179 | #define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) | |
180 | #define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) | |
181 | #define NOT_READY(ppbus) ((ppb_rstr(ppbus)^LPS_INVERT)&LPS_MASK) | |
182 | ||
183 | #define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */ | |
184 | #define MAX_SPIN 20 /* Max delay for device ready in usecs */ | |
185 | ||
186 | ||
187 | static d_open_t lptopen; | |
188 | static d_close_t lptclose; | |
189 | static d_write_t lptwrite; | |
190 | static d_read_t lptread; | |
191 | static d_ioctl_t lptioctl; | |
192 | ||
193 | #define CDEV_MAJOR 16 | |
fef8985e MD |
194 | static struct dev_ops lpt_ops = { |
195 | { LPT_NAME, CDEV_MAJOR, 0 }, | |
196 | .d_open = lptopen, | |
197 | .d_close = lptclose, | |
198 | .d_read = lptread, | |
199 | .d_write = lptwrite, | |
200 | .d_ioctl = lptioctl, | |
984263bc MD |
201 | }; |
202 | ||
203 | static int | |
204 | lpt_request_ppbus(device_t dev, int how) | |
205 | { | |
206 | device_t ppbus = device_get_parent(dev); | |
207 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
208 | int error; | |
209 | ||
210 | if (sc->sc_state & HAVEBUS) | |
211 | return (0); | |
212 | ||
213 | /* we have the bus only if the request succeded */ | |
214 | if ((error = ppb_request_bus(ppbus, dev, how)) == 0) | |
215 | sc->sc_state |= HAVEBUS; | |
216 | ||
217 | return (error); | |
218 | } | |
219 | ||
220 | static int | |
221 | lpt_release_ppbus(device_t dev) | |
222 | { | |
223 | device_t ppbus = device_get_parent(dev); | |
224 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
225 | int error = 0; | |
226 | ||
227 | if ((error = ppb_release_bus(ppbus, dev)) == 0) | |
228 | sc->sc_state &= ~HAVEBUS; | |
229 | ||
230 | return (error); | |
231 | } | |
232 | ||
233 | /* | |
234 | * Internal routine to lptprobe to do port tests of one byte value | |
235 | */ | |
236 | static int | |
237 | lpt_port_test(device_t ppbus, u_char data, u_char mask) | |
238 | { | |
239 | int temp, timeout; | |
240 | ||
241 | data = data & mask; | |
242 | ppb_wdtr(ppbus, data); | |
243 | timeout = 10000; | |
244 | do { | |
245 | DELAY(10); | |
246 | temp = ppb_rdtr(ppbus) & mask; | |
247 | } | |
248 | while (temp != data && --timeout); | |
249 | lprintf(("out=%x\tin=%x\ttout=%d\n", data, temp, timeout)); | |
250 | return (temp == data); | |
251 | } | |
252 | ||
253 | /* | |
254 | * Probe simplified by replacing multiple loops with a hardcoded | |
255 | * test pattern - 1999/02/08 des@freebsd.org | |
256 | * | |
257 | * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 | |
258 | * Based partially on Rod Grimes' printer probe | |
259 | * | |
260 | * Logic: | |
261 | * 1) If no port address was given, use the bios detected ports | |
262 | * and autodetect what ports the printers are on. | |
263 | * 2) Otherwise, probe the data port at the address given, | |
264 | * using the method in Rod Grimes' port probe. | |
265 | * (Much code ripped off directly from Rod's probe.) | |
266 | * | |
267 | * Comments from Rod's probe: | |
268 | * Logic: | |
269 | * 1) You should be able to write to and read back the same value | |
270 | * to the data port. Do an alternating zeros, alternating ones, | |
271 | * walking zero, and walking one test to check for stuck bits. | |
272 | * | |
273 | * 2) You should be able to write to and read back the same value | |
274 | * to the control port lower 5 bits, the upper 3 bits are reserved | |
275 | * per the IBM PC technical reference manauls and different boards | |
276 | * do different things with them. Do an alternating zeros, alternating | |
277 | * ones, walking zero, and walking one test to check for stuck bits. | |
278 | * | |
279 | * Some printers drag the strobe line down when the are powered off | |
280 | * so this bit has been masked out of the control port test. | |
281 | * | |
282 | * XXX Some printers may not like a fast pulse on init or strobe, I | |
283 | * don't know at this point, if that becomes a problem these bits | |
284 | * should be turned off in the mask byte for the control port test. | |
285 | * | |
286 | * We are finally left with a mask of 0x14, due to some printers | |
287 | * being adamant about holding other bits high ........ | |
288 | * | |
289 | * Before probing the control port, we write a 0 to the data port - | |
290 | * If not, some printers chuck out garbage when the strobe line | |
291 | * gets toggled. | |
292 | * | |
293 | * 3) Set the data and control ports to a value of 0 | |
294 | * | |
295 | * This probe routine has been tested on Epson Lx-800, HP LJ3P, | |
296 | * Epson FX-1170 and C.Itoh 8510RM | |
297 | * printers. | |
298 | * Quick exit on fail added. | |
299 | */ | |
300 | static int | |
301 | lpt_detect(device_t dev) | |
302 | { | |
303 | device_t ppbus = device_get_parent(dev); | |
304 | ||
305 | static u_char testbyte[18] = { | |
306 | 0x55, /* alternating zeros */ | |
307 | 0xaa, /* alternating ones */ | |
308 | 0xfe, 0xfd, 0xfb, 0xf7, | |
309 | 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ | |
310 | 0x01, 0x02, 0x04, 0x08, | |
311 | 0x10, 0x20, 0x40, 0x80 /* walking one */ | |
312 | }; | |
313 | int i, error, status; | |
314 | ||
315 | status = 1; /* assume success */ | |
316 | ||
317 | if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { | |
e3869ec7 | 318 | kprintf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); |
984263bc MD |
319 | status = 0; |
320 | goto end_probe; | |
321 | } | |
322 | ||
323 | for (i = 0; i < 18 && status; i++) | |
324 | if (!lpt_port_test(ppbus, testbyte[i], 0xff)) { | |
325 | status = 0; | |
326 | goto end_probe; | |
327 | } | |
328 | ||
329 | end_probe: | |
330 | /* write 0's to control and data ports */ | |
331 | ppb_wdtr(ppbus, 0); | |
332 | ppb_wctr(ppbus, 0); | |
333 | ||
334 | lpt_release_ppbus(dev); | |
335 | ||
336 | return (status); | |
337 | } | |
338 | ||
984263bc MD |
339 | /* |
340 | * lpt_probe() | |
341 | */ | |
342 | static int | |
343 | lpt_probe(device_t dev) | |
344 | { | |
345 | struct lpt_data *sc; | |
346 | ||
347 | sc = DEVTOSOFTC(dev); | |
348 | bzero(sc, sizeof(struct lpt_data)); | |
349 | ||
350 | /* | |
351 | * Now, try to detect the printer. | |
352 | */ | |
353 | if (!lpt_detect(dev)) | |
354 | return (ENXIO); | |
355 | ||
356 | device_set_desc(dev, "Printer"); | |
357 | ||
358 | return (0); | |
359 | } | |
360 | ||
361 | static int | |
362 | lpt_attach(device_t dev) | |
363 | { | |
364 | device_t ppbus = device_get_parent(dev); | |
365 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
366 | int zero = 0, unit = device_get_unit(dev); | |
367 | int error; | |
368 | uintptr_t irq; | |
369 | ||
370 | sc->sc_primed = 0; /* not primed yet */ | |
6aed8a5b | 371 | callout_init(&sc->sc_callout); |
984263bc MD |
372 | |
373 | if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { | |
e3869ec7 | 374 | kprintf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); |
984263bc MD |
375 | return (0); |
376 | } | |
377 | ||
378 | ppb_wctr(ppbus, LPC_NINIT); | |
379 | ||
380 | /* check if we can use interrupt, should be done by ppc stuff */ | |
381 | lprintf(("oldirq %x\n", sc->sc_irq)); | |
382 | ||
383 | /* retrieve the ppbus irq */ | |
384 | BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); | |
385 | ||
386 | if (irq > 0) { | |
387 | /* declare our interrupt handler */ | |
388 | sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, | |
389 | &zero, irq, irq, 1, RF_SHAREABLE); | |
390 | } | |
391 | if (sc->intr_resource) { | |
392 | sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; | |
393 | device_printf(dev, "Interrupt-driven port\n"); | |
394 | } else { | |
395 | sc->sc_irq = 0; | |
396 | device_printf(dev, "Polled port\n"); | |
397 | } | |
398 | lprintf(("irq %x %x\n", irq, sc->sc_irq)); | |
399 | ||
400 | lpt_release_ppbus(dev); | |
401 | ||
3e82b46c MD |
402 | make_dev(&lpt_ops, unit, UID_ROOT, GID_WHEEL, |
403 | 0600, LPT_NAME "%d", unit); | |
404 | make_dev(&lpt_ops, unit | LP_BYPASS, UID_ROOT, GID_WHEEL, | |
405 | 0600, LPT_NAME "%d.ctl", unit); | |
984263bc MD |
406 | return (0); |
407 | } | |
408 | ||
409 | static void | |
410 | lptout(void *arg) | |
411 | { | |
412 | device_t dev = (device_t)arg; | |
413 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
414 | #ifdef LPT_DEBUG | |
415 | device_t ppbus = device_get_parent(dev); | |
416 | #endif | |
417 | ||
418 | lprintf(("T %x ", ppb_rstr(ppbus))); | |
419 | if (sc->sc_state & OPEN) { | |
420 | sc->sc_backoff++; | |
421 | if (sc->sc_backoff > hz/LPTOUTMAX) | |
422 | sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX; | |
6aed8a5b MD |
423 | callout_reset(&sc->sc_callout, sc->sc_backoff, lptout, dev); |
424 | } else { | |
984263bc | 425 | sc->sc_state &= ~TOUT; |
6aed8a5b | 426 | } |
984263bc MD |
427 | |
428 | if (sc->sc_state & EERROR) | |
429 | sc->sc_state &= ~EERROR; | |
430 | ||
431 | /* | |
432 | * Avoid possible hangs due to missed interrupts | |
433 | */ | |
434 | if (sc->sc_xfercnt) { | |
435 | lptintr(dev); | |
436 | } else { | |
437 | sc->sc_state &= ~OBUSY; | |
438 | wakeup((caddr_t)dev); | |
439 | } | |
440 | } | |
441 | ||
442 | /* | |
443 | * lptopen -- reset the printer, then wait until it's selected and not busy. | |
444 | * If LP_BYPASS flag is selected, then we do not try to select the | |
445 | * printer -- this is just used for passing ioctls. | |
446 | */ | |
447 | ||
448 | static int | |
fef8985e | 449 | lptopen(struct dev_open_args *ap) |
984263bc | 450 | { |
b13267a5 | 451 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
452 | int trys, err; |
453 | u_int unit = LPTUNIT(minor(dev)); | |
454 | struct lpt_data *sc = UNITOSOFTC(unit); | |
455 | device_t lptdev = UNITODEVICE(unit); | |
456 | device_t ppbus = device_get_parent(lptdev); | |
457 | ||
458 | if (!sc) | |
459 | return (ENXIO); | |
460 | ||
461 | if (sc->sc_state) { | |
462 | lprintf((LPT_NAME ": still open %x\n", sc->sc_state)); | |
463 | return(EBUSY); | |
464 | } else | |
465 | sc->sc_state |= LPTINIT; | |
466 | ||
467 | sc->sc_flags = LPTFLAGS(minor(dev)); | |
468 | ||
469 | /* Check for open with BYPASS flag set. */ | |
470 | if (sc->sc_flags & LP_BYPASS) { | |
471 | sc->sc_state = OPEN; | |
472 | return(0); | |
473 | } | |
474 | ||
475 | /* request the ppbus only if we don't have it already */ | |
476 | if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { | |
477 | /* give it a chance to try later */ | |
478 | sc->sc_state = 0; | |
479 | return (err); | |
480 | } | |
481 | ||
b28b340f | 482 | crit_enter(); |
984263bc MD |
483 | lprintf((LPT_NAME " flags 0x%x\n", sc->sc_flags)); |
484 | ||
485 | /* set IRQ status according to ENABLE_IRQ flag | |
486 | */ | |
487 | if (sc->sc_irq & LP_ENABLE_IRQ) | |
488 | sc->sc_irq |= LP_USE_IRQ; | |
489 | else | |
490 | sc->sc_irq &= ~LP_USE_IRQ; | |
491 | ||
492 | /* init printer */ | |
493 | if ((sc->sc_flags & LP_NO_PRIME) == 0) { | |
494 | if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { | |
495 | ppb_wctr(ppbus, 0); | |
496 | sc->sc_primed++; | |
497 | DELAY(500); | |
498 | } | |
499 | } | |
500 | ||
501 | ppb_wctr(ppbus, LPC_SEL|LPC_NINIT); | |
502 | ||
503 | /* wait till ready (printer running diagnostics) */ | |
504 | trys = 0; | |
505 | do { | |
506 | /* ran out of waiting for the printer */ | |
507 | if (trys++ >= LPINITRDY*4) { | |
b28b340f | 508 | crit_exit(); |
984263bc MD |
509 | sc->sc_state = 0; |
510 | lprintf(("status %x\n", ppb_rstr(ppbus))); | |
511 | ||
512 | lpt_release_ppbus(lptdev); | |
513 | return (EBUSY); | |
514 | } | |
515 | ||
516 | /* wait 1/4 second, give up if we get a signal */ | |
377d4740 | 517 | if (tsleep((caddr_t)lptdev, PCATCH, "lptinit", hz/4) != |
984263bc MD |
518 | EWOULDBLOCK) { |
519 | sc->sc_state = 0; | |
b28b340f | 520 | crit_exit(); |
984263bc MD |
521 | |
522 | lpt_release_ppbus(lptdev); | |
523 | return (EBUSY); | |
524 | } | |
525 | ||
526 | /* is printer online and ready for output */ | |
527 | } while ((ppb_rstr(ppbus) & | |
528 | (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != | |
529 | (LPS_SEL|LPS_NBSY|LPS_NERR)); | |
530 | ||
531 | sc->sc_control = LPC_SEL|LPC_NINIT; | |
532 | if (sc->sc_flags & LP_AUTOLF) | |
533 | sc->sc_control |= LPC_AUTOL; | |
534 | ||
535 | /* enable interrupt if interrupt-driven */ | |
536 | if (sc->sc_irq & LP_USE_IRQ) | |
537 | sc->sc_control |= LPC_ENA; | |
538 | ||
539 | ppb_wctr(ppbus, sc->sc_control); | |
540 | ||
541 | sc->sc_state = OPEN; | |
efda3bd0 MD |
542 | sc->sc_inbuf = kmalloc(BUFSIZE, M_LPT, M_WAITOK); |
543 | sc->sc_statbuf = kmalloc(BUFSTATSIZE, M_LPT, M_WAITOK); | |
984263bc | 544 | sc->sc_xfercnt = 0; |
b28b340f JS |
545 | |
546 | crit_exit(); | |
984263bc MD |
547 | |
548 | /* release the ppbus */ | |
549 | lpt_release_ppbus(lptdev); | |
550 | ||
551 | /* only use timeout if using interrupt */ | |
552 | lprintf(("irq %x\n", sc->sc_irq)); | |
553 | if (sc->sc_irq & LP_USE_IRQ) { | |
554 | sc->sc_state |= TOUT; | |
6aed8a5b MD |
555 | sc->sc_backoff = hz / LPTOUTINITIAL; |
556 | callout_reset(&sc->sc_callout, sc->sc_backoff, lptout, lptdev); | |
984263bc MD |
557 | } |
558 | ||
559 | lprintf(("opened.\n")); | |
560 | return(0); | |
561 | } | |
562 | ||
563 | /* | |
564 | * lptclose -- close the device, free the local line buffer. | |
565 | * | |
566 | * Check for interrupted write call added. | |
567 | */ | |
568 | ||
569 | static int | |
fef8985e | 570 | lptclose(struct dev_close_args *ap) |
984263bc | 571 | { |
b13267a5 | 572 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
573 | u_int unit = LPTUNIT(minor(dev)); |
574 | struct lpt_data *sc = UNITOSOFTC(unit); | |
575 | device_t lptdev = UNITODEVICE(unit); | |
576 | device_t ppbus = device_get_parent(lptdev); | |
577 | int err; | |
578 | ||
579 | if(sc->sc_flags & LP_BYPASS) | |
580 | goto end_close; | |
581 | ||
582 | if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) | |
583 | return (err); | |
584 | ||
585 | sc->sc_state &= ~OPEN; | |
586 | ||
587 | /* if the last write was interrupted, don't complete it */ | |
6aed8a5b | 588 | if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) { |
984263bc | 589 | while ((ppb_rstr(ppbus) & |
6aed8a5b MD |
590 | (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != |
591 | (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) { | |
984263bc | 592 | /* wait 1/4 second, give up if we get a signal */ |
377d4740 | 593 | if (tsleep((caddr_t)lptdev, PCATCH, |
6aed8a5b | 594 | "lpclose", hz) != EWOULDBLOCK) { |
984263bc | 595 | break; |
6aed8a5b MD |
596 | } |
597 | } | |
598 | } | |
599 | callout_stop(&sc->sc_callout); | |
984263bc | 600 | ppb_wctr(ppbus, LPC_NINIT); |
efda3bd0 MD |
601 | kfree(sc->sc_inbuf, M_LPT); |
602 | kfree(sc->sc_statbuf, M_LPT); | |
984263bc MD |
603 | |
604 | end_close: | |
605 | /* release the bus anyway | |
606 | * unregistration of interrupt forced by release | |
607 | */ | |
608 | lpt_release_ppbus(lptdev); | |
609 | ||
610 | sc->sc_state = 0; | |
611 | sc->sc_xfercnt = 0; | |
612 | lprintf(("closed.\n")); | |
613 | return(0); | |
614 | } | |
615 | ||
616 | /* | |
617 | * lpt_pushbytes() | |
618 | * Workhorse for actually spinning and writing bytes to printer | |
619 | * Derived from lpa.c | |
620 | * Originally by ? | |
621 | * | |
622 | * This code is only used when we are polling the port | |
623 | */ | |
624 | static int | |
625 | lpt_pushbytes(device_t dev) | |
626 | { | |
627 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
628 | device_t ppbus = device_get_parent(dev); | |
629 | int spin, err, tic; | |
630 | char ch; | |
631 | ||
632 | lprintf(("p")); | |
633 | /* loop for every character .. */ | |
634 | while (sc->sc_xfercnt > 0) { | |
635 | /* printer data */ | |
636 | ch = *(sc->sc_cp); | |
637 | sc->sc_cp++; | |
638 | sc->sc_xfercnt--; | |
639 | ||
640 | /* | |
641 | * Wait for printer ready. | |
642 | * Loop 20 usecs testing BUSY bit, then sleep | |
643 | * for exponentially increasing timeout. (vak) | |
644 | */ | |
645 | for (spin = 0; NOT_READY(ppbus) && spin < MAX_SPIN; ++spin) | |
646 | DELAY(1); /* XXX delay is NOT this accurate! */ | |
647 | if (spin >= MAX_SPIN) { | |
648 | tic = 0; | |
649 | while (NOT_READY(ppbus)) { | |
650 | /* | |
651 | * Now sleep, every cycle a | |
652 | * little longer .. | |
653 | */ | |
654 | tic = tic + tic + 1; | |
655 | /* | |
656 | * But no more than 10 seconds. (vak) | |
657 | */ | |
658 | if (tic > MAX_SLEEP) | |
659 | tic = MAX_SLEEP; | |
377d4740 | 660 | err = tsleep((caddr_t)dev, 0, |
984263bc MD |
661 | LPT_NAME "poll", tic); |
662 | if (err != EWOULDBLOCK) { | |
663 | return (err); | |
664 | } | |
665 | } | |
666 | } | |
667 | ||
668 | /* output data */ | |
669 | ppb_wdtr(ppbus, ch); | |
670 | /* strobe */ | |
671 | ppb_wctr(ppbus, sc->sc_control|LPC_STB); | |
672 | ppb_wctr(ppbus, sc->sc_control); | |
673 | ||
674 | } | |
675 | return(0); | |
676 | } | |
677 | ||
678 | /* | |
679 | * lptread --retrieve printer status in IEEE1284 NIBBLE mode | |
680 | */ | |
681 | ||
682 | static int | |
fef8985e | 683 | lptread(struct dev_read_args *ap) |
984263bc | 684 | { |
b13267a5 | 685 | cdev_t dev = ap->a_head.a_dev; |
fef8985e | 686 | struct uio *uio = ap->a_uio; |
984263bc MD |
687 | u_int unit = LPTUNIT(minor(dev)); |
688 | struct lpt_data *sc = UNITOSOFTC(unit); | |
689 | device_t lptdev = UNITODEVICE(unit); | |
690 | device_t ppbus = device_get_parent(lptdev); | |
691 | int error = 0, len; | |
692 | ||
693 | if (sc->sc_flags & LP_BYPASS) { | |
694 | /* we can't do reads in bypass mode */ | |
695 | return (EPERM); | |
696 | } | |
697 | ||
698 | if ((error = ppb_1284_negociate(ppbus, PPB_NIBBLE, 0))) | |
699 | return (error); | |
700 | ||
701 | /* read data in an other buffer, read/write may be simultaneous */ | |
702 | len = 0; | |
703 | while (uio->uio_resid) { | |
e54488bb MD |
704 | error = ppb_1284_read(ppbus, PPB_NIBBLE, sc->sc_statbuf, |
705 | (int)szmin(BUFSTATSIZE, uio->uio_resid), | |
706 | len); | |
707 | if (error) | |
984263bc | 708 | goto error; |
984263bc MD |
709 | |
710 | if (!len) | |
711 | goto error; /* no more data */ | |
712 | ||
e54488bb | 713 | if ((error = uiomove(sc->sc_statbuf, (size_t)len, uio))) |
984263bc MD |
714 | goto error; |
715 | } | |
716 | ||
717 | error: | |
718 | ppb_1284_terminate(ppbus); | |
719 | return (error); | |
720 | } | |
721 | ||
722 | /* | |
723 | * lptwrite --copy a line from user space to a local buffer, then call | |
724 | * putc to get the chars moved to the output queue. | |
725 | * | |
726 | * Flagging of interrupted write added. | |
727 | */ | |
728 | ||
729 | static int | |
fef8985e | 730 | lptwrite(struct dev_write_args *ap) |
984263bc | 731 | { |
b13267a5 | 732 | cdev_t dev = ap->a_head.a_dev; |
fef8985e | 733 | struct uio *uio = ap->a_uio; |
f96d6c88 | 734 | unsigned n; |
984263bc MD |
735 | int err; |
736 | u_int unit = LPTUNIT(minor(dev)); | |
737 | struct lpt_data *sc = UNITOSOFTC(unit); | |
738 | device_t lptdev = UNITODEVICE(unit); | |
739 | device_t ppbus = device_get_parent(lptdev); | |
740 | ||
741 | if(sc->sc_flags & LP_BYPASS) { | |
742 | /* we can't do writes in bypass mode */ | |
743 | return(EPERM); | |
744 | } | |
745 | ||
746 | /* request the ppbus only if we don't have it already */ | |
747 | /* XXX interrupt registration?! */ | |
748 | if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) | |
749 | return (err); | |
750 | ||
751 | /* if interrupts are working, register the handler */ | |
752 | if (sc->sc_irq & LP_USE_IRQ) { | |
753 | /* register our interrupt handler */ | |
754 | err = BUS_SETUP_INTR(ppbus, lptdev, sc->intr_resource, | |
ee61f228 | 755 | 0, lpt_intr, lptdev, |
e9cb6d99 | 756 | &sc->intr_cookie, NULL); |
984263bc MD |
757 | if (err) { |
758 | device_printf(lptdev, "handler registration failed, polled mode.\n"); | |
759 | sc->sc_irq &= ~LP_USE_IRQ; | |
760 | } | |
761 | } | |
762 | ||
763 | sc->sc_state &= ~INTERRUPTED; | |
e54488bb | 764 | while ((n = (unsigned)szmin(BUFSIZE, uio->uio_resid)) != 0) { |
984263bc | 765 | sc->sc_cp = sc->sc_inbuf; |
e54488bb | 766 | uiomove(sc->sc_cp, (size_t)n, uio); |
984263bc MD |
767 | sc->sc_xfercnt = n ; |
768 | ||
769 | if (sc->sc_irq & LP_ENABLE_EXT) { | |
770 | /* try any extended mode */ | |
771 | err = ppb_write(ppbus, sc->sc_cp, | |
772 | sc->sc_xfercnt, 0); | |
773 | switch (err) { | |
774 | case 0: | |
775 | /* if not all data was sent, we could rely | |
776 | * on polling for the last bytes */ | |
777 | sc->sc_xfercnt = 0; | |
778 | break; | |
779 | case EINTR: | |
780 | sc->sc_state |= INTERRUPTED; | |
781 | return(err); | |
782 | case EINVAL: | |
783 | /* advanced mode not avail */ | |
784 | log(LOG_NOTICE, LPT_NAME "%d: advanced mode not avail, polling\n", unit); | |
785 | break; | |
786 | default: | |
787 | return(err); | |
788 | } | |
789 | } else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { | |
790 | lprintf(("i")); | |
791 | /* if the printer is ready for a char, */ | |
792 | /* give it one */ | |
793 | if ((sc->sc_state & OBUSY) == 0){ | |
794 | lprintf(("\nC %d. ", sc->sc_xfercnt)); | |
795 | lptintr(lptdev); | |
796 | } | |
797 | lprintf(("W ")); | |
798 | if (sc->sc_state & OBUSY) | |
799 | if ((err = tsleep((caddr_t)lptdev, | |
377d4740 | 800 | PCATCH, LPT_NAME "write", 0))) { |
984263bc MD |
801 | sc->sc_state |= INTERRUPTED; |
802 | return(err); | |
803 | } | |
804 | } | |
805 | ||
806 | /* check to see if we must do a polled write */ | |
807 | if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { | |
808 | lprintf(("p")); | |
809 | ||
810 | err = lpt_pushbytes(lptdev); | |
811 | ||
812 | if (err) | |
813 | return(err); | |
814 | } | |
815 | } | |
816 | ||
817 | /* we have not been interrupted, release the ppbus */ | |
818 | lpt_release_ppbus(lptdev); | |
819 | ||
820 | return(0); | |
821 | } | |
822 | ||
823 | /* | |
824 | * lpt_intr -- handle printer interrupts which occur when the printer is | |
825 | * ready to accept another char. | |
826 | * | |
827 | * do checking for interrupted write call. | |
828 | */ | |
829 | ||
830 | static void | |
831 | lpt_intr(void *arg) | |
832 | { | |
833 | device_t lptdev = (device_t)arg; | |
834 | device_t ppbus = device_get_parent(lptdev); | |
835 | struct lpt_data *sc = DEVTOSOFTC(lptdev); | |
836 | int sts = 0; | |
837 | int i; | |
838 | ||
839 | /* we must own the bus to use it */ | |
840 | if ((sc->sc_state & HAVEBUS) == 0) | |
841 | return; | |
842 | ||
843 | /* | |
844 | * Is printer online and ready for output? | |
845 | * | |
846 | * Avoid falling back to lptout() too quickly. First spin-loop | |
847 | * to see if the printer will become ready ``really soon now''. | |
848 | */ | |
849 | for (i = 0; i < 100 && | |
850 | ((sts=ppb_rstr(ppbus)) & RDY_MASK) != LP_READY; i++) ; | |
851 | ||
852 | if ((sts & RDY_MASK) == LP_READY) { | |
853 | sc->sc_state = (sc->sc_state | OBUSY) & ~EERROR; | |
854 | sc->sc_backoff = hz/LPTOUTINITIAL; | |
855 | ||
856 | if (sc->sc_xfercnt) { | |
857 | /* send char */ | |
858 | /*lprintf(("%x ", *sc->sc_cp)); */ | |
859 | ppb_wdtr(ppbus, *sc->sc_cp++) ; | |
860 | ppb_wctr(ppbus, sc->sc_control|LPC_STB); | |
861 | /* DELAY(X) */ | |
862 | ppb_wctr(ppbus, sc->sc_control); | |
863 | ||
864 | /* any more data for printer */ | |
865 | if(--(sc->sc_xfercnt) > 0) return; | |
866 | } | |
867 | ||
868 | /* | |
869 | * No more data waiting for printer. | |
870 | * Wakeup is not done if write call was not interrupted. | |
871 | */ | |
872 | sc->sc_state &= ~OBUSY; | |
873 | ||
874 | if(!(sc->sc_state & INTERRUPTED)) | |
875 | wakeup((caddr_t)lptdev); | |
876 | lprintf(("w ")); | |
877 | return; | |
878 | } else { /* check for error */ | |
879 | if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) && | |
880 | (sc->sc_state & OPEN)) | |
881 | sc->sc_state |= EERROR; | |
882 | /* lptout() will jump in and try to restart. */ | |
883 | } | |
884 | lprintf(("sts %x ", sts)); | |
885 | } | |
886 | ||
887 | static void | |
888 | lptintr(device_t dev) | |
889 | { | |
890 | /* call the interrupt at required spl level */ | |
b28b340f | 891 | crit_enter(); |
984263bc MD |
892 | |
893 | lpt_intr(dev); | |
894 | ||
b28b340f | 895 | crit_exit(); |
984263bc MD |
896 | } |
897 | ||
898 | static int | |
fef8985e | 899 | lptioctl(struct dev_ioctl_args *ap) |
984263bc | 900 | { |
b13267a5 | 901 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
902 | int error = 0; |
903 | u_int unit = LPTUNIT(minor(dev)); | |
904 | struct lpt_data *sc = UNITOSOFTC(unit); | |
905 | u_char old_sc_irq; /* old printer IRQ status */ | |
906 | ||
fef8985e | 907 | switch (ap->a_cmd) { |
984263bc MD |
908 | case LPT_IRQ : |
909 | if(sc->sc_irq & LP_HAS_IRQ) { | |
910 | /* | |
911 | * NOTE: | |
912 | * If the IRQ status is changed, | |
913 | * this will only be visible on the | |
914 | * next open. | |
915 | * | |
916 | * If interrupt status changes, | |
917 | * this gets syslog'd. | |
918 | */ | |
919 | old_sc_irq = sc->sc_irq; | |
fef8985e | 920 | switch(*(int*)ap->a_data) { |
984263bc MD |
921 | case 0: |
922 | sc->sc_irq &= (~LP_ENABLE_IRQ); | |
923 | break; | |
924 | case 1: | |
925 | sc->sc_irq &= (~LP_ENABLE_EXT); | |
926 | sc->sc_irq |= LP_ENABLE_IRQ; | |
927 | break; | |
928 | case 2: | |
929 | /* classic irq based transfer and advanced | |
930 | * modes are in conflict | |
931 | */ | |
932 | sc->sc_irq &= (~LP_ENABLE_IRQ); | |
933 | sc->sc_irq |= LP_ENABLE_EXT; | |
934 | break; | |
935 | case 3: | |
936 | sc->sc_irq &= (~LP_ENABLE_EXT); | |
937 | break; | |
938 | default: | |
939 | break; | |
940 | } | |
941 | ||
942 | if (old_sc_irq != sc->sc_irq ) | |
943 | log(LOG_NOTICE, LPT_NAME "%d: switched to %s %s mode\n", | |
944 | unit, | |
945 | (sc->sc_irq & LP_ENABLE_IRQ)? | |
946 | "interrupt-driven":"polled", | |
947 | (sc->sc_irq & LP_ENABLE_EXT)? | |
948 | "extended":"standard"); | |
949 | } else /* polled port */ | |
950 | error = EOPNOTSUPP; | |
951 | break; | |
952 | default: | |
953 | error = ENODEV; | |
954 | } | |
955 | ||
956 | return(error); | |
957 | } | |
958 | ||
39b5d600 MD |
959 | /* |
960 | * Because lpt is a static device that always exists under a ppbus device, | |
961 | * and not scanned by the ppbus device, we need an identify function to | |
962 | * install its device. | |
963 | */ | |
984263bc MD |
964 | static device_method_t lpt_methods[] = { |
965 | /* device interface */ | |
39b5d600 | 966 | DEVMETHOD(device_identify, bus_generic_identify), |
984263bc MD |
967 | DEVMETHOD(device_probe, lpt_probe), |
968 | DEVMETHOD(device_attach, lpt_attach), | |
969 | ||
970 | { 0, 0 } | |
971 | }; | |
972 | ||
973 | static driver_t lpt_driver = { | |
974 | LPT_NAME, | |
975 | lpt_methods, | |
976 | sizeof(struct lpt_data), | |
977 | }; | |
978 | ||
979 | DRIVER_MODULE(lpt, ppbus, lpt_driver, lpt_devclass, 0, 0); | |
39b5d600 | 980 |