[BACK]Return to lpt.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/lpt.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: lpt.c,v 1.5 2002/03/14 01:26:54 millert Exp $ */
                      2: /*     $NetBSD: lpt.c,v 1.42 1996/10/21 22:41:14 thorpej Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1993, 1994 Charles Hannum.
                      6:  * Copyright (c) 1990 William F. Jolitz, TeleMuse
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This software is a component of "386BSD" developed by
                     20:  *     William F. Jolitz, TeleMuse.
                     21:  * 4. Neither the name of the developer nor the name "386BSD"
                     22:  *    may be used to endorse or promote products derived from this software
                     23:  *    without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
                     26:  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
                     27:  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
                     28:  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
                     29:  * NOT MAKE USE OF THIS WORK.
                     30:  *
                     31:  * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
                     32:  * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
                     33:  * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
                     34:  * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
                     35:  * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
                     36:  * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
                     37:  * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
                     38:  * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
                     39:  *
                     40:  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
                     41:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     42:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     43:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
                     44:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     45:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     46:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     47:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     48:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     49:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     50:  * SUCH DAMAGE.
                     51:  */
                     52:
                     53: /*
                     54:  * Device Driver for AT parallel printer port
                     55:  */
                     56:
                     57: #include <sys/param.h>
                     58: #include <sys/systm.h>
                     59: #include <sys/proc.h>
                     60: #include <sys/user.h>
                     61: #include <sys/buf.h>
                     62: #include <sys/kernel.h>
                     63: #include <sys/ioctl.h>
                     64: #include <sys/uio.h>
                     65: #include <sys/device.h>
                     66: #include <sys/conf.h>
                     67: #include <sys/syslog.h>
                     68:
                     69: #include <machine/bus.h>
                     70: #include <machine/intr.h>
                     71:
                     72: #include <dev/ic/lptreg.h>
                     73: #include <dev/ic/lptvar.h>
                     74:
                     75: #include "lpt.h"
                     76:
                     77: #define        TIMEOUT         hz*16   /* wait up to 16 seconds for a ready */
                     78: #define        STEP            hz/4
                     79:
                     80: #define        LPTPRI          (PZERO+8)
                     81: #define        LPT_BSIZE       1024
                     82:
                     83: #if !defined(DEBUG) || !defined(notdef)
                     84: #define LPRINTF(a)
                     85: #else
                     86: #define LPRINTF(a)     if (lptdebug) printf a
                     87: int lptdebug = 1;
                     88: #endif
                     89:
                     90: /* XXX does not belong here */
                     91: cdev_decl(lpt);
                     92:
                     93: struct cfdriver lpt_cd = {
                     94:        NULL, "lpt", DV_TTY
                     95: };
                     96:
                     97: #define        LPTUNIT(s)      (minor(s) & 0x1f)
                     98: #define        LPTFLAGS(s)     (minor(s) & 0xe0)
                     99:
                    100: #define        LPS_INVERT      (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK)
                    101: #define        LPS_MASK        (LPS_SELECT|LPS_NERR|LPS_NBSY|LPS_NACK|LPS_NOPAPER)
                    102: #define        NOT_READY() \
                    103:     ((bus_space_read_1(iot, ioh, lpt_status) ^ LPS_INVERT) & LPS_MASK)
                    104: #define        NOT_READY_ERR() \
                    105:     lpt_not_ready(bus_space_read_1(iot, ioh, lpt_status), sc)
                    106:
                    107: int    lpt_not_ready(u_int8_t, struct lpt_softc *);
                    108: void   lptwakeup(void *arg);
                    109: int    lptpushbytes(struct lpt_softc *);
                    110:
                    111: /*
                    112:  * Internal routine to lptprobe to do port tests of one byte value.
                    113:  */
                    114: int
                    115: lpt_port_test(iot, ioh, base, off, data, mask)
                    116:        bus_space_tag_t iot;
                    117:        bus_space_handle_t ioh;
                    118:        bus_addr_t base;
                    119:        bus_size_t off;
                    120:        u_int8_t data, mask;
                    121: {
                    122:        int timeout;
                    123:        u_int8_t temp;
                    124:
                    125:        data &= mask;
                    126:        bus_space_write_1(iot, ioh, off, data);
                    127:        timeout = 1000;
                    128:        do {
                    129:                delay(10);
                    130:                temp = bus_space_read_1(iot, ioh, off) & mask;
                    131:        } while (temp != data && --timeout);
                    132:        LPRINTF(("lpt: port=0x%x out=0x%x in=0x%x timeout=%d\n", base + off,
                    133:            data, temp, timeout));
                    134:        return (temp == data);
                    135: }
                    136:
                    137: void
                    138: lpt_attach_common(sc)
                    139:        struct lpt_softc *sc;
                    140: {
                    141:        printf("\n");
                    142:
                    143:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, lpt_control, LPC_NINIT);
                    144:
                    145:        timeout_set(&sc->sc_wakeup_tmo, lptwakeup, sc);
                    146: }
                    147:
                    148: /*
                    149:  * Reset the printer, then wait until it's selected and not busy.
                    150:  */
                    151: int
                    152: lptopen(dev, flag, mode, p)
                    153:        dev_t dev;
                    154:        int flag;
                    155:        int mode;
                    156:        struct proc *p;
                    157: {
                    158:        int unit = LPTUNIT(dev);
                    159:        u_int8_t flags = LPTFLAGS(dev);
                    160:        struct lpt_softc *sc;
                    161:        bus_space_tag_t iot;
                    162:        bus_space_handle_t ioh;
                    163:        u_int8_t control;
                    164:        int error;
                    165:        int spin;
                    166:
                    167:        if (unit >= lpt_cd.cd_ndevs)
                    168:                return ENXIO;
                    169:        sc = lpt_cd.cd_devs[unit];
                    170:        if (!sc)
                    171:                return ENXIO;
                    172:
                    173:        sc->sc_flags = (sc->sc_flags & LPT_POLLED) | flags;
                    174:        if ((sc->sc_flags & (LPT_POLLED|LPT_NOINTR)) == LPT_POLLED)
                    175:                return ENXIO;
                    176:
                    177: #ifdef DIAGNOSTIC
                    178:        if (sc->sc_state)
                    179:                printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname,
                    180:                    sc->sc_state);
                    181: #endif
                    182:
                    183:        if (sc->sc_state)
                    184:                return EBUSY;
                    185:
                    186:        sc->sc_state = LPT_INIT;
                    187:        LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags));
                    188:        iot = sc->sc_iot;
                    189:        ioh = sc->sc_ioh;
                    190:
                    191:        if ((flags & LPT_NOPRIME) == 0) {
                    192:                /* assert INIT for 100 usec to start up printer */
                    193:                bus_space_write_1(iot, ioh, lpt_control, LPC_SELECT);
                    194:                delay(100);
                    195:        }
                    196:
                    197:        control = LPC_SELECT | LPC_NINIT;
                    198:        bus_space_write_1(iot, ioh, lpt_control, control);
                    199:
                    200:        /* wait till ready (printer running diagnostics) */
                    201:        for (spin = 0; NOT_READY_ERR(); spin += STEP) {
                    202:                if (spin >= TIMEOUT) {
                    203:                        sc->sc_state = 0;
                    204:                        return EBUSY;
                    205:                }
                    206:
                    207:                /* wait 1/4 second, give up if we get a signal */
                    208:                error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", STEP);
                    209:                if (error != EWOULDBLOCK) {
                    210:                        sc->sc_state = 0;
                    211:                        return error;
                    212:                }
                    213:        }
                    214:
                    215:        if ((flags & LPT_NOINTR) == 0)
                    216:                control |= LPC_IENABLE;
                    217:        if (flags & LPT_AUTOLF)
                    218:                control |= LPC_AUTOLF;
                    219:        sc->sc_control = control;
                    220:        bus_space_write_1(iot, ioh, lpt_control, control);
                    221:
                    222:        sc->sc_inbuf = geteblk(LPT_BSIZE);
                    223:        sc->sc_count = 0;
                    224:        sc->sc_state = LPT_OPEN;
                    225:
                    226:        if ((sc->sc_flags & LPT_NOINTR) == 0)
                    227:                lptwakeup(sc);
                    228:
                    229:        LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname));
                    230:        return 0;
                    231: }
                    232:
                    233: int
                    234: lpt_not_ready(status, sc)
                    235:        u_int8_t status;
                    236:        struct lpt_softc *sc;
                    237: {
                    238:        u_int8_t new;
                    239:
                    240:        status = (status ^ LPS_INVERT) & LPS_MASK;
                    241:        new = status & ~sc->sc_laststatus;
                    242:        sc->sc_laststatus = status;
                    243:
                    244:        if (new & LPS_SELECT)
                    245:                log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
                    246:        else if (new & LPS_NOPAPER)
                    247:                log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
                    248:        else if (new & LPS_NERR)
                    249:                log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
                    250:
                    251:        return status;
                    252: }
                    253:
                    254: void
                    255: lptwakeup(arg)
                    256:        void *arg;
                    257: {
                    258:        struct lpt_softc *sc = arg;
                    259:        int s;
                    260:
                    261:        s = spltty();
                    262:        lptintr(sc);
                    263:        splx(s);
                    264:
                    265:        timeout_add(&sc->sc_wakeup_tmo, STEP);
                    266: }
                    267:
                    268: /*
                    269:  * Close the device, and free the local line buffer.
                    270:  */
                    271: int
                    272: lptclose(dev, flag, mode, p)
                    273:        dev_t dev;
                    274:        int flag;
                    275:        int mode;
                    276:        struct proc *p;
                    277: {
                    278:        int unit = LPTUNIT(dev);
                    279:        struct lpt_softc *sc = lpt_cd.cd_devs[unit];
                    280:        bus_space_tag_t iot = sc->sc_iot;
                    281:        bus_space_handle_t ioh = sc->sc_ioh;
                    282:
                    283:        if (sc->sc_count)
                    284:                (void) lptpushbytes(sc);
                    285:
                    286:        if ((sc->sc_flags & LPT_NOINTR) == 0)
                    287:                timeout_del(&sc->sc_wakeup_tmo);
                    288:
                    289:        bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
                    290:        sc->sc_state = 0;
                    291:        bus_space_write_1(iot, ioh, lpt_control, LPC_NINIT);
                    292:        brelse(sc->sc_inbuf);
                    293:
                    294:        LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname));
                    295:        return 0;
                    296: }
                    297:
                    298: int
                    299: lptpushbytes(sc)
                    300:        struct lpt_softc *sc;
                    301: {
                    302:        bus_space_tag_t iot = sc->sc_iot;
                    303:        bus_space_handle_t ioh = sc->sc_ioh;
                    304:        int error;
                    305:
                    306:        if (sc->sc_flags & LPT_NOINTR) {
                    307:                int spin, tic;
                    308:                u_int8_t control = sc->sc_control;
                    309:
                    310:                while (sc->sc_count > 0) {
                    311:                        spin = 0;
                    312:                        while (NOT_READY()) {
                    313:                                if (++spin < sc->sc_spinmax)
                    314:                                        continue;
                    315:                                tic = 0;
                    316:                                /* adapt busy-wait algorithm */
                    317:                                sc->sc_spinmax++;
                    318:                                while (NOT_READY_ERR()) {
                    319:                                        /* exponential backoff */
                    320:                                        tic = tic + tic + 1;
                    321:                                        if (tic > TIMEOUT)
                    322:                                                tic = TIMEOUT;
                    323:                                        error = tsleep((caddr_t)sc,
                    324:                                            LPTPRI | PCATCH, "lptpsh", tic);
                    325:                                        if (error != EWOULDBLOCK)
                    326:                                                return error;
                    327:                                }
                    328:                                break;
                    329:                        }
                    330:
                    331:                        bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++);
                    332:                        bus_space_write_1(iot, ioh, lpt_control,
                    333:                            control | LPC_STROBE);
                    334:                        sc->sc_count--;
                    335:                        bus_space_write_1(iot, ioh, lpt_control, control);
                    336:
                    337:                        /* adapt busy-wait algorithm */
                    338:                        if (spin*2 + 16 < sc->sc_spinmax)
                    339:                                sc->sc_spinmax--;
                    340:                }
                    341:        } else {
                    342:                int s;
                    343:
                    344:                while (sc->sc_count > 0) {
                    345:                        /* if the printer is ready for a char, give it one */
                    346:                        if ((sc->sc_state & LPT_OBUSY) == 0) {
                    347:                                LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname,
                    348:                                    sc->sc_count));
                    349:                                s = spltty();
                    350:                                (void) lptintr(sc);
                    351:                                splx(s);
                    352:                        }
                    353:                        error = tsleep((caddr_t)sc, LPTPRI | PCATCH,
                    354:                            "lptwrite2", 0);
                    355:                        if (error)
                    356:                                return error;
                    357:                }
                    358:        }
                    359:        return 0;
                    360: }
                    361:
                    362: /*
                    363:  * Copy a line from user space to a local buffer, then call putc to get the
                    364:  * chars moved to the output queue.
                    365:  */
                    366: int
                    367: lptwrite(dev, uio, flags)
                    368:        dev_t dev;
                    369:        struct uio *uio;
                    370:        int flags;
                    371: {
                    372:        struct lpt_softc *sc = lpt_cd.cd_devs[LPTUNIT(dev)];
                    373:        size_t n;
                    374:        int error = 0;
                    375:
                    376:        while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) {
                    377:                uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
                    378:                sc->sc_count = n;
                    379:                error = lptpushbytes(sc);
                    380:                if (error) {
                    381:                        /*
                    382:                         * Return accurate residual if interrupted or timed
                    383:                         * out.
                    384:                         */
                    385:                        uio->uio_resid += sc->sc_count;
                    386:                        sc->sc_count = 0;
                    387:                        return error;
                    388:                }
                    389:        }
                    390:        return 0;
                    391: }
                    392:
                    393: /*
                    394:  * Handle printer interrupts which occur when the printer is ready to accept
                    395:  * another char.
                    396:  */
                    397: int
                    398: lptintr(arg)
                    399:        void *arg;
                    400: {
                    401:        struct lpt_softc *sc = arg;
                    402:        bus_space_tag_t iot = sc->sc_iot;
                    403:        bus_space_handle_t ioh = sc->sc_ioh;
                    404:
                    405:        if (((sc->sc_state & LPT_OPEN) == 0 && sc->sc_count == 0) ||
                    406:            (sc->sc_flags & LPT_NOINTR))
                    407:                return 0;
                    408:
                    409:        /* is printer online and ready for output */
                    410:        if (NOT_READY() && NOT_READY_ERR())
                    411:                return -1;
                    412:
                    413:        if (sc->sc_count) {
                    414:                u_int8_t control = sc->sc_control;
                    415:                /* send char */
                    416:                bus_space_write_1(iot, ioh, lpt_data, *sc->sc_cp++);
                    417:                delay (50);
                    418:                bus_space_write_1(iot, ioh, lpt_control, control | LPC_STROBE);
                    419:                sc->sc_count--;
                    420:                bus_space_write_1(iot, ioh, lpt_control, control);
                    421:                sc->sc_state |= LPT_OBUSY;
                    422:        } else
                    423:                sc->sc_state &= ~LPT_OBUSY;
                    424:
                    425:        if (sc->sc_count == 0) {
                    426:                /* none, wake up the top half to get more */
                    427:                wakeup((caddr_t)sc);
                    428:        }
                    429:
                    430:        return 1;
                    431: }
                    432:
                    433: int
                    434: lptioctl(dev, cmd, data, flag, p)
                    435:        dev_t dev;
                    436:        u_long cmd;
                    437:        caddr_t data;
                    438:        int flag;
                    439:        struct proc *p;
                    440: {
                    441:        int error = 0;
                    442:
                    443:        switch (cmd) {
                    444:        default:
                    445:                error = ENODEV;
                    446:        }
                    447:
                    448:        return error;
                    449: }

CVSweb