Home | History | Annotate | Line # | Download | only in ic
lptvar.h revision 1.1
      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  */
     49  */
     50 
     51 /*
     52  * Device Driver for AT parallel printer port
     53  * Written by William Jolitz 12/18/90
     54  */
     55 
     56 #include "lpt.h"
     57 #if NLPT > 0
     58 
     59 #include "param.h"
     60 #include "user.h"
     61 #include "buf.h"
     62 #include "systm.h"
     63 #include "kernel.h"
     64 #include "ioctl.h"
     65 #include "tty.h"
     66 #include "uio.h"
     67 
     68 #include "i386/isa/isa_device.h"
     69 #include "i386/isa/lptreg.h"
     70 
     71 #define	LPINITRDY	4	/* wait up to 4 seconds for a ready */
     72 #define	LPTOUTTIME	4	/* wait up to 4 seconds for a ready */
     73 #define	LPPRI		(PZERO+8)
     74 #define	BUFSIZE		1024
     75 
     76 #ifndef DEBUG
     77 #define lprintf
     78 #else
     79 #define lprintf		if (lpflag) printf
     80 #endif
     81 
     82 int lptout();
     83 #ifdef DEBUG
     84 int lpflag = 1;
     85 #endif
     86 
     87 int 	lptprobe(), lptattach(), lptintr();
     88 
     89 struct	isa_driver lptdriver = {
     90 	lptprobe, lptattach, "lpt"
     91 };
     92 
     93 #define	LPTUNIT(s)	(((s)>>6)&0x3)
     94 #define	LPTFLAGS(s)	((s)&0x3f)
     95 
     96 struct lpt_softc {
     97 	short	sc_port;
     98 	short	sc_state;
     99 	/* default case: negative prime, negative ack, handshake strobe,
    100 	   prime once */
    101 	u_char	sc_control;
    102 	char	sc_flags;
    103 #define LP_POS_INIT	0x01	/* if we are a postive init signal */
    104 #define LP_POS_ACK	0x02	/* if we are a positive going ack */
    105 #define LP_NO_PRIME	0x04	/* don't prime the printer at all */
    106 #define LP_PRIMEOPEN	0x08	/* prime on every open */
    107 #define LP_AUTOLF	0x10	/* tell printer to do an automatic lf */
    108 #define LP_BYPASS	0x20	/* bypass  printer ready checks */
    109 	struct	buf *sc_inbuf;
    110 	short	sc_xfercnt ;
    111 	char	sc_primed;
    112 	char	*sc_cp ;
    113 } lpt_sc[NLPT] ;
    114 
    115 /* bits for state */
    116 #define	OPEN		(1<<0)	/* device is open */
    117 #define	ASLP		(1<<1)	/* awaiting draining of printer */
    118 #define	ERROR		(1<<2)	/* error was received from printer */
    119 #define	OBUSY		(1<<3)	/* printer is busy doing output */
    120 #define LPTOUT		(1<<4)	/* timeout while not selected	*/
    121 #define TOUT		(1<<5)	/* timeout while not selected	*/
    122 #define INIT		(1<<6)	/* waiting to initialize for open */
    123 
    124 lptprobe(idp)
    125 	struct isa_device *idp;
    126 {	unsigned v;
    127 
    128 	outb(idp->id_iobase+lpt_status,0xf0);
    129 	v = inb(idp->id_iobase+lpt_status);
    130 	outb(idp->id_iobase+lpt_status,0);
    131 	if (inb(idp->id_iobase+lpt_status) == v) {
    132 		outb(idp->id_iobase+lpt_control,0xff);
    133 		DELAY(100);
    134 		if (inb(idp->id_iobase+lpt_control) != 0xff)
    135 			return(0);
    136 		outb(idp->id_iobase+lpt_control,0);
    137 		DELAY(100);
    138 		if (inb(idp->id_iobase+lpt_control) != 0xe0)
    139 			return(0);
    140 		return(1);
    141 	}
    142 	return(0);
    143 }
    144 
    145 lptattach(isdp)
    146 	struct isa_device *isdp;
    147 {
    148 	struct	lpt_softc	*sc;
    149 
    150 	sc = lpt_sc + isdp->id_unit;
    151 	sc->sc_port = isdp->id_iobase;
    152 	outb(sc->sc_port+lpt_control, LPC_NINIT);
    153 	return (1);
    154 }
    155 
    156 /*
    157  * lptopen -- reset the printer, then wait until it's selected and not busy.
    158  */
    159 
    160 lptopen(dev, flag)
    161 	dev_t dev;
    162 	int flag;
    163 {
    164 	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
    165 	int s;
    166 	int trys, port;
    167 
    168 	if (sc->sc_state) {
    169 lprintf("lp: still open\n") ;
    170 printf("still open %x\n", sc->sc_state);
    171 		return(EBUSY);
    172 	} else	sc->sc_state |= INIT;
    173 
    174 	s = spltty();
    175 	sc->sc_flags = LPTFLAGS(minor(dev));
    176 lprintf("lp flags 0x%x\n", sc->sc_flags);
    177 	port = sc->sc_port;
    178 
    179 	/* init printer */
    180 	if((sc->sc_flags & LP_NO_PRIME) == 0) {
    181 		if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
    182 			outb(port+lpt_control, 0);
    183 			sc->sc_primed++;
    184 			DELAY(500);
    185 		}
    186 	}
    187 	outb(port+lpt_control, LPC_SEL|LPC_NINIT);
    188 
    189 	/* wait till ready (printer running diagnostics) */
    190 	trys = 0;
    191 	do {
    192 		/* ran out of waiting for the printer */
    193 		if (trys++ >= LPINITRDY*4) {
    194 			splx(s);
    195 			sc->sc_state = 0;
    196 printf ("status %x\n", inb(port+lpt_status) );
    197 			return (EBUSY);
    198 		}
    199 
    200 		/* wait 1/4 second, give up if we get a signal */
    201 		if (tsleep (sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) {
    202 			sc->sc_state = 0;
    203 			splx(s);
    204 			return (EBUSY);
    205 		}
    206 
    207 		/* is printer online and ready for output */
    208 	} while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
    209 			(LPS_SEL|LPS_NBSY|LPS_NERR));
    210 
    211 	if(sc->sc_flags&LP_AUTOLF) {
    212 		outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL);
    213 		sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL;
    214 	} else {
    215 		outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA);
    216 		sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA;
    217 	}
    218 
    219 	sc->sc_state = OPEN | TOUT;
    220 	sc->sc_inbuf = geteblk(BUFSIZE);
    221 	sc->sc_xfercnt = 0;
    222 	splx(s);
    223 	timeout (lptout, sc, hz/2);
    224 lprintf("opened.\n");
    225 	return(0);
    226 }
    227 
    228 lptout (sc)
    229 	struct lpt_softc *sc;
    230 {	int pl;
    231 
    232 lprintf ("T %x ", inb(sc->sc_port+lpt_status));
    233 	if (sc->sc_state&OPEN)
    234 		timeout (lptout, sc, hz/2);
    235 	else	sc->sc_state &= ~TOUT;
    236 
    237 	if (sc->sc_state & ERROR)
    238 		sc->sc_state &= ~ERROR;
    239 
    240 	/*
    241 	 * Avoid possible hangs do to missed interrupts
    242 	 */
    243 	if (sc->sc_xfercnt) {
    244 		pl = spltty();
    245 		lptintr(sc - lpt_sc);
    246 		splx(pl);
    247 	} else {
    248 		sc->sc_state &= ~OBUSY;
    249 		wakeup((caddr_t)sc);
    250 	}
    251 }
    252 
    253 /*
    254  * lptclose -- close the device, free the local line buffer.
    255  */
    256 
    257 lptclose(dev, flag)
    258 	int flag;
    259 {
    260 	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
    261 	int port = sc->sc_port;
    262 
    263 	sc->sc_state &= ~OPEN;
    264 	while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
    265 			(LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
    266 		/* wait 1/4 second, give up if we get a signal */
    267 		if (tsleep (sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK)
    268 			break;
    269 
    270 	sc->sc_state = 0;
    271 	sc->sc_xfercnt = 0;
    272 	outb(sc->sc_port+lpt_control, LPC_NINIT);
    273 	brelse(sc->sc_inbuf);
    274 lprintf("closed.\n");
    275 	return(0);
    276 }
    277 
    278 /*
    279  * lptwrite --copy a line from user space to a local buffer, then call
    280  * putc to get the chars moved to the output queue.
    281  */
    282 
    283 lptwrite(dev, uio)
    284 	dev_t dev;
    285 	struct uio *uio;
    286 {
    287 	register unsigned n;
    288 	int pl, err;
    289 	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
    290 
    291 	while (n = MIN(BUFSIZE, uio->uio_resid)) {
    292 		sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
    293 		uiomove(sc->sc_cp, n, uio);
    294 		sc->sc_xfercnt = n ;
    295 		while (sc->sc_xfercnt > 0) {
    296 			/* if the printer is ready for a char, give it one */
    297 			if ((sc->sc_state & OBUSY) == 0){
    298 lprintf("\nC %d. ", sc->sc_xfercnt);
    299 				pl = spltty();
    300 				lptintr(sc - lpt_sc);
    301 				(void) splx(pl);
    302 			}
    303 lprintf("W ");
    304 			if (err = tsleep (sc, LPPRI|PCATCH, "lpwrite", 0))
    305 				return(err);
    306 		}
    307 	}
    308 	return(0);
    309 }
    310 
    311 /*
    312  * lptintr -- handle printer interrupts which occur when the printer is
    313  * ready to accept another char.
    314  */
    315 
    316 lptintr(unit)
    317 {
    318 	struct lpt_softc *sc = lpt_sc + unit;
    319 	int port = sc->sc_port,sts;
    320 
    321 	/* is printer online and ready for output */
    322 	if (((sts=inb(port+lpt_status)) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) ==
    323 			(LPS_SEL|LPS_NBSY|LPS_NERR)) {
    324 			/* is this a false interrupt ? */
    325 			if ((sc->sc_state & OBUSY)
    326 				&& (sts & LPS_NACK) == 0) return;
    327 		sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR;
    328 
    329 		if (sc->sc_xfercnt) {
    330 			/* send char */
    331 /*lprintf("%x ", *sc->sc_cp); */
    332 			outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ;
    333 			outb(port+lpt_control, sc->sc_control|LPC_STB);
    334 			/* DELAY(X) */
    335 			outb(port+lpt_control, sc->sc_control);
    336 		}
    337 
    338 		/* any more bytes for the printer? */
    339 		if (sc->sc_xfercnt > 0) return;
    340 
    341 		/* none, wake up the top half to get more */
    342 		sc->sc_state &= ~OBUSY;
    343 		wakeup((caddr_t)sc);
    344 lprintf("w ");
    345 return;
    346 	} else	sc->sc_state |= ERROR;
    347 lprintf("sts %x ", sts);
    348 }
    349 
    350 #endif NLP
    351