Annotation of lucent/sys/src/9/pc/devincon.c, revision 1.1.1.1

1.1       root        1: #include       "u.h"
                      2: #include       "../port/lib.h"
                      3: #include       "mem.h"
                      4: #include       "dat.h"
                      5: #include       "fns.h"
                      6: #include       "../port/error.h"
                      7: #include       "devtab.h"
                      8: 
                      9: #include       "io.h"
                     10: 
                     11: /* Centronix parallel (printer) port */
                     12: 
                     13: typedef struct Lptinfo Lptinfo;
                     14: 
                     15: struct Lptinfo
                     16: {
                     17:        int     base;           /* port number */
                     18:        int     ivec;           /* interrupt number */
                     19: };
                     20: 
                     21: static Lptinfo lptinfo[] = {
                     22:        0x3bc,  Parallelvec,    /* lpt1 (safari) */
                     23:        0x378,  Parallelvec,    /* lpt1 (`official') */
                     24:        0x278,  Int0vec+5,      /* lpt2 (`official') */
                     25: };
                     26: #define NDEV   (sizeof lptinfo/sizeof lptinfo[0])
                     27: 
                     28: extern int     incondev;       /* from config */
                     29: 
                     30: /* offsets, and bits in the registers */
                     31: enum
                     32: {
                     33:        /* data latch register */
                     34:        Qdlr=           0x0,
                     35:        /* printer status register */
                     36:        Qpsr=           0x1,
                     37:        Fbusy=          0x80,
                     38:        Fintbar=        0x40,
                     39:        /* printer control register */
                     40:        Qpcr=           0x2,
                     41:        Fie=            0x10,
                     42:        Fsi=            0x08,
                     43:        Finitbar=       0x04,
                     44:        Faf=            0x02,
                     45:        Fstrobe=        0x01,
                     46: 
                     47:        /* other `registers' */
                     48:        Qstats=         0x03,
                     49:        Qdebug=         0x04
                     50: };
                     51: 
                     52: /*
                     53:  *     af  si  dlr<7:0>
                     54:  *      0   x  xxxxxxxx        wr ctl/data char (si is dcto)
                     55:  *      1   0  xxxxxxxx        wr cmd
                     56:  *      1   1  xxxxxx00        rd ctl/data char
                     57:  *      1   1  xxxxxx01        rd status
                     58:  *      1   1  xxxxxx11        nop (multiplexer to normal state)
                     59:  *
                     60:  *      psr<7:3> multiplexed as follows:
                     61:  *
                     62:  *                     bc7  bc6  bc5  bc4  bc3
                     63:  *      rd, st- low    bsy   d8   d7   d6   d5
                     64:  *      rd, st- high    d4   d3   d2   d1   d0
                     65:  *      other          bsy  int-
                     66:  */
                     67: 
                     68: typedef struct Incon   Incon;
                     69: 
                     70: #define NOW (MACHP(0)->ticks*MS2HZ)
                     71: 
                     72: #define DPRINT if(incondebug)kprint
                     73: 
                     74: static void    inconintr(Ureg *ur, void *a);
                     75: 
                     76: enum {
                     77:        Minstation=     2,      /* lowest station # to poll */
                     78:        Maxstation=     15,     /* highest station # to poll */
                     79:        Nincon=         1,      /* number of incons */
                     80:        Nin=            32,     /* Blocks in the input ring */
                     81:        Bsize=          128,    /* size of an input ring block */
                     82:        Mfifo=          0xff    /* a mask, must be 2^n-1, must be > Nin */
                     83: };
                     84: 
                     85: struct Incon {
                     86:        QLock;
                     87: 
                     88:        QLock   xmit;           /* transmit lock */
                     89:        QLock   reslock;        /* reset lock */
                     90:        int     dev;            /* base address of port */
                     91:        int     station;        /* station number */
                     92:        int     state;          /* chip state */
                     93:        Rendez  r;              /* output process */
                     94:        Rendez  kr;             /* input kernel process */
                     95:        ushort  chan;           /* current input channel */
                     96:        Queue   *rq;            /* read queue */
                     97:        int     kstarted;       /* true if kernel process started */
                     98: 
                     99:        /*  input blocks */
                    100: 
                    101:        Block   *inb[Nin];
                    102:        ushort  wi;             
                    103:        ushort  ri;
                    104: 
                    105:        /* statistics */
                    106: 
                    107:        ulong   overflow;       /* overflow errors */
                    108:        ulong   pack0;          /* channel 0 */
                    109:        ulong   crc;            /* crc errors */
                    110:        ulong   in;             /* bytes in */
                    111:        ulong   out;            /* bytes out */
                    112:        ulong   wait;           /* wait time in milliseconds */
                    113: };
                    114: 
                    115: Incon incon[Nincon];
                    116: 
                    117: /*
                    118:  *  chip state
                    119:  */
                    120: enum {
                    121:        Selecting,
                    122:        Selected,
                    123:        Notliving,
                    124: };
                    125: 
                    126: /*
                    127:  *  internal chip registers
                    128:  */
                    129: #define        sel_polln       0
                    130: #define        sel_station     1
                    131: #define        sel_poll0       2
                    132: #define sel_rcv_cnt    3
                    133: #define sel_rcv_tim    4
                    134: #define sel_tx_cnt     5
                    135: 
                    136: /*
                    137:  *  CSR bits
                    138:  */
                    139: #define INCON_RUN      0x80
                    140: #define INCON_STOP     0x00
                    141: #define ENABLE_IRQ     0x40
                    142: #define ENABLE_TX_IRQ  0x20
                    143: #define INCON_ALIVE    0x80
                    144: #define TX_FULL                0x10
                    145: #define TX_EMPTY       0x08
                    146: #define RCV_EMPTY      0x04
                    147: #define OVERFLOW       0x02
                    148: #define CRC_ERROR      0x01
                    149: 
                    150: /*
                    151:  *  polling constants
                    152:  */
                    153: #define HT_GNOT        0x30
                    154: #define HT_UNIX        0x31
                    155: #define ST_UNIX 0x04
                    156: #define NCHAN 64
                    157: 
                    158: static void inconkproc(void*);
                    159: 
                    160: /*
                    161:  *  incon stream module definition
                    162:  */
                    163: static void inconoput(Queue*, Block*);
                    164: static void inconstopen(Queue*, Stream*);
                    165: static void inconstclose(Queue*);
                    166: Qinfo inconinfo =
                    167: {
                    168:        nullput,
                    169:        inconoput,
                    170:        inconstopen,
                    171:        inconstclose,
                    172:        "incon"
                    173: };
                    174: 
                    175: int incondebug = 0;
                    176: 
                    177: Dirtab incondir[]={
                    178:        "dlr",          {Qdlr},         1,              0666,
                    179:        "psr",          {Qpsr},         5,              0444,
                    180:        "pcr",          {Qpcr},         0,              0666,
                    181:        "stats",        {Qstats},       0,              0444,
                    182:        "debug",        {Qdebug},       0,              0666,
                    183: };
                    184: #define NINCON (sizeof incondir/sizeof incondir[0])
                    185: 
                    186: static void
                    187: nop(void)
                    188: {
                    189: }
                    190: 
                    191: static int
                    192: slowinb(int x)
                    193: {
                    194:        nop();
                    195:        nop();
                    196:        return inb(x);
                    197: }
                    198: 
                    199: static void
                    200: reset(int dev)                         /* hardware reset */
                    201: {
                    202:        outb(dev+Qpcr, Finitbar);
                    203:        outb(dev+Qpcr, 0);
                    204:        outb(dev+Qpcr, Finitbar);
                    205: }
                    206: 
                    207: static void
                    208: wrctl(int dev, int data)               /* write control character */
                    209: {
                    210:        outb(dev+Qpcr, Finitbar);       /* no interrupts, please */
                    211:        outb(dev+Qdlr, data);
                    212:        outb(dev+Qpcr, Finitbar|Fstrobe);
                    213:        outb(dev+Qpcr, Finitbar|Fie);
                    214: }
                    215: 
                    216: static void
                    217: wrdata(int dev, int data)              /* write data character */
                    218: {
                    219:        outb(dev+Qpcr, Finitbar|Fsi);
                    220:        outb(dev+Qdlr, data);
                    221:        outb(dev+Qpcr, Finitbar|Fsi|Fstrobe);
                    222:        outb(dev+Qpcr, Finitbar|Fsi|Fie);
                    223: }
                    224: 
                    225: static void
                    226: wrcmd(int dev, int data)               /* write command */
                    227: {
                    228:        outb(dev+Qpcr, Finitbar|Faf);
                    229:        outb(dev+Qdlr, data);
                    230:        outb(dev+Qpcr, Finitbar|Faf|Fstrobe);
                    231:        outb(dev+Qpcr, Finitbar|Faf|Fie);
                    232: }
                    233: 
                    234: static int
                    235: rdstatus(Incon *ip)                    /* read status */
                    236: {
                    237:        int dev, data;
                    238: 
                    239:        dev = ip->dev;
                    240: 
                    241:        outb(dev+Qpcr, Finitbar|Faf|Fsi);
                    242:        outb(dev+Qdlr, 0x01);
                    243:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
                    244:        data = (inb(dev+Qpsr)&0xf8)<<2;
                    245:        outb(dev+Qpcr, Finitbar|Faf|Fsi);
                    246:        data |= inb(dev+Qpsr)>>3;
                    247:        if(data&(OVERFLOW|CRC_ERROR)){
                    248:                if(data&OVERFLOW)
                    249:                        ip->overflow++;
                    250:                if(data&CRC_ERROR)
                    251:                        ip->crc++;
                    252:        }
                    253:        outb(dev+Qdlr, 0x03);
                    254:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
                    255:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fie);
                    256: 
                    257:        return data;
                    258: }
                    259: 
                    260: static void
                    261: iwrcmd(int dev, int data)              /* write command at interrupt level */
                    262: {
                    263:        outb(dev+Qdlr, data);
                    264:        outb(dev+Qpcr, Finitbar|Faf|Fstrobe);
                    265:        outb(dev+Qpcr, Finitbar|Faf);
                    266: }
                    267: 
                    268: static int
                    269: irdstatus(Incon *ip)                   /* read status at interrupt level */
                    270: {
                    271:        int dev, data;
                    272: 
                    273:        dev = ip->dev;
                    274: 
                    275:        outb(dev+Qdlr, 0x01);
                    276:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
                    277:        data = (slowinb(dev+Qpsr)&0xf8)<<2;
                    278:        outb(dev+Qpcr, Finitbar|Faf|Fsi);
                    279:        data |= slowinb(dev+Qpsr)>>3;
                    280:        if(data&(OVERFLOW|CRC_ERROR)){
                    281:                if(data&OVERFLOW)
                    282:                        ip->overflow++;
                    283:                if(data&CRC_ERROR)
                    284:                        ip->crc++;
                    285:        }
                    286: 
                    287:        return data;
                    288: }
                    289: 
                    290: static int
                    291: irddata(int dev)                       /* read data at interrupt level */
                    292: {
                    293:        int data;
                    294: 
                    295:        outb(dev+Qdlr, 0x00);
                    296:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
                    297:        data = (slowinb(dev+Qpsr)&0xf8)<<2;
                    298:        outb(dev+Qpcr, Finitbar|Faf|Fsi);
                    299:        data |= slowinb(dev+Qpsr)>>3;
                    300: 
                    301:        return data;
                    302: }
                    303: 
                    304: static int
                    305: irdnext(int dev)                       /* read next data at interrupt level */
                    306: {
                    307:        int data;
                    308: 
                    309:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
                    310:        data = (inb(dev+Qpsr)&0xf8)<<2;
                    311:        outb(dev+Qpcr, Finitbar|Faf|Fsi);
                    312:        data |= inb(dev+Qpsr)>>3;
                    313: 
                    314:        return data;
                    315: }
                    316: 
                    317: static void
                    318: irdnop(int dev, int pcr)               /* read nop (mux reset) */
                    319: {
                    320:        outb(dev+Qdlr, 0x03);
                    321:        outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
                    322:        outb(dev+Qpcr, pcr);
                    323: }
                    324: 
                    325: int            Irdnext(int);
                    326: #define        irdnext Irdnext
                    327: /**/
                    328: 
                    329: /*
                    330:  *  set the incon parameters
                    331:  */
                    332: void
                    333: inconset(Incon *ip, int cnt, int del)
                    334: {
                    335:        int dev;
                    336: 
                    337:        if (cnt<1 || cnt>14 || del<1 || del>15)
                    338:                error(Ebadarg);
                    339: 
                    340:        dev = ip->dev;
                    341:        wrcmd(dev, sel_rcv_cnt | INCON_RUN);
                    342:        wrdata(dev, cnt);
                    343:        wrcmd(dev, sel_rcv_tim | INCON_RUN);
                    344:        wrdata(dev, del);
                    345:        wrcmd(dev, INCON_RUN | ENABLE_IRQ);
                    346: }
                    347: 
                    348: /*
                    349:  *  parse a set request
                    350:  */
                    351: void
                    352: inconsetctl(Incon *ip, Block *bp)
                    353: {
                    354:        char *field[3];
                    355:        int n;
                    356:        int del;
                    357:        int cnt;
                    358: 
                    359:        del = 15;
                    360:        n = getfields((char *)bp->rptr, field, 3, " ");
                    361:        switch(n){
                    362:        default:
                    363:                freeb(bp);
                    364:                error(Ebadarg);
                    365:        case 2:
                    366:                del = strtol(field[1], 0, 0);
                    367:                if(del<0 || del>15){
                    368:                        freeb(bp);
                    369:                        error(Ebadarg);
                    370:                }
                    371:                /* fall through */
                    372:        case 1:
                    373:                cnt = strtol(field[0], 0, 0);
                    374:                if(cnt<0 || cnt>15){
                    375:                        freeb(bp);
                    376:                        error(Ebadarg);
                    377:                }
                    378:        }
                    379:        inconset(ip, cnt, del);
                    380:        freeb(bp);
                    381: }
                    382: 
                    383: /*
                    384:  *  poll for a station number
                    385:  */
                    386: void 
                    387: inconpoll(Incon *ip, int station)
                    388: {
                    389:        ulong timer;
                    390:        int dev;
                    391:        char *p;
                    392: 
                    393:        dev = ip->dev;
                    394: 
                    395:        /*
                    396:         *  get us to a known state
                    397:         */
                    398:        ip->state = Notliving;
                    399:        wrcmd(dev, INCON_STOP);
                    400: 
                    401:        /*
                    402:         * try a station number
                    403:         */
                    404:        wrcmd(dev, sel_station);
                    405:        wrdata(dev, station);
                    406:        wrcmd(dev, sel_poll0);
                    407:        wrdata(dev, HT_GNOT);
                    408:        wrcmd(dev, sel_rcv_cnt);
                    409:        wrdata(dev, 3);
                    410:        wrcmd(dev, sel_rcv_tim);
                    411:        wrdata(dev, 15);
                    412:        wrcmd(dev, sel_tx_cnt);
                    413:        wrdata(dev, 1);
                    414:        wrcmd(dev, sel_polln);
                    415:        wrdata(dev, 0x00);
                    416:        wrdata(dev, ST_UNIX);
                    417:        wrdata(dev, NCHAN);
                    418:        for(p = "gnot"; *p; p++)
                    419:                wrdata(dev, *p);
                    420:        wrctl(dev, 0);
                    421: 
                    422:        /*
                    423:         *  poll and wait for ready (or 1/4 second)
                    424:         */
                    425:        ip->state = Selecting;
                    426:        wrcmd(dev, INCON_RUN | ENABLE_IRQ);
                    427:        timer = NOW + 250;
                    428:        while (NOW < timer) {
                    429:                nop();
                    430:                if(rdstatus(ip) & INCON_ALIVE){
                    431:                        ip->station = station;
                    432:                        ip->state = Selected;
                    433:                        break;
                    434:                }
                    435:        }
                    436: }
                    437: 
                    438: /*
                    439:  *  reset the chip and find a new station number
                    440:  */
                    441: void
                    442: inconrestart(Incon *ip)
                    443: {
                    444:        int i;
                    445: 
                    446:        if(!canqlock(&ip->reslock))
                    447:                return;
                    448: 
                    449:        /*
                    450:         *  poll for incon station numbers
                    451:         */
                    452:        DPRINT("inconrestart\n");
                    453:        for(i = Minstation; i <= Maxstation; i++){
                    454:                inconpoll(ip, i);
                    455:                if(ip->state == Selected)
                    456:                        break;
                    457:        }
                    458:        switch(ip->state) {
                    459:        case Selecting:
                    460:                DPRINT("incon[%d] not polled\n", ip-incon);
                    461:                print("incon[%d] not polled\n", ip-incon);
                    462:                break;
                    463:        case Selected:
                    464:                DPRINT("incon[%d] station %d\n", ip-incon, ip->station);
                    465:                print("incon[%d] station %d\n", ip-incon, ip->station);
                    466:                inconset(ip, 3, 15);
                    467:                break;
                    468:        default:
                    469:                DPRINT("incon[%d] bollixed\n", ip-incon);
                    470:                print("incon[%d] bollixed\n", ip-incon);
                    471:                break;
                    472:        }
                    473:        qunlock(&ip->reslock);
                    474: }
                    475: 
                    476: /*
                    477:  *  reset all incon chips.
                    478:  */
                    479: 
                    480: void
                    481: inconreset(void)
                    482: {
                    483:        int i;
                    484:        char *p;
                    485: 
                    486:        /*
                    487:         *  get incondev from p9rc
                    488:         */
                    489:        p = getconf("incondev");
                    490:        if(p)
                    491:                incondev = atoi(p);
                    492: 
                    493:        /*
                    494:         * state is Selected if we used incon as the boot device
                    495:         * i.e. we've already got a station number.
                    496:         * state is Selecting if this is a first-time open.
                    497:         */
                    498: /*     inconset(&incon[0], 3, 15); /**/
                    499:        for(i=0; i<Nincon; i++){
                    500:                incon[i].dev = lptinfo[incondev].base;
                    501:                incon[i].state = Notliving;
                    502:                reset(incon[i].dev);
                    503:                incon[i].ri = incon[i].wi = 0;
                    504:        }
                    505:        incon[0].state = Selecting;
                    506:        wrcmd(incon[0].dev, INCON_STOP);
                    507: }
                    508: 
                    509: void
                    510: inconinit(void)
                    511: {
                    512:        wrcmd(incon[0].dev, INCON_STOP);
                    513: }
                    514: 
                    515: /*
                    516:  *  enable the device for interrupts, spec is the device number
                    517:  */
                    518: Chan*
                    519: inconattach(char *spec)
                    520: {
                    521:        Incon *ip;
                    522:        int i;
                    523:        Chan *c;
                    524: 
                    525:        setvec(lptinfo[incondev].ivec, inconintr, 0);
                    526:        i = strtoul(spec, 0, 0);
                    527:        if(i >= Nincon)
                    528:                error(Ebadarg);
                    529:        ip = &incon[i];
                    530:        rdstatus(ip);
                    531:        if(ip->state != Selected)
                    532:                inconrestart(ip);
                    533: 
                    534:        c = devattach('i', spec);
                    535:        c->dev = i;
                    536:        c->qid.path = CHDIR;
                    537:        c->qid.vers = 0;
                    538:        return c;
                    539: }
                    540: 
                    541: Chan*
                    542: inconclone(Chan *c, Chan *nc)
                    543: {
                    544:        return devclone(c, nc);
                    545: }
                    546: 
                    547: int     
                    548: inconwalk(Chan *c, char *name)
                    549: {
                    550:        return devwalk(c, name, incondir, NINCON, streamgen);
                    551: }
                    552: 
                    553: void    
                    554: inconstat(Chan *c, char *dp)
                    555: {
                    556:        devstat(c, dp, incondir, NINCON, streamgen);
                    557: }
                    558: 
                    559: Chan*
                    560: inconopen(Chan *c, int omode)
                    561: {
                    562:        if(c->qid.path != CHDIR && c->qid.path >= Slowqid)
                    563:                streamopen(c, &inconinfo);
                    564:        c->mode = openmode(omode);
                    565:        c->flag |= COPEN;
                    566:        c->offset = 0;
                    567:        return c;
                    568: }
                    569: 
                    570: void    
                    571: inconcreate(Chan *c, char *name, int omode, ulong perm)
                    572: {
                    573:        USED(c, name, omode, perm);
                    574:        error(Eperm);
                    575: }
                    576: 
                    577: void    
                    578: inconclose(Chan *c)
                    579: {
                    580:        if(c->qid.path != CHDIR && c->qid.path >= Slowqid)
                    581:                streamclose(c);
                    582: }
                    583: 
                    584: long    
                    585: inconread(Chan *c, void *buf, long n, ulong offset)
                    586: {
                    587:        char b[256];
                    588:        Incon *ip;
                    589: 
                    590:        if(c->qid.path == CHDIR)
                    591:                return devdirread(c, buf, n, incondir, NINCON, streamgen);
                    592:        ip = &incon[c->dev];
                    593:        switch(c->qid.path){
                    594:        default:
                    595:                return streamread(c, buf, n);
                    596:        case Qdlr:
                    597:        case Qpsr:
                    598:        case Qpcr:
                    599:                sprint(b, "0x%2.2ux\n", inb(ip->dev + c->qid.path));
                    600:                break;
                    601:        case Qstats:
                    602:                sprint(b, "state: %d\nstation: %d\nin: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n",
                    603:                        ip->state, ip->station, ip->in, ip->out, ip->overflow, ip->crc, ip->wait);
                    604:                break;
                    605:        case Qdebug:
                    606:                sprint(b, "%d\n", incondebug);
                    607:                break;
                    608:        }
                    609:        return readstr(offset, buf, n, b);
                    610: }
                    611: 
                    612: long    
                    613: inconwrite(Chan *c, void *buf, long n, ulong offset)
                    614: {
                    615:        char b[8];
                    616:        Incon *ip;
                    617:        int data;
                    618: 
                    619:        USED(offset);
                    620:        switch(c->qid.path){
                    621:        default:
                    622:                return streamwrite(c, buf, n, 0);
                    623:        case Qdlr:
                    624:        case Qpcr:
                    625:        case Qdebug:
                    626:                break;
                    627:        }
                    628:        if(n > sizeof b-1)
                    629:                n = sizeof b-1;
                    630:        memmove(b, buf, n);
                    631:        b[n] = 0;
                    632:        data = strtoul(b, 0, 0);
                    633:        switch(c->qid.path){
                    634:        default:
                    635:                ip = &incon[c->dev];
                    636:                outb(ip->dev + c->qid.path, data);
                    637:                break;
                    638:        case Qdebug:
                    639:                incondebug = data;
                    640:                break;
                    641:        }
                    642:        return n;
                    643: }
                    644: 
                    645: void    
                    646: inconremove(Chan *c)
                    647: {
                    648:        USED(c);
                    649:        error(Eperm);
                    650: }
                    651: 
                    652: void    
                    653: inconwstat(Chan *c, char *dp)
                    654: {
                    655:        USED(c, dp);
                    656:        error(Eperm);
                    657: }
                    658: 
                    659: /*
                    660:  *     the stream routines
                    661:  */
                    662: 
                    663: /*
                    664:  *  kill off the kernel process
                    665:  */
                    666: static int
                    667: kNotliving(void *arg)
                    668: {
                    669:        Incon *ip;
                    670: 
                    671:        ip = (Incon *)arg;
                    672:        return ip->kstarted == 0;
                    673: }
                    674: 
                    675: static void
                    676: inconstclose(Queue * q)
                    677: {
                    678:        Incon *ip;
                    679: 
                    680:        ip = (Incon *)q->ptr;
                    681:        qlock(ip);
                    682:        ip->rq = 0;
                    683:        qunlock(ip);
                    684:        wakeup(&ip->kr);
                    685:        sleep(&ip->r, kNotliving, ip);
                    686: }
                    687: 
                    688: /*
                    689:  *  create the kernel process for input
                    690:  *  first wait for any old ones to die
                    691:  */
                    692: static void
                    693: inconstopen(Queue *q, Stream *s)
                    694: {
                    695:        Incon *ip;
                    696:        char name[32];
                    697: 
                    698:        ip = &incon[s->dev];
                    699:        sprint(name, "incon%d", s->dev);
                    700:        q->ptr = q->other->ptr = ip;
                    701:        wakeup(&ip->kr);
                    702:        sleep(&ip->r, kNotliving, ip);
                    703:        ip->rq = q;
                    704:        kproc(name, inconkproc, ip);
                    705: }
                    706: 
                    707: /*
                    708:  *  free all blocks of a message in `q', `bp' is the first block
                    709:  *  of the message
                    710:  */
                    711: static void
                    712: freemsg(Queue *q, Block *bp)
                    713: {
                    714:        for(; bp; bp = getq(q)){
                    715:                if(bp->flags & S_DELIM){
                    716:                        freeb(bp);
                    717:                        return;
                    718:                }
                    719:                freeb(bp);
                    720:        }
                    721: }
                    722: 
                    723: static void
                    724: showpkt(char *str, int chan, int ctl, Block *bp, int i)
                    725: {
                    726:        int n;
                    727: 
                    728:        n = bp->wptr - bp->rptr;
                    729:        kprint("%s(%d)%uo %d", str, chan, ctl, n);
                    730:        if(n > 8)
                    731:                n = 8;
                    732:        for(; i<n; i++)
                    733:                kprint(" %2.2ux", bp->rptr[i]);
                    734:        kprint("\n");
                    735: }
                    736: 
                    737: /*
                    738:  *  output a block
                    739:  *
                    740:  *  the first 2 bytes of every message are the channel number,
                    741:  *  low order byte first.  the third is a possible trailing control
                    742:  *  character.
                    743:  */
                    744: void
                    745: inconoput(Queue *q, Block *bp)
                    746: {
                    747:        int dev;
                    748:        Incon *ip;
                    749:        ulong end;
                    750:        int status, chan, ctl;
                    751:        int n, size;
                    752: 
                    753:        ip = (Incon *)q->ptr;
                    754: 
                    755:        if(bp->type != M_DATA){
                    756:                if(streamparse("inconset", bp))
                    757:                        inconsetctl(ip, bp);
                    758:                else
                    759:                        freeb(bp);
                    760:                return;
                    761:        }
                    762:        if(BLEN(bp) < 3){
                    763:                bp = pullup(bp, 3);
                    764:                if(bp == 0){
                    765:                        print("inconoput pullup failed\n");
                    766:                        return;
                    767:                }
                    768:        }
                    769: 
                    770:        /*
                    771:         *  get a whole message before handing bytes to the device
                    772:         */
                    773:        if(!putq(q, bp))
                    774:                return;
                    775: 
                    776:        /*
                    777:         *  one transmitter at a time
                    778:         */
                    779:        qlock(&ip->xmit);
                    780:        dev = ip->dev;
                    781: 
                    782:        /*
                    783:         *  parse message
                    784:         */
                    785:        bp = getq(q);
                    786:        chan = bp->rptr[0] | (bp->rptr[1]<<8);
                    787:        ctl = bp->rptr[2];
                    788:        bp->rptr += 3;
                    789:        if(chan<=0)
                    790:                print("bad channel %d\n", chan);
                    791: 
                    792:        if(incondebug){
                    793:                kprint("0x%.2ux ", rdstatus(ip));
                    794:                showpkt("->", chan, ctl, bp, 0);
                    795:        }
                    796: 
                    797:        /*
                    798:         *  make sure there's an incon out there
                    799:         */
                    800:        if(!(rdstatus(ip)&INCON_ALIVE) || ip->state==Notliving){
                    801:                DPRINT("inconoput: not ready");
                    802:                inconrestart(ip);
                    803:                freemsg(q, bp);
                    804:                qunlock(&ip->xmit);
                    805:                return;
                    806:        }
                    807: 
                    808:        /*
                    809:         *  send the 8 bit data
                    810:         */
                    811:        for(;;){
                    812:                /*
                    813:                 *  spin till there is room
                    814:                 */
                    815:                for(n=0, end = NOW+1000; (status=rdstatus(ip)) & TX_FULL; n++){
                    816:                        nop();  /* make sure we don't optimize too much */
                    817:                        if(NOW > end){
                    818:                                print("incon output stuck 0 %.2ux\n", status);
                    819:                                freemsg(q, bp);
                    820:                                qunlock(&ip->xmit);
                    821:                                return;
                    822:                        }
                    823:                }
                    824:                ip->wait = (n + ip->wait)>>1;
                    825: 
                    826:                /*
                    827:                 *  put in next packet
                    828:                 */
                    829:                n = bp->wptr - bp->rptr;
                    830:                if(n > 16)
                    831:                        n = 16;
                    832:                size = n;
                    833:                wrctl(dev, chan);
                    834:                ip->out += n;
                    835:                while(n--){
                    836:                        wrdata(dev, *bp->rptr++);
                    837:                }
                    838: 
                    839:                /*
                    840:                 *  get next block 
                    841:                 */
                    842:                if(bp->rptr >= bp->wptr){
                    843:                        if(bp->flags & S_DELIM){
                    844:                                freeb(bp);
                    845:                                break;
                    846:                        }
                    847:                        freeb(bp);
                    848:                        bp = getq(q);
                    849:                        if(bp==0)
                    850:                                break;
                    851:                }
                    852: 
                    853:                /*
                    854:                 *  end packet
                    855:                 */
                    856:                wrctl(dev, 0);
                    857:        }
                    858: 
                    859:        /*
                    860:         *  send the control byte if there is one
                    861:         */
                    862:        if(ctl){
                    863:                if(size >= 16){
                    864:                        wrctl(dev, 0);
                    865:                        for(end = NOW+1000; rdstatus(ip) & TX_FULL;){
                    866:                                nop();  /* make sure we don't optimize too much */
                    867:                                if(NOW > end){
                    868:                                        print("incon output stuck 1\n");
                    869:                                        freemsg(q, bp);
                    870:                                        qunlock(&ip->xmit);
                    871:                                        return;
                    872:                                }
                    873:                        }
                    874:                        wrctl(dev, chan);
                    875:                }
                    876:                if(rdstatus(ip) & TX_FULL)
                    877:                        print("inconfull\n");
                    878:                ip->out += 1;
                    879:                wrctl(dev, ctl);
                    880:        }
                    881:        wrctl(dev, 0);
                    882: 
                    883:        qunlock(&ip->xmit);
                    884:        return;
                    885: }
                    886: 
                    887: /*
                    888:  *  return true if the raw fifo is non-empty
                    889:  */
                    890: static int
                    891: notempty(void *arg)
                    892: {
                    893:        Incon *ip;
                    894: 
                    895:        ip = (Incon *)arg;
                    896:        return ip->ri!=ip->wi;
                    897: }
                    898: 
                    899: /*
                    900:  *  Read bytes from the raw input circular buffer.
                    901:  */
                    902: static void
                    903: inconkproc(void *arg)
                    904: {
                    905:        Incon *ip;
                    906:        Block *bp;
                    907:        int i;
                    908:        int locked;
                    909: 
                    910:        ip = (Incon *)arg;
                    911:        ip->kstarted = 1;
                    912: 
                    913:        /*
                    914:         *  create a number of blocks for input
                    915:         */
                    916:        for(i = 0; i < Nin; i++){
                    917:                bp = ip->inb[i] = allocb(Bsize);
                    918:                bp->wptr += 3;
                    919:        }
                    920: 
                    921:        locked = 0;
                    922:        if(waserror()){
                    923:                if(locked)
                    924:                        qunlock(ip);
                    925:                ip->kstarted = 0;
                    926:                wakeup(&ip->r);
                    927:                return;
                    928:        }
                    929: 
                    930:        for(;;){
                    931:                /*
                    932:                 *  sleep if input fifo empty
                    933:                 */
                    934:                sleep(&ip->kr, notempty, ip);
                    935: 
                    936:                /*
                    937:                 *  die if the device is closed
                    938:                 */
                    939:                USED(locked);
                    940:                qlock(ip);
                    941:                locked = 1;
                    942:                if(ip->rq == 0){
                    943:                        qunlock(ip);
                    944:                        ip->kstarted = 0;
                    945:                        wakeup(&ip->r);
                    946:                        poperror();
                    947:                        return;
                    948:                }
                    949: 
                    950:                /*
                    951:                 *  send blocks upstream and stage new blocks.
                    952:                 */
                    953:                while(ip->ri != ip->wi){
                    954:                        bp = ip->inb[ip->ri];
                    955:                        bp->flags |= S_DELIM;
                    956:                        ip->in += BLEN(bp);
                    957:                        PUTNEXT(ip->rq, bp);
                    958:                        bp = ip->inb[ip->ri] = allocb(Bsize);
                    959:                        bp->wptr += 3;
                    960:                        ip->ri = (ip->ri+1)%Nin;
                    961:                }
                    962:                USED(locked);
                    963:                qunlock(ip);
                    964:                locked = 0;
                    965:        }
                    966: }
                    967: 
                    968: /*
                    969:  *  drop a single packet
                    970:  */
                    971: static void
                    972: droppacket(int dev)
                    973: {
                    974:        if(irddata(dev) == 0)
                    975:                return;
                    976:        while(irdnext(dev))
                    977:                ;
                    978: }
                    979: 
                    980: /*
                    981:  *  flush the input fifo
                    982:  */
                    983: static void
                    984: flushfifo(Incon *ip)
                    985: {
                    986:        while(!(irdstatus(ip) & RCV_EMPTY))
                    987:                droppacket(ip->dev);
                    988: }
                    989: 
                    990: /*
                    991:  *  advance the queue. if we've run out of staged input blocks,
                    992:  *  drop the packet and return 0.  otherwise return the next input
                    993:  *  block to fill.
                    994:  */
                    995: static Block *
                    996: nextin(Incon *ip, unsigned int c)
                    997: {
                    998:        Block *bp;
                    999:        int next;
                   1000: 
                   1001:        bp = ip->inb[ip->wi];
                   1002:        bp->rptr[0] = ip->chan;
                   1003:        bp->rptr[1] = ip->chan>>8;
                   1004:        bp->rptr[2] = c;
                   1005:        if(incondebug)
                   1006:                showpkt("<-", ip->chan, c, bp, 3);
                   1007: 
                   1008:        next = (ip->wi+1)%Nin;
                   1009:        if(next == ip->ri){
                   1010:                bp->wptr = bp->rptr+3;
                   1011:                return bp;
                   1012:        }
                   1013:        ip->wi = next;
                   1014: 
                   1015:        return ip->inb[ip->wi];
                   1016: }
                   1017: 
                   1018: /*
                   1019:  *  read the packets from the device into the staged input blocks.
                   1020:  *  we have to do this at interrupt tevel to turn off the interrupts.
                   1021:  */
                   1022: static void
                   1023: rdpackets(Incon *ip)
                   1024: {
                   1025:        Block *bp;
                   1026:        unsigned int c;
                   1027:        int dev;
                   1028:        uchar *p;
                   1029:        int first = ip->wi;
                   1030: 
                   1031:        dev = ip->dev;
                   1032:        bp = ip->inb[ip->wi];
                   1033:        if(bp==0){
                   1034:                flushfifo(ip);
                   1035:                return;
                   1036:        }
                   1037:        p = bp->wptr;
                   1038:        while(!(irdstatus(ip) & RCV_EMPTY)){
                   1039:                /*
                   1040:                 *  get channel number
                   1041:                 */
                   1042:                c = irddata(dev);
                   1043:                if(c == 0){
                   1044:                        droppacket(dev);
                   1045:                        continue;
                   1046:                }
                   1047:                if(ip->chan != c){
                   1048:                        if(p - bp->rptr > 3){
                   1049:                                bp->wptr = p;
                   1050:                                bp = nextin(ip, 0);
                   1051:                                p = bp->wptr;
                   1052:                        }
                   1053:                        ip->chan = c;
                   1054:                }
                   1055: 
                   1056:                /*
                   1057:                 *  null byte marks end of packet
                   1058:                 */
                   1059:                while(c = irdnext(dev)){        /* assign = */
                   1060:                        if((c & 0x100) == 0){
                   1061:                                /*
                   1062:                                 *  control byte ends block
                   1063:                                 */
                   1064:                                bp->wptr = p;
                   1065:                                bp = nextin(ip, c);
                   1066:                                p = bp->wptr;
                   1067:                        }else{
                   1068:                                /*
                   1069:                                 *  data byte, put in local buffer
                   1070:                                 */
                   1071:                                *p++ = c;
                   1072:                        }
                   1073:                }
                   1074: 
                   1075:                /*
                   1076:                 *  pass a block on if it doesn't have room for one more
                   1077:                 *  packet.  this way we don't have to check per byte.
                   1078:                 */
                   1079:                if(p + 16 > bp->lim){
                   1080:                        bp->wptr = p;
                   1081:                        bp = nextin(ip, 0);
                   1082:                        p = bp->wptr;
                   1083:                }
                   1084:        }       
                   1085:        bp->wptr = p;
                   1086:        if(bp->wptr != bp->rptr+3)
                   1087:                nextin(ip, 0);
                   1088: 
                   1089:        if(first != ip->wi)/**/
                   1090:                wakeup(&ip->kr);
                   1091: }
                   1092: 
                   1093: /*
                   1094:  *  Receive an incon interrupt.  One entry point
                   1095:  *  for all types of interrupt.  Until we figure out
                   1096:  *  how to use more than one incon, this routine only
                   1097:  *  is for incon[0].
                   1098:  */
                   1099: static void
                   1100: inconintr(Ureg *ur, void *a)
                   1101: {
                   1102:        uchar status;
                   1103:        int pcr;
                   1104:        Incon *ip;
                   1105: 
                   1106:        USED(ur, a);
                   1107:        ip = &incon[0];
                   1108:        pcr = inb(ip->dev+Qpcr);
                   1109:        if(!(pcr & Fie))
                   1110:                return;
                   1111:        status = irdstatus(ip);
                   1112:        if(incondebug){
                   1113:                kprint("pcr=%2.2x status=%2.2x\n", pcr, status);
                   1114:                if(pcr & Fstrobe)
                   1115:                        kprint("YIKES!!\n");
                   1116:        }
                   1117:        if(!(status & RCV_EMPTY))
                   1118:                rdpackets(ip);
                   1119: 
                   1120:        /* see if it died underneath us */
                   1121:        if(!(status&INCON_ALIVE)){
                   1122:                switch(ip->state){
                   1123:                case Selected:
                   1124:                        iwrcmd(ip->dev, INCON_STOP);
                   1125:                        DPRINT("Incon died\n");
                   1126:                        print("Incon died\n");
                   1127:                        break;
                   1128:                case Selecting:
                   1129:                        DPRINT("rejected\n");
                   1130:                        print("rejected\n");
                   1131:                        break;
                   1132:                default:
                   1133:                        iwrcmd(ip->dev, INCON_STOP);
                   1134:                        DPRINT("state was %d\n", ip->state);
                   1135:                        break;
                   1136:                }
                   1137:                ip->state = Notliving;
                   1138:        }
                   1139:        irdnop(ip->dev, pcr);
                   1140: }

unix.superglobalmegacorp.com

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