1 /* $NetBSD: lpt.c,v 1.77 2009/11/23 02:13:46 rmind Exp $ */
4 * Copyright (c) 1993, 1994 Charles M. Hannum.
5 * Copyright (c) 1990 William F. Jolitz, TeleMuse
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This software is a component of "386BSD" developed by
19 * William F. Jolitz, TeleMuse.
20 * 4. Neither the name of the developer nor the name "386BSD"
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
25 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
26 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
27 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
28 * NOT MAKE USE OF THIS WORK.
30 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
31 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
32 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
33 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
34 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
35 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
36 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
37 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
39 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * Device Driver for AT style parallel printer port
56 #include <sys/cdefs.h>
57 __KERNEL_RCSID(0, "$NetBSD: lpt.c,v 1.77 2009/11/23 02:13:46 rmind Exp $");
59 #include <sys/param.h>
60 #include <sys/systm.h>
62 #include <sys/malloc.h>
63 #include <sys/kernel.h>
64 #include <sys/ioctl.h>
66 #include <sys/device.h>
68 #include <sys/syslog.h>
73 #include <dev/ic/lptreg.h>
74 #include <dev/ic/lptvar.h>
76 #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
79 #define LPTPRI (PZERO+8)
80 #define LPT_BSIZE 1024
87 #define LPRINTF(a) if (lptdebug) printf a
91 extern struct cfdriver lpt_cd
;
93 dev_type_open(lptopen
);
94 dev_type_close(lptclose
);
95 dev_type_write(lptwrite
);
96 dev_type_ioctl(lptioctl
);
98 const struct cdevsw lpt_cdevsw
= {
99 lptopen
, lptclose
, noread
, lptwrite
, lptioctl
,
100 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
103 #define LPTUNIT(s) (minor(s) & 0x1f)
104 #define LPTFLAGS(s) (minor(s) & 0xe0)
106 static void lptsoftintr(void *);
109 lpt_attach_subr(struct lpt_softc
*sc
)
112 bus_space_handle_t ioh
;
119 bus_space_write_1(iot
, ioh
, lpt_control
, LPC_NINIT
);
121 callout_init(&sc
->sc_wakeup_ch
, 0);
122 sc
->sc_sih
= softint_establish(SOFTINT_SERIAL
, lptsoftintr
, sc
);
128 lpt_detach_subr(device_t self
, int flags
)
130 struct lpt_softc
*sc
= device_private(self
);
133 softint_disestablish(sc
->sc_sih
);
134 callout_destroy(&sc
->sc_wakeup_ch
);
139 * Reset the printer, then wait until it's selected and not busy.
142 lptopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
144 u_char flags
= LPTFLAGS(dev
);
145 struct lpt_softc
*sc
;
147 bus_space_handle_t ioh
;
152 sc
= device_lookup_private(&lpt_cd
, LPTUNIT(dev
));
153 if (!sc
|| !sc
->sc_dev_ok
)
156 #if 0 /* XXX what to do? */
157 if (sc
->sc_irq
== IRQUNK
&& (flags
& LPT_NOINTR
) == 0)
163 aprint_verbose_dev(sc
->sc_dev
, "stat=0x%x not zero\n",
170 sc
->sc_state
= LPT_INIT
;
171 sc
->sc_flags
= flags
;
172 LPRINTF(("%s: open: flags=0x%x\n", device_xname(sc
->sc_dev
),
177 if ((flags
& LPT_NOPRIME
) == 0) {
178 /* assert INIT for 100 usec to start up printer */
179 bus_space_write_1(iot
, ioh
, lpt_control
, LPC_SELECT
);
183 control
= LPC_SELECT
| LPC_NINIT
;
184 bus_space_write_1(iot
, ioh
, lpt_control
, control
);
186 /* wait till ready (printer running diagnostics) */
187 for (spin
= 0; NOT_READY_ERR(); spin
+= STEP
) {
188 if (spin
>= TIMEOUT
) {
193 /* wait 1/4 second, give up if we get a signal */
194 error
= tsleep((void *)sc
, LPTPRI
| PCATCH
, "lptopen", STEP
);
195 if (error
!= EWOULDBLOCK
) {
201 if ((flags
& LPT_NOINTR
) == 0)
202 control
|= LPC_IENABLE
;
203 if (flags
& LPT_AUTOLF
)
204 control
|= LPC_AUTOLF
;
205 sc
->sc_control
= control
;
206 bus_space_write_1(iot
, ioh
, lpt_control
, control
);
208 sc
->sc_inbuf
= malloc(LPT_BSIZE
, M_DEVBUF
, M_WAITOK
);
210 sc
->sc_state
= LPT_OPEN
;
212 if ((sc
->sc_flags
& LPT_NOINTR
) == 0)
215 LPRINTF(("%s: opened\n", device_xname(sc
->sc_dev
)));
220 lptnotready(u_char status
, struct lpt_softc
*sc
)
224 status
= (status
^ LPS_INVERT
) & LPS_MASK
;
225 new = status
& ~sc
->sc_laststatus
;
226 sc
->sc_laststatus
= status
;
228 if (sc
->sc_state
& LPT_OPEN
) {
229 if (new & LPS_SELECT
)
231 "%s: offline\n", device_xname(sc
->sc_dev
));
232 else if (new & LPS_NOPAPER
)
234 "%s: out of paper\n", device_xname(sc
->sc_dev
));
235 else if (new & LPS_NERR
)
237 "%s: output error\n", device_xname(sc
->sc_dev
));
246 struct lpt_softc
*sc
= arg
;
253 callout_reset(&sc
->sc_wakeup_ch
, STEP
, lptwakeup
, sc
);
257 * Close the device, and free the local line buffer.
260 lptclose(dev_t dev
, int flag
, int mode
,
263 struct lpt_softc
*sc
=
264 device_lookup_private(&lpt_cd
, LPTUNIT(dev
));
265 bus_space_tag_t iot
= sc
->sc_iot
;
266 bus_space_handle_t ioh
= sc
->sc_ioh
;
269 (void) lptpushbytes(sc
);
271 if ((sc
->sc_flags
& LPT_NOINTR
) == 0)
272 callout_stop(&sc
->sc_wakeup_ch
);
274 bus_space_write_1(iot
, ioh
, lpt_control
, LPC_NINIT
);
276 bus_space_write_1(iot
, ioh
, lpt_control
, LPC_NINIT
);
277 free(sc
->sc_inbuf
, M_DEVBUF
);
279 LPRINTF(("%s: closed\n", device_xname(sc
->sc_dev
)));
284 lptpushbytes(struct lpt_softc
*sc
)
286 bus_space_tag_t iot
= sc
->sc_iot
;
287 bus_space_handle_t ioh
= sc
->sc_ioh
;
290 if (sc
->sc_flags
& LPT_NOINTR
) {
292 u_char control
= sc
->sc_control
;
294 while (sc
->sc_count
> 0) {
296 while (NOT_READY()) {
297 if (++spin
< sc
->sc_spinmax
)
300 /* adapt busy-wait algorithm */
302 while (NOT_READY_ERR()) {
303 /* exponential backoff */
307 error
= tsleep((void *)sc
,
308 LPTPRI
| PCATCH
, "lptpsh", tic
);
309 if (error
!= EWOULDBLOCK
)
315 bus_space_write_1(iot
, ioh
, lpt_data
, *sc
->sc_cp
++);
317 bus_space_write_1(iot
, ioh
, lpt_control
,
318 control
| LPC_STROBE
);
321 bus_space_write_1(iot
, ioh
, lpt_control
, control
);
324 /* adapt busy-wait algorithm */
325 if (spin
*2 + 16 < sc
->sc_spinmax
)
331 while (sc
->sc_count
> 0) {
332 /* if the printer is ready for a char, give it one */
333 if ((sc
->sc_state
& LPT_OBUSY
) == 0) {
334 LPRINTF(("%s: write %lu\n",
335 device_xname(sc
->sc_dev
),
336 (u_long
)sc
->sc_count
));
341 error
= tsleep((void *)sc
, LPTPRI
| PCATCH
,
351 * Copy a line from user space to a local buffer, then call putc to get the
352 * chars moved to the output queue.
355 lptwrite(dev_t dev
, struct uio
*uio
, int flags
)
357 struct lpt_softc
*sc
=
358 device_lookup_private(&lpt_cd
, LPTUNIT(dev
));
362 while ((n
= min(LPT_BSIZE
, uio
->uio_resid
)) != 0) {
363 uiomove(sc
->sc_cp
= sc
->sc_inbuf
, n
, uio
);
365 error
= lptpushbytes(sc
);
368 * Return accurate residual if interrupted or timed
371 uio
->uio_resid
+= sc
->sc_count
;
380 * Handle printer interrupts which occur when the printer is ready to accept
386 struct lpt_softc
*sc
= arg
;
387 bus_space_tag_t iot
= sc
->sc_iot
;
388 bus_space_handle_t ioh
= sc
->sc_ioh
;
391 if ((sc
->sc_state
& LPT_OPEN
) == 0)
395 /* is printer online and ready for output */
396 if (NOT_READY() && NOT_READY_ERR())
400 u_char control
= sc
->sc_control
;
402 bus_space_write_1(iot
, ioh
, lpt_data
, *sc
->sc_cp
++);
404 bus_space_write_1(iot
, ioh
, lpt_control
, control
| LPC_STROBE
);
407 bus_space_write_1(iot
, ioh
, lpt_control
, control
);
409 sc
->sc_state
|= LPT_OBUSY
;
411 sc
->sc_state
&= ~LPT_OBUSY
;
413 if (sc
->sc_count
== 0) {
414 /* none, wake up the top half to get more */
415 softint_schedule(sc
->sc_sih
);
422 lptsoftintr(void *cookie
)
429 lptioctl(dev_t dev
, u_long cmd
, void *data
,
430 int flag
, struct lwp
*l
)