|
|
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: * lpa.c,v 1.4 1993/06/05 22:58:29 cgd Exp ! 49: */ ! 50: ! 51: /* ! 52: * Device Driver for AT parallel printer port ! 53: * Written by William Jolitz 12/18/90 ! 54: * Modified to run without interrupts ! 55: * 92-08-19 Wolfgang Stanglmeier <[email protected]> ! 56: * Slight cleanup and reorganization, try to handle restarted syscalls ! 57: * 92-09-08 Andy Valencia <[email protected]> ! 58: * 93-04-08 Rodney W. Grimes <[email protected]> ! 59: * Converted to driver name lpa, shares lptreg.h with lpt.c, fixed probe ! 60: * so that it returns IO_LPTSIZE. Added dummy lpaioctl. Added my new ! 61: * probe code from lpt.c, as the one in here was crud. ! 62: */ ! 63: ! 64: #include "lpa.h" ! 65: #if NLPA > 0 ! 66: ! 67: #include "param.h" ! 68: #include "buf.h" ! 69: #include "systm.h" ! 70: #include "ioctl.h" ! 71: #include "tty.h" ! 72: #include "proc.h" ! 73: #include "user.h" ! 74: #include "uio.h" ! 75: #include "kernel.h" ! 76: #include "malloc.h" ! 77: ! 78: #include "i386/isa/isa.h" ! 79: #include "i386/isa/isa_device.h" ! 80: #include "i386/isa/lptreg.h" ! 81: ! 82: /* internal used flags */ ! 83: #define OPEN (0x01) /* device is open */ ! 84: #define INIT (0x02) /* device in open procedure */ ! 85: ! 86: /* flags from minor device */ ! 87: #define LPA_PRIME (0x20) /* prime printer on open */ ! 88: #define LPA_ERROR (0x10) /* log error conditions */ ! 89: ! 90: #define LPA_FLAG(x) ((x) & 0xfc) ! 91: #define LPA_UNIT(x) ((x) & 0x03) ! 92: ! 93: /* Printer Ready condition */ ! 94: #define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) ! 95: #define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) ! 96: #define NOT_READY() ((inb(sc->sc_stat)^LPS_INVERT)&LPS_MASK) ! 97: ! 98: /* tsleep priority */ ! 99: #define LPPRI ((PZERO+8) | PCATCH) ! 100: ! 101: /* debug flags */ ! 102: #ifndef DEBUG ! 103: #define lprintf ! 104: #else ! 105: #define lprintf if (lpaflag) printf ! 106: int lpaflag = 1; ! 107: #endif ! 108: ! 109: int lpaprobe(), lpaattach(); ! 110: struct isa_driver lpadriver = {lpaprobe, lpaattach, "lpa"}; ! 111: ! 112: /* ! 113: * copy usermode data into sysmode buffer ! 114: */ ! 115: #define BUFSIZE 1024 ! 116: ! 117: /* ! 118: ** Waittimes ! 119: */ ! 120: #define TIMEOUT (hz*16) /* Timeout while open device */ ! 121: #define LONG (hz* 1) /* Timesteps while open */ ! 122: ! 123: #define MAX_SPIN 255 /* max loop counter for busy wait */ ! 124: ! 125: struct lpa_softc { ! 126: char *sc_cp; /* current data to print */ ! 127: int sc_count; /* bytes queued in sc_inbuf */ ! 128: short sc_data; /* printer data port */ ! 129: short sc_stat; /* printer control port */ ! 130: short sc_ctrl; /* printer status port */ ! 131: u_char sc_flags; /* flags (open and internal) */ ! 132: u_char sc_unit; /* unit-number */ ! 133: u_char sc_smax; /* current max busy loop cnt */ ! 134: char /* buffer for data */ ! 135: *sc_inbuf; ! 136: } lpa_sc[NLPA]; ! 137: ! 138: /* ! 139: * Internal routine to lpaprobe to do port tests of one byte value ! 140: */ ! 141: int ! 142: lpa_port_test(short port, u_char data, u_char mask) ! 143: { ! 144: int temp, timeout; ! 145: ! 146: data = data & mask; ! 147: outb(port, data); ! 148: timeout = 100; ! 149: do ! 150: temp = inb(port) & mask; ! 151: while (temp != data && --timeout); ! 152: lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp); ! 153: return (temp == data); ! 154: } ! 155: ! 156: /* ! 157: * New lpaprobe routine written by Rodney W. Grimes, 3/25/1993 ! 158: * ! 159: * Logic: ! 160: * 1) You should be able to write to and read back the same value ! 161: * to the data port. Do an alternating zeros, alternating ones, ! 162: * walking zero, and walking one test to check for stuck bits. ! 163: * ! 164: * 2) You should be able to write to and read back the same value ! 165: * to the control port lower 5 bits, the upper 3 bits are reserved ! 166: * per the IBM PC technical reference manauls and different boards ! 167: * do different things with them. Do an alternating zeros, alternating ! 168: * ones, walking zero, and walking one test to check for stuck bits. ! 169: * ! 170: * Some printers drag the strobe line down when the are powered off ! 171: * so this bit has been masked out of the control port test. ! 172: * ! 173: * XXX Some printers may not like a fast pulse on init or strobe, I ! 174: * don't know at this point, if that becomes a problem these bits ! 175: * should be turned off in the mask byte for the control port test. ! 176: * ! 177: * 3) Set the data and control ports to a value of 0 ! 178: */ ! 179: ! 180: int ! 181: lpaprobe(struct isa_device *dvp) ! 182: { ! 183: int status; ! 184: short port; ! 185: u_char data; ! 186: u_char mask; ! 187: int i; ! 188: ! 189: status = IO_LPTSIZE; ! 190: ! 191: port = dvp->id_iobase + lpt_data; ! 192: mask = 0xff; ! 193: while (mask != 0) ! 194: { ! 195: data = 0x55; /* Alternating zeros */ ! 196: if (!lpa_port_test(port, data, mask)) status = 0; ! 197: ! 198: data = 0xaa; /* Alternating ones */ ! 199: if (!lpa_port_test(port, data, mask)) status = 0; ! 200: ! 201: for (i = 0; i < 8; i++) /* Walking zero */ ! 202: { ! 203: data = ~(1 << i); ! 204: if (!lpa_port_test(port, data, mask)) status = 0; ! 205: } ! 206: ! 207: for (i = 0; i < 8; i++) /* Walking one */ ! 208: { ! 209: data = (1 << i); ! 210: if (!lpa_port_test(port, data, mask)) status = 0; ! 211: } ! 212: ! 213: if (port == dvp->id_iobase + lpt_data) ! 214: { ! 215: port = dvp->id_iobase + lpt_control; ! 216: mask = 0x1e; ! 217: } ! 218: else ! 219: mask = 0; ! 220: } ! 221: outb(dvp->id_iobase+lpt_data, 0); ! 222: outb(dvp->id_iobase+lpt_control, 0); ! 223: return (status); ! 224: } ! 225: ! 226: /* ! 227: * lpaattach() ! 228: * Install device ! 229: */ ! 230: lpaattach(isdp) ! 231: struct isa_device *isdp; ! 232: { ! 233: struct lpa_softc *sc; ! 234: ! 235: sc = lpa_sc + isdp->id_unit; ! 236: sc->sc_unit = isdp->id_unit; ! 237: sc->sc_data = isdp->id_iobase + lpt_data; ! 238: sc->sc_stat = isdp->id_iobase + lpt_status; ! 239: sc->sc_ctrl = isdp->id_iobase + lpt_control; ! 240: outb(sc->sc_ctrl, LPC_NINIT); ! 241: return (1); ! 242: } ! 243: ! 244: /* ! 245: * lpaopen() ! 246: * New open on device. ! 247: * ! 248: * We forbid all but first open ! 249: */ ! 250: lpaopen(dev, flag) ! 251: dev_t dev; ! 252: int flag; ! 253: { ! 254: struct lpa_softc *sc; ! 255: int delay; /* slept time in 1/hz seconds of tsleep */ ! 256: int err; ! 257: u_char sta, unit; ! 258: ! 259: unit= LPA_UNIT(minor(dev)); ! 260: sta = LPA_FLAG(minor(dev)); ! 261: ! 262: /* minor number out of limits ? */ ! 263: if (unit >= NLPA) ! 264: return (ENXIO); ! 265: sc = lpa_sc + unit; ! 266: ! 267: /* Attached ? */ ! 268: if (!sc->sc_ctrl) { /* not attached */ ! 269: return(ENXIO); ! 270: } ! 271: ! 272: /* Printer busy ? */ ! 273: if (sc->sc_flags) { /* too late .. */ ! 274: return(EBUSY); ! 275: } ! 276: ! 277: /* Have memory for buffer? */ ! 278: sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); ! 279: if (sc->sc_inbuf == 0) ! 280: return(ENOMEM); ! 281: ! 282: /* Init printer */ ! 283: sc->sc_flags = sta | INIT; ! 284: if (sc->sc_flags & LPA_PRIME) { ! 285: outb(sc->sc_ctrl, 0); ! 286: } ! 287: ! 288: /* Select printer */ ! 289: outb(sc->sc_ctrl, LPC_SEL|LPC_NINIT); ! 290: ! 291: /* and wait for ready .. */ ! 292: for (delay=0; NOT_READY(); delay+= LONG) { ! 293: if (delay >= TIMEOUT) { /* too long waited .. */ ! 294: sc->sc_flags = 0; ! 295: return (EBUSY); ! 296: } ! 297: ! 298: /* sleep a moment */ ! 299: if ((err = tsleep (sc, LPPRI, "lpa: open", LONG)) != ! 300: EWOULDBLOCK) { ! 301: sc->sc_flags = 0; ! 302: return (EBUSY); ! 303: } ! 304: } ! 305: ! 306: /* Printer ready .. set variables */ ! 307: sc->sc_flags |= OPEN; ! 308: sc->sc_count = 0; ! 309: ! 310: return(0); ! 311: } ! 312: ! 313: /* ! 314: * pushbytes() ! 315: * Workhorse for actually spinning and writing bytes to printer ! 316: */ ! 317: static ! 318: pushbytes(sc) ! 319: struct lpa_softc *sc; ! 320: { ! 321: int spin, err, tic; ! 322: char ch; ! 323: ! 324: /* loop for every character .. */ ! 325: while (sc->sc_count > 0) { ! 326: /* printer data */ ! 327: ch = *(sc->sc_cp); ! 328: sc->sc_cp += 1; ! 329: sc->sc_count -= 1; ! 330: outb(sc->sc_data, ch); ! 331: ! 332: /* Busy wait for printer ready .. */ ! 333: spin = tic = 0; ! 334: while (NOT_READY()) { ! 335: if (++spin >= sc->sc_smax) { ! 336: /* ! 337: * Now sleep, every cycle a ! 338: * little longer .. ! 339: */ ! 340: tic = tic + tic + 1; ! 341: err = tsleep(sc, LPPRI, "lpa: write", tic); ! 342: if (err != EWOULDBLOCK) { ! 343: return (err); ! 344: } ! 345: } ! 346: } ! 347: ! 348: /* strobe */ ! 349: outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL|LPC_STB); ! 350: outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL); ! 351: ! 352: /* Adapt busy-wait length... */ ! 353: if (spin >= sc->sc_smax) { /* was sleep wait */ ! 354: if (sc->sc_smax<MAX_SPIN) ! 355: sc->sc_smax++; ! 356: } ! 357: if (spin*2 < sc->sc_smax) { ! 358: sc->sc_smax--; ! 359: } ! 360: } ! 361: return(0); ! 362: } ! 363: ! 364: /* ! 365: * lpaclose() ! 366: * Close on lp. Try to flush data in buffer out. ! 367: */ ! 368: lpaclose(dev, flag) ! 369: dev_t dev; ! 370: int flag; ! 371: { ! 372: struct lpa_softc *sc = lpa_sc + LPA_UNIT(minor(dev)); ! 373: ! 374: /* If there's queued data, try to flush it */ ! 375: (void)pushbytes(sc); ! 376: ! 377: /* really close .. quite simple :-) */ ! 378: outb(sc->sc_ctrl, LPC_NINIT); ! 379: sc->sc_flags = 0; ! 380: free(sc->sc_inbuf, M_DEVBUF); ! 381: sc->sc_inbuf = 0; /* Sanity */ ! 382: return(0); ! 383: } ! 384: ! 385: /* ! 386: * lpawrite() ! 387: * Copy from user's buffer, then print ! 388: */ ! 389: lpawrite(dev, uio) ! 390: dev_t dev; ! 391: struct uio *uio; ! 392: { ! 393: struct lpa_softc *sc = lpa_sc + LPA_UNIT(minor(dev)); ! 394: int err; ! 395: ! 396: /* Write out old bytes from interrupted syscall */ ! 397: if (sc->sc_count > 0) { ! 398: err = pushbytes(sc); ! 399: if (err) ! 400: return(err); ! 401: } ! 402: ! 403: /* main loop */ ! 404: while ((sc->sc_count = MIN(BUFSIZE, uio->uio_resid)) > 0) { ! 405: /* get from user-space */ ! 406: sc->sc_cp = sc->sc_inbuf; ! 407: uiomove(sc->sc_inbuf, sc->sc_count, uio); ! 408: err = pushbytes(sc); ! 409: if (err) ! 410: return(err); ! 411: } ! 412: return(0); ! 413: } ! 414: ! 415: int ! 416: lpaioctl(dev_t dev, int cmd, caddr_t data, int flag) ! 417: { ! 418: int error; ! 419: ! 420: error = 0; ! 421: switch (cmd) { ! 422: #ifdef THISISASAMPLE ! 423: case XXX: ! 424: dothis; andthis; andthat; ! 425: error=x; ! 426: break; ! 427: #endif /* THISISASAMPLE */ ! 428: default: ! 429: error = ENODEV; ! 430: } ! 431: ! 432: return(error); ! 433: } ! 434: ! 435: #endif /* NLPA > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.