1 /* $NetBSD: lpt.c,v 1.31 2009/07/08 12:23:10 tsutsui Exp $ */
4 * Copyright (c) 1996 Leo Weppelman
5 * Copyright (c) 1993, 1994 Charles M. Hannum.
6 * Copyright (c) 1990 William F. Jolitz, TeleMuse
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This software is a component of "386BSD" developed by
20 * William F. Jolitz, TeleMuse.
21 * 4. Neither the name of the developer nor the name "386BSD"
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * Device Driver originally written for AT parallel printer port. Now
40 * drives the printer port on the YM2149.
42 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
43 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
44 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
45 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
46 * NOT MAKE USE OF THIS WORK.
48 * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
49 * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
50 * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
51 * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
52 * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
53 * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
54 * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
55 * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
58 #include <sys/cdefs.h>
59 __KERNEL_RCSID(0, "$NetBSD: lpt.c,v 1.31 2009/07/08 12:23:10 tsutsui Exp $");
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/callout.h>
66 #include <sys/kernel.h>
67 #include <sys/ioctl.h>
69 #include <sys/device.h>
71 #include <sys/syslog.h>
73 #include <machine/cpu.h>
74 #include <machine/iomap.h>
75 #include <machine/mfp.h>
76 #include <machine/intr.h>
78 #include <atari/dev/ym2149reg.h>
80 #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
83 #define LPTPRI (PZERO+8)
84 #define LPT_BSIZE 1024
86 #if !defined(DEBUG) || !defined(notdef)
87 #define lprintf if (0) aprint_error_dev
89 #define lprintf if (lptdebug) aprint_error_dev
95 struct callout sc_wakeup_ch
;
101 #define LPT_OPEN 0x01 /* device is open */
102 #define LPT_OBUSY 0x02 /* printer is busy doing output */
103 #define LPT_INIT 0x04 /* waiting to initialize for open */
105 #define LPT_AUTOLF 0x20 /* automatic LF on CR XXX: LWP - not yet... */
106 #define LPT_NOINTR 0x40 /* do not use interrupt */
109 #define LPTUNIT(s) (minor(s) & 0x1f)
110 #define LPTFLAGS(s) (minor(s) & 0xe0)
111 #define NOT_READY() (MFP->mf_gpip & IO_PBSY)
113 /* {b,c}devsw[] function prototypes */
114 dev_type_open(lpopen
);
115 dev_type_close(lpclose
);
116 dev_type_write(lpwrite
);
117 dev_type_ioctl(lpioctl
);
119 static void lptwakeup (void *arg
);
120 static int pushbytes (struct lpt_softc
*);
121 static void lptpseudointr (struct lpt_softc
*);
122 int lptintr (struct lpt_softc
*);
123 int lpthwintr (struct lpt_softc
*, int);
129 static void lpattach (device_t
, device_t
, void *);
130 static int lpmatch (device_t
, cfdata_t
, void *);
132 CFATTACH_DECL_NEW(lp
, sizeof(struct lpt_softc
),
133 lpmatch
, lpattach
, NULL
, NULL
);
135 extern struct cfdriver lp_cd
;
137 const struct cdevsw lp_cdevsw
= {
138 lpopen
, lpclose
, noread
, lpwrite
, lpioctl
,
139 nostop
, notty
, nopoll
, nommap
, nokqfilter
,
144 lpmatch(device_t pdp
, cfdata_t cfp
, void *auxp
)
146 static int lpt_matched
= 0;
148 /* Match at most 1 lpt unit */
149 if (strcmp((char *)auxp
, "lpt") || lpt_matched
)
157 lpattach(device_t pdp
, device_t dp
, void *auxp
)
159 struct lpt_softc
*sc
= device_private(dp
);
166 if (intr_establish(0, USER_VEC
, 0, (hw_ifun_t
)lpthwintr
, sc
) == NULL
)
167 aprint_error_dev(dp
, "Can't establish interrupt\n");
170 callout_init(&sc
->sc_wakeup_ch
, 0);
174 * Reset the printer, then wait until it's selected and not busy.
177 lpopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
179 u_char flags
= LPTFLAGS(dev
);
180 struct lpt_softc
*sc
;
185 sc
= device_lookup_private(&lp_cd
, LPTUNIT(dev
));
191 aprint_verbose_dev(sc
->sc_dev
, "stat=0x%x not zero\n",
198 sc
->sc_state
= LPT_INIT
;
199 sc
->sc_flags
= flags
;
200 lprintf(sc
->sc_dev
, "open: flags=0x%x\n", flags
);
202 /* wait till ready (printer running diagnostics) */
203 for (spin
= 0; NOT_READY(); spin
+= STEP
) {
204 if (spin
>= TIMEOUT
) {
209 /* wait 1/4 second, give up if we get a signal */
210 if ((error
= tsleep((void *)sc
, LPTPRI
| PCATCH
, "lptopen",
211 STEP
)) != EWOULDBLOCK
) {
217 sc
->sc_inbuf
= geteblk(LPT_BSIZE
);
219 sc
->sc_state
= LPT_OPEN
;
221 if ((sc
->sc_flags
& LPT_NOINTR
) == 0) {
225 MFP
->mf_imrb
|= IB_PBSY
;
226 MFP
->mf_ierb
|= IB_PBSY
;
230 lprintf(sc
->sc_dev
, "opened\n");
237 struct lpt_softc
*sc
= arg
;
241 callout_reset(&sc
->sc_wakeup_ch
, STEP
, lptwakeup
, sc
);
245 * Close the device, and free the local line buffer.
248 lpclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
250 struct lpt_softc
*sc
= device_lookup_private(&lp_cd
, LPTUNIT(dev
));
254 (void) pushbytes(sc
);
256 if ((sc
->sc_flags
& LPT_NOINTR
) == 0) {
257 callout_stop(&sc
->sc_wakeup_ch
);
260 MFP
->mf_ierb
&= ~IB_PBSY
;
261 MFP
->mf_imrb
&= ~IB_PBSY
;
266 brelse(sc
->sc_inbuf
, 0);
268 lprintf(sc
->sc_dev
, "closed\n");
273 pushbytes(struct lpt_softc
*sc
)
277 if (sc
->sc_flags
& LPT_NOINTR
) {
280 while (sc
->sc_count
> 0) {
282 while (NOT_READY()) {
283 if (++spin
< sc
->sc_spinmax
)
286 /* adapt busy-wait algorithm */
288 while (NOT_READY()) {
289 /* exponential backoff */
293 error
= tsleep((void *)sc
,
294 LPTPRI
| PCATCH
, "lptpsh", tic
);
295 if (error
!= EWOULDBLOCK
)
301 ym2149_write_ioport(YM_IOB
, *sc
->sc_cp
++);
306 /* adapt busy-wait algorithm */
307 if (spin
*2 + 16 < sc
->sc_spinmax
)
311 while (sc
->sc_count
> 0) {
312 /* if the printer is ready for a char, give it one */
313 if ((sc
->sc_state
& LPT_OBUSY
) == 0) {
314 lprintf(sc
->sc_dev
, "write %d\n",
316 (void) lptpseudointr(sc
);
318 if ((error
= tsleep((void *)sc
, LPTPRI
| PCATCH
,
319 "lptwrite2", 0)) != 0)
327 * Copy a line from user space to a local buffer, then call putc to get the
328 * chars moved to the output queue.
331 lpwrite(dev_t dev
, struct uio
*uio
, int flags
)
333 struct lpt_softc
*sc
= device_lookup_private(&lp_cd
,LPTUNIT(dev
));
337 while ((n
= min(LPT_BSIZE
, uio
->uio_resid
)) > 0) {
338 uiomove(sc
->sc_cp
= sc
->sc_inbuf
->b_data
, n
, uio
);
340 error
= pushbytes(sc
);
343 * Return accurate residual if interrupted or timed
346 uio
->uio_resid
+= sc
->sc_count
;
355 * Handle printer interrupts which occur when the printer is ready to accept
359 lptintr(struct lpt_softc
*sc
)
361 /* is printer online and ready for output */
368 ym2149_write_ioport(YM_IOB
, *sc
->sc_cp
++);
372 sc
->sc_state
|= LPT_OBUSY
;
374 sc
->sc_state
&= ~LPT_OBUSY
;
376 if (sc
->sc_count
== 0) {
377 /* none, wake up the top half to get more */
385 lptpseudointr(struct lpt_softc
*sc
)
395 lpthwintr(struct lpt_softc
*sc
, int sr
)
398 add_sicallback((si_farg
)lptpseudointr
, sc
, 0);
399 else lptpseudointr(sc
);
404 lpioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)