Annotation of coherent/b/kernel/io.386/lp386.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * This is a driver for PC parallel printers.
        !             3:  * It has been tested on an EPSON MX-80, Printronix P300, HP LaserJet II.
        !             4:  * Supports up to three line printers.
        !             5:  */
        !             6: #include <sys/coherent.h>
        !             7: #include <sys/reg.h>
        !             8: #include <sys/con.h>
        !             9: #include <sys/devices.h>
        !            10: #include <errno.h>
        !            11: #include <sys/io.h>
        !            12: #include <sys/proc.h>
        !            13: #include <sys/sched.h>
        !            14: #include <sys/stat.h>
        !            15: 
        !            16: /*
        !            17:  * Patchable parameters.
        !            18:  *
        !            19:  *     LP0_OK specifies whether LP0 is always THERE.
        !            20:  *     LPTIME specifies number of ticks between polls.
        !            21:  *     LPWAIT specifies loop counter to wait in poll.
        !            22:  *     LPTEST specifies whether or not to test for on-line conditition.
        !            23:  */
        !            24: int    LP0_OK = 0;
        !            25: int    LPTIME = 4;
        !            26: int    LPWAIT = 400;
        !            27: int    LPTEST = 1;
        !            28: 
        !            29: /*
        !            30:  * Driver configuration.
        !            31:  */
        !            32: int    lpload();
        !            33: int    lpunload();
        !            34: int    lpwrite();
        !            35: int    lpopen();
        !            36: int    lpclose();
        !            37: int    lpintr();
        !            38: int    nulldev();
        !            39: int    nonedev();
        !            40: 
        !            41: CON    lpcon = {
        !            42:        DFCHR,                          /* Flags */
        !            43:        LP_MAJOR,                               /* Major index */
        !            44:        lpopen,                         /* Open */
        !            45:        lpclose,                        /* Close */
        !            46:        nulldev,                        /* Block */
        !            47:        nonedev,                        /* Read */
        !            48:        lpwrite,                        /* Write */
        !            49:        nonedev,                        /* Ioctl */
        !            50:        nulldev,                        /* Powerfail */
        !            51:        nulldev,                        /* Timeout */
        !            52:        lpload,                         /* Load */
        !            53:        lpunload                        /* Unload */
        !            54: };
        !            55: 
        !            56: /*
        !            57:  * Line Printer Registers.
        !            58:  */
        !            59: #define        LPDAT   (0)                     /* Data port, lpbase + 0 */
        !            60: #define        LPSTR   (1)                     /* Status port, lpbase + 1 */
        !            61: #define        LPCSR   (2)                     /* Control port, lpbase + 2 */
        !            62: 
        !            63: /*
        !            64:  * LP Flag Bits.
        !            65:  */
        !            66: #define        LPTHERE 0x01                    /* Interface actually there */
        !            67: #define        LPOPEN  0x02                    /* Printer is open */
        !            68: #define        LPSLEEP 0x04                    /* Sleeping on buffer event */
        !            69: #define        LPRAW   0x80                    /* Raw mode */
        !            70: 
        !            71: /*
        !            72:  * Printer database.
        !            73:  * Terminated by lpbase = 0.
        !            74:  * NLP = # entries - 1.
        !            75:  */
        !            76: static struct  lpinfo  {
        !            77:        int     lpbase;                 /* I/O Base address */
        !            78:        int     lpflag;                 /* Flags */
        !            79:        int     lpcol;                  /* Current horizontal position */
        !            80: }      lpinfo[] = {
        !            81:        {       0x3BC   },
        !            82:        {       0x378   },
        !            83:        {       0x278   },
        !            84:        {       0x000   }
        !            85: };
        !            86: #define        NLP     (sizeof(lpinfo) / sizeof(lpinfo[0]) - 1)
        !            87: 
        !            88: /*
        !            89:  * LP Status Register Bits.
        !            90:  */
        !            91: #define        ACK     0x80                    /* Ack (active high) */
        !            92: #define        BUSY    0x40                    /* Busy (active high) */
        !            93: #define        NOPAPER 0x20                    /* No paper */
        !            94: #define        ONLINE  0x10                    /* On line */
        !            95: #define        NERROR  0x08                    /* Error (active low) */
        !            96: 
        !            97: /* IBM cable */
        !            98: #define        IBMNBSY 0x80                    /* Busy (active low) */
        !            99: #define        IBMNACK 0x40                    /* Ack (active low) */
        !           100: 
        !           101: /*
        !           102:  * LP Control Register Bits.
        !           103:  */
        !           104: #define        IENABLE 0x10                    /* Interrupt enable */
        !           105: #define        SEL     0x08                    /* Select input */
        !           106: #define        NINIT   0x04                    /* Initialise printer (active low) */
        !           107: #define        AFEED   0x02                    /* Auto line feed */
        !           108: #define        STROBE  0x01                    /* Strobe */
        !           109: 
        !           110: /*
        !           111:  * On load
        !           112:  * compute the port addresses,
        !           113:  * reset the printer, and select it.
        !           114:  */
        !           115: static
        !           116: lpload()
        !           117: {
        !           118:        register struct lpinfo * p;
        !           119:        register int delay;
        !           120:        static int notfirst;
        !           121: 
        !           122:        /*
        !           123:         * Only initialize hardware on first invocation.
        !           124:         * Necessary if used as console device [condev].
        !           125:         */
        !           126:        if (notfirst)
        !           127:                return;
        !           128:        notfirst = 1;
        !           129: 
        !           130:        /*
        !           131:         * Note: since some PC clones lp ports can't be read,
        !           132:         * their lpflag field has to be patched to 'LPTHERE'.
        !           133:         */
        !           134:        if (LP0_OK & 1)
        !           135:                lpinfo[0].lpflag |= LPTHERE;
        !           136:        if (LP0_OK & 2)
        !           137:                lpinfo[1].lpflag |= LPTHERE;
        !           138:        if (LP0_OK & 4)
        !           139:                lpinfo[2].lpflag |= LPTHERE;
        !           140: 
        !           141:        for (p = lpinfo; p->lpbase ; ++p) {
        !           142: 
        !           143:                /*
        !           144:                 * Check printer port existence.
        !           145:                 */
        !           146:                if ((p->lpflag & LPTHERE) == 0) {
        !           147:                        outb(p->lpbase+LPDAT, 0xA5);
        !           148:                        delay = LPWAIT; do {
        !           149:                        } while (--delay);
        !           150:                        if (inb(p->lpbase+LPDAT) == 0xA5)
        !           151:                                p->lpflag |= LPTHERE;
        !           152:                }
        !           153: 
        !           154:                /*
        !           155:                 * Initialize and select printer.
        !           156:                 */
        !           157:                outb(p->lpbase+LPCSR, SEL);
        !           158:                delay = LPWAIT; do {
        !           159:                } while (--delay);
        !           160:                outb(p->lpbase+LPCSR, SEL|NINIT);
        !           161:        }
        !           162: }
        !           163: 
        !           164: /*
        !           165:  * On unload
        !           166:  * cancel any timed functions.
        !           167:  */
        !           168: static
        !           169: lpunload()
        !           170: {
        !           171:        lptimer();
        !           172: }
        !           173: 
        !           174: /*
        !           175:  * The open routine makes sure that
        !           176:  * only one process has the printer open
        !           177:  * at one time, and not too much else.
        !           178:  */
        !           179: static
        !           180: lpopen(dev, mode)
        !           181: dev_t  dev;
        !           182: {
        !           183:        register struct lpinfo * p;
        !           184: 
        !           185:        /*
        !           186:         * Illegal printer port.
        !           187:         */
        !           188:        if ((minor(dev) & ~LPRAW) >= NLP) {
        !           189:                u.u_error = ENXIO;
        !           190:                return;
        !           191:        }
        !           192: 
        !           193:        /*
        !           194:         * Access attributes.
        !           195:         */
        !           196:        p = &lpinfo[ minor(dev) & ~LPRAW ];
        !           197: 
        !           198:        /*
        !           199:         * Attempt initialization if printer port not found.
        !           200:         */
        !           201:        if ((p->lpflag&LPTHERE) == 0)
        !           202:                lpload();
        !           203: 
        !           204:        /*
        !           205:         * Printer port not found.
        !           206:         */
        !           207:        if ((p->lpflag&LPTHERE) == 0) {
        !           208:                u.u_error = ENXIO;
        !           209:                return;
        !           210:        }
        !           211: 
        !           212:        /*
        !           213:         * Printer port already open.
        !           214:         */
        !           215:        if ((p->lpflag&LPOPEN) != 0) {
        !           216:                u.u_error = EBUSY;
        !           217:                return;
        !           218:        }
        !           219: 
        !           220:        /*
        !           221:         * Printer powered off or off-line
        !           222:         */
        !           223:        if (LPTEST && !(inb(p->lpbase+LPSTR) & ONLINE)) {
        !           224:                u.u_error = EIO;
        !           225:                return;
        !           226:        }
        !           227: 
        !           228:        /*
        !           229:         * Flag port as being open.
        !           230:         */
        !           231:        p->lpflag &= ~LPRAW;
        !           232:        p->lpflag |= LPOPEN | minor(dev) & LPRAW;
        !           233: 
        !           234:        /*
        !           235:         * Initiate periodic printer scan if user open.
        !           236:         */
        !           237:        if ((SELF != NULL) && (SELF->p_pid != 0))
        !           238:                lptimer();
        !           239: }
        !           240: 
        !           241: /*
        !           242:  * The close routine marks the device as no longer open.
        !           243:  */
        !           244: static
        !           245: lpclose(dev)
        !           246: dev_t  dev;
        !           247: {
        !           248:        lpinfo[ minor(dev) & ~LPRAW ].lpflag &= ~LPOPEN;
        !           249: }
        !           250: 
        !           251: /*
        !           252:  * The write routine copies the
        !           253:  * characters from the user buffer to
        !           254:  * the printer buffer, expanding tabs and
        !           255:  * keeping track of the current horizontal
        !           256:  * position of the print head.
        !           257:  */
        !           258: static
        !           259: lpwrite(dev, iop)
        !           260: dev_t  dev;
        !           261: IO     *iop;
        !           262: {
        !           263:        register struct lpinfo * p;
        !           264:        register int    c;
        !           265: 
        !           266:        p = &lpinfo[ minor(dev) & ~LPRAW ];
        !           267: 
        !           268:        /*
        !           269:         * Writes from kernel are handled via busy-waits instead of timeouts.
        !           270:         */
        !           271:        if (iop->io_seg == IOSYS) {
        !           272: 
        !           273:                while ((c=iogetc(iop)) >= 0) {
        !           274: 
        !           275:                        while ((inb(p->lpbase+LPSTR) & IBMNBSY) == 0)
        !           276:                                ;
        !           277: 
        !           278:                        outb(p->lpbase+LPDAT, c);
        !           279:                        outb(p->lpbase+LPCSR, SEL|NINIT|STROBE);
        !           280:                        outb(p->lpbase+LPCSR, SEL|NINIT);
        !           281:                }
        !           282:                return;
        !           283:        }
        !           284: 
        !           285:        /*
        !           286:         * Writes from user are handled via lpchar() which uses timeouts.
        !           287:         */
        !           288:        while ((c=iogetc(iop)) >= 0) {
        !           289: 
        !           290:                if ((p->lpflag&LPRAW) == 0) {
        !           291: 
        !           292:                        switch (c) {
        !           293: 
        !           294:                        case '\t':
        !           295:                                do {
        !           296:                                        lpchar(p, ' ');
        !           297:                                } while ((++p->lpcol&07) != 0);
        !           298:                                continue;
        !           299:        
        !           300:                        case '\n':
        !           301:                                lpchar(p, '\r');
        !           302:                                /* no break */
        !           303: 
        !           304:                        case '\r':
        !           305:                        case '\f':
        !           306:                                p->lpcol = 0;
        !           307:                                break;
        !           308:        
        !           309:                        case '\b':
        !           310:                                --p->lpcol;
        !           311:                                break;
        !           312:        
        !           313:                        default:
        !           314:                                ++p->lpcol;
        !           315:                        }
        !           316:                }
        !           317:                lpchar(p, c);
        !           318:        }
        !           319: }
        !           320: 
        !           321: /*
        !           322:  * Put a character into the printer buffer.
        !           323:  * If the printer doesn't respond ready in a reasonable time
        !           324:  * sleep for a while.
        !           325:  */
        !           326: static
        !           327: lpchar(p, c)
        !           328: register struct lpinfo *p;
        !           329: int c;
        !           330: {
        !           331:        register int    waitCount;
        !           332:        register int    s;
        !           333: 
        !           334:        waitCount = LPWAIT;
        !           335:        while ((inb(p->lpbase+LPSTR) & IBMNBSY) == 0) {
        !           336:                if (--waitCount == 0) {
        !           337:                        s = sphi();
        !           338:                        p->lpflag |= LPSLEEP;
        !           339:                        x_sleep((char *)p, pritty, slpriSigLjmp, "lpchar");
        !           340:                        spl(s);
        !           341:                        waitCount = LPWAIT;
        !           342:                }
        !           343:        }
        !           344: 
        !           345:        outb(p->lpbase+LPDAT, c);
        !           346:        outb(p->lpbase+LPCSR, SEL|NINIT|STROBE);
        !           347:        outb(p->lpbase+LPCSR, SEL|NINIT);
        !           348: }
        !           349: 
        !           350: /*
        !           351:  * Poll the line printer interface from the clock.
        !           352:  * Turn it off when there is nothing left to do.
        !           353:  */
        !           354: static
        !           355: lptimer()
        !           356: {
        !           357:        register struct lpinfo *p;
        !           358:        int isopen = 0;
        !           359:        static TIM tim;
        !           360: 
        !           361:        /*
        !           362:         * Scan all printers.
        !           363:         */
        !           364:        for (p = lpinfo; p->lpbase; ++p) {
        !           365: 
        !           366:                /*
        !           367:                 * Ignore unopened printers.
        !           368:                 */
        !           369:                if ((p->lpflag & LPOPEN) == 0)
        !           370:                        continue;
        !           371: 
        !           372:                ++isopen;
        !           373: 
        !           374:                /*
        !           375:                 * Check for sleeping process on ready printer.
        !           376:                 */
        !           377:                if((p->lpflag & LPSLEEP) && (inb(p->lpbase+LPSTR) & IBMNBSY)){
        !           378:                        p->lpflag &= ~LPSLEEP;
        !           379:                        wakeup((char *)p);
        !           380:                }
        !           381:        }
        !           382: 
        !           383:        /*
        !           384:         * Reschedule timer function if at least 1 printer is still open.
        !           385:         */
        !           386:        if (isopen)
        !           387:                timeout(&tim, LPTIME, lptimer, &tim);
        !           388: }

unix.superglobalmegacorp.com

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