|
|
1.1 ! root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.