Annotation of Net2/arch/i386/isa/lpa.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.