Annotation of coherent/d/286_KERNEL/USRSRC/io/lp.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/i8086.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/uproc.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 = EDBUSY;
        !           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 = EDATTN;
        !           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:                if ( SELF->p_ssig!=0 && nondsig() ) {
        !           320:                        u.u_error = EINTR;
        !           321:                        break;
        !           322:                }
        !           323:        }
        !           324: }
        !           325: 
        !           326: /*
        !           327:  * Put a character into the printer buffer.
        !           328:  * If the printer doesn't respond ready in a reasonable time
        !           329:  * sleep for a while.
        !           330:  */
        !           331: static
        !           332: lpchar( p, c )
        !           333: register struct lpinfo *p;
        !           334: int c;
        !           335: {
        !           336:        register int    s;
        !           337: 
        !           338:        s = LPWAIT;
        !           339:        while ( (inb(p->lpbase+LPSTR) & IBMNBSY) == 0 ) {
        !           340:                if ( --s == 0 ) {
        !           341:                        s = sphi();
        !           342:                        p->lpflag |= LPSLEEP;
        !           343:                        sleep((char *)p, 0, 0, 0);
        !           344:                        spl(s);
        !           345:                        s = LPWAIT;
        !           346:                }
        !           347:        }
        !           348: 
        !           349:        outb( p->lpbase+LPDAT, c );
        !           350:        outb( p->lpbase+LPCSR, SEL|NINIT|STROBE );
        !           351:        outb( p->lpbase+LPCSR, SEL|NINIT );
        !           352: }
        !           353: 
        !           354: /*
        !           355:  * Poll the line printer interface from the clock.
        !           356:  * Turn it off when there is nothing left to do.
        !           357:  */
        !           358: static
        !           359: lptimer()
        !           360: {
        !           361:        register struct lpinfo *p;
        !           362:        int isopen = 0;
        !           363:        static TIM tim;
        !           364: 
        !           365:        /*
        !           366:         * Scan all printers.
        !           367:         */
        !           368:        for ( p = lpinfo; p->lpbase; ++p ) {
        !           369: 
        !           370:                /*
        !           371:                 * Ignore unopened printers.
        !           372:                 */
        !           373:                if ( (p->lpflag & LPOPEN) == 0 )
        !           374:                        continue;
        !           375: 
        !           376:                ++isopen;
        !           377: 
        !           378:                /*
        !           379:                 * Check for sleeping process on ready printer.
        !           380:                 */
        !           381:                if((p->lpflag & LPSLEEP) && (inb(p->lpbase+LPSTR) & IBMNBSY)){
        !           382:                        p->lpflag &= ~LPSLEEP;
        !           383:                        wakeup((char *)p);
        !           384:                }
        !           385:        }
        !           386: 
        !           387:        /*
        !           388:         * Reschedule timer function if at least 1 printer is still open.
        !           389:         */
        !           390:        if ( isopen )
        !           391:                timeout( &tim, LPTIME, lptimer, &tim );
        !           392: }

unix.superglobalmegacorp.com

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