Annotation of coherent/d/286_KERNEL/USRSRC/io/tn.c, revision 1.1

1.1     ! root        1: /* (-lgl
        !             2:  *     COHERENT Driver Kit Version 1.1.0
        !             3:  *     Copyright (c) 1982, 1990 by Mark Williams Company.
        !             4:  *     All rights reserved. May not be copied without permission.
        !             5:  -lgl) */
        !             6: /*
        !             7:  * Tiac ARCNET PC-234 Device Driver
        !             8:  *
        !             9:  * True support for up to 4 network cards through minor devices 0-3.
        !            10:  * Up to 4 protocols now supported.  Novell access is through normal
        !            11:  * minor device.  Netbios access is through novell minor device + 16.
        !            12:  */
        !            13: 
        !            14: #include <sys/coherent.h>
        !            15: #include <sys/con.h>
        !            16: #include <sys/devices.h>
        !            17: #include <sys/sched.h>
        !            18: #include <sys/seg.h>
        !            19: #include <sys/stat.h>
        !            20: #include <sys/uproc.h>
        !            21: #include <sys/tnioctl.h>
        !            22: #include <errno.h>
        !            23: 
        !            24: /*
        !            25:  * External functions.
        !            26:  */
        !            27: extern int  wakeup();
        !            28: extern void pollwake();
        !            29: extern void defer();
        !            30: 
        !            31: /*
        !            32:  * Driver functions.
        !            33:  */
        !            34: void   tnopen();
        !            35: void   tnclose();
        !            36: int    tnread();
        !            37: int    tnwrite();
        !            38: int    tnioctl();
        !            39: void   tncycle();
        !            40: void   tnload();
        !            41: void   tnuload();
        !            42: int    tnpoll();
        !            43: int    nonedev();
        !            44: int    nulldev();
        !            45: void   tn0intr();
        !            46: void   tn1intr();
        !            47: void   tn2intr();
        !            48: void   tn3intr();
        !            49: void   tnintr();
        !            50: 
        !            51: /*
        !            52:  * Driver Configuration.
        !            53:  */
        !            54: CON
        !            55: tncon = {
        !            56:        DFCHR|DFPOL,                    /* Flags        */
        !            57:        TN_MAJOR,                       /* Major Index  */
        !            58:        tnopen,                         /* Open         */
        !            59:        tnclose,                        /* Close        */
        !            60:        nonedev,                        /* Block        */
        !            61:        tnread,                         /* Read         */
        !            62:        tnwrite,                        /* Write        */
        !            63:        tnioctl,                        /* Ioctl        */
        !            64:        nulldev,                        /* Power fail   */
        !            65:        tncycle,                        /* Timeout      */
        !            66:        tnload,                         /* Load         */
        !            67:        tnuload,                        /* Unload       */
        !            68:        tnpoll                          /* Poll         */
        !            69: };
        !            70: 
        !            71: /*
        !            72:  * Interrupt Entry Points.
        !            73:  */
        !            74: void (*tnintf[4])() = {
        !            75:        tn0intr,
        !            76:        tn1intr,
        !            77:        tn2intr,
        !            78:        tn3intr
        !            79: };
        !            80: 
        !            81: #define        BIT(n)          (1 << (n))
        !            82: 
        !            83: /*
        !            84:  * Bitmask, indexed by bit numbers 0..7.
        !            85:  */
        !            86: static unsigned char bitm[8] = { BIT(0), BIT(1), BIT(2), BIT(3),
        !            87:                                 BIT(4), BIT(5), BIT(6), BIT(7) };
        !            88: 
        !            89: /*
        !            90:  * Patchable parameters - Cards 0-3.
        !            91:  */
        !            92:                /* Card    0       1       2      3  */
        !            93: int    TNIRQ [4] = {      2,      7,      4,      0 };
        !            94: saddr_t        TNSEL [4] = { 0xD000, 0x0000, 0x0000, 0x0000 };
        !            95: int    TNPORT[4] = {  0x2E0,  0x220,  0x240,  0x000 };
        !            96: 
        !            97: /*
        !            98:  * Patchable parameters - Prefix Byte.
        !            99:  * Indexed by high nibble of minor device.
        !           100:  */
        !           101: int    TNPREFIX[4] = { 0x00,   0xF3,   0x00,   0x00 };
        !           102: 
        !           103: /*
        !           104:  * Patchable variables.
        !           105:  * TNTIME = Transmit watchdog timer in seconds.
        !           106:  */
        !           107: int TNTIME = 5;
        !           108: 
        !           109: /*
        !           110:  * Register addresses.
        !           111:  */
        !           112: #define        NIR             (tp->tnport)    /* Network Interrupt Mask Reg (w)  */
        !           113: #define        NSR             (tp->tnport)    /* Network Status Register    (r)  */
        !           114: #define        NCR             (tp->tnport+1)  /* Network Command Register   (w)  */
        !           115: #define        NZR             (tp->tnport+8)  /* Network Zap (reset) Reg    (w)  */
        !           116: 
        !           117: /*
        !           118:  * Network Interrupt Register (NIR).
        !           119:  */
        !           120: #define        NI_Tx           BIT(0)          /* Enable Transmitter Avail Intr   */
        !           121: #define        NI_RECON        BIT(2)          /* Enable Reconfiguration   Intr   */
        !           122: #define        NI_Rx           BIT(7)          /* Enable Receiver Full     Intr   */
        !           123: 
        !           124: /*
        !           125:  * Network Status Register (NSR).
        !           126:  */
        !           127: #define        NS_TxRDY        BIT(0)          /* Transmitter Available           */
        !           128: #define        NS_TxACK        BIT(1)          /* Transmit Message Acknowledged   */
        !           129: #define        NS_RECON        BIT(2)          /* Network Reconfiguration         */
        !           130: #define        NS_TEST         BIT(3)          /* Test                            */
        !           131: #define        NS_POR          BIT(4)          /* Power on Reset                  */
        !           132: #define        NS_ETS1         BIT(5)          /* Extended Timeout Status 1       */
        !           133: #define        NS_ETS2         BIT(6)          /* Extended Timeout Status 2       */
        !           134: #define        NS_RxRDY        BIT(7)          /* Packet Received - Receiver Off  */
        !           135: 
        !           136: /*
        !           137:  * Network Command Register (NCR).
        !           138:  */
        !           139: #define        NC_TxDIS        (((0)<<3) + 1)  /* Disable Transmitter             */
        !           140: #define        NC_RxDIS        (((0)<<3) + 2)  /* Disable Receiver                */
        !           141: #define        NC_TxENA(n)     (((n)<<3) + 3)  /* Enable Transmitter on Page n    */
        !           142: #define        NC_RxENA(n)     (((n)<<3)+0x84) /* Enable Receiver    on Page n    */
        !           143: #define        NC_DFC          (((1)<<3) + 5)  /* Define Configuration (2k buf)   */
        !           144: #define        NC_POR          (((1)<<3) + 6)  /* Clear NS_POR flag               */
        !           145: #define        NC_RECON        (((2)<<3) + 6)  /* Clear NS_RECON flag             */
        !           146: 
        !           147: /*
        !           148:  * Packet Control.
        !           149:  */
        !           150: struct tnet_s {
        !           151: 
        !           152:        /*
        !           153:         * Four buffers per card - 2 receive, 2 transmit.
        !           154:         */
        !           155:        struct tnbuf_s {                /* tnget*,tnput* use tn_sel:tn_off */
        !           156:                unsigned        tn_off; /* tn_sel:tn_off  = current byte   */
        !           157:                saddr_t         tn_sel; /* network buffer selector         */
        !           158:                struct tnbuf_s *tn_next;/* pointer to next pkt in queue    */
        !           159:                unsigned        tn_ena; /* Command to enable packet        */
        !           160:                unsigned        tn_base;/* tn_sel:tn_base = pkt address    */
        !           161:                unsigned        tn_xnid;/* Transmit node id                */
        !           162:                unsigned        tn_xlen;/* Transmit length                 */
        !           163:        } tnbuf [4];
        !           164: 
        !           165:        struct tnbuf_s *        RxBusy[4];/* Queues of full receive packets*/
        !           166:        struct tnbuf_s *        RxIdle; /* Queue of empty receive packets  */
        !           167: 
        !           168:        struct tnbuf_s *        TxBusy; /* Queue of full transmit packets  */
        !           169:        struct tnbuf_s *        TxIdle; /* Queue of empty transmit packets */
        !           170: 
        !           171:        event_t                 RxPoll[4];/* Polls for input packets       */
        !           172:        event_t                 TxPoll; /* Polls for empty output packets  */
        !           173: 
        !           174:        char                    RxReq[4];/* 1 = Proc waiting for recv buf  */
        !           175:        char                    TxReq;  /* 1 = Proc waiting for xmit buf   */
        !           176:        char                    refc[4];/* # opens, indexed by prefix code */
        !           177: 
        !           178:        unsigned                tnmask; /* Interrupt enable mask           */
        !           179:        unsigned                tnport; /* Base I/O port                   */
        !           180:        char                    tnaddr[8];/* ARC-NET Node ID, low byte 1st */
        !           181: 
        !           182:        unsigned                tntime; /* transmit watchdog timer         */
        !           183:        unsigned                recon;  /* number of long reconfigurations */
        !           184:        unsigned                pri;    /* priority event occurred         */
        !           185:        long                    rbolt;  /* lbolt at last reconfiguration   */
        !           186:        unsigned char           bad[32];/* bit mask of bad nodes           */
        !           187:        unsigned char           mod[32];/* bit mask of changed nodes       */
        !           188:        long                    recons; /* reconfiguration statistic       */
        !           189:        SEG *                   statseg;/* Segment containing stats        */
        !           190: 
        !           191: } tnet [4];
        !           192: 
        !           193: /*
        !           194:  * Load Routine.
        !           195:  */
        !           196: void
        !           197: tnload()
        !           198: {
        !           199:        register struct tnet_s  * tp;
        !           200:        register struct tnbuf_s * np;
        !           201:        faddr_t faddr;
        !           202:        paddr_t paddr;
        !           203:        int i;
        !           204:        int nid;
        !           205:        long delay;
        !           206: 
        !           207:        for ( tp = &tnet[0], i = 0; i < 4; i++, tp++ ) {
        !           208: 
        !           209:                /*
        !           210:                 * Validate patchable parameters.
        !           211:                 */
        !           212:                if ( (TNSEL[i] == 0) || (TNPORT[i] == 0) || (TNIRQ[i] == 0) ) {
        !           213:                        TNPORT[i] = 0;
        !           214:                        TNSEL[i]  = 0;
        !           215:                        TNIRQ[i]  = 0;
        !           216:                        continue;
        !           217:                }
        !           218: 
        !           219:                tp->tnport = TNPORT[i];
        !           220: 
        !           221:                /*
        !           222:                 * Clear Power-On-Reset Flag.
        !           223:                 */
        !           224:                outb( NCR, NC_POR );
        !           225: 
        !           226:                /*
        !           227:                 * Validate card presence.
        !           228:                 * NOTE: tp->tnport must be programmed before using NIR macro.
        !           229:                 */
        !           230:                if ( inb(NSR) & (NS_TEST|NS_POR) ) {
        !           231:                        tp->tnport = 0;
        !           232:                        continue;
        !           233:                }
        !           234: 
        !           235:                /*
        !           236:                 * Convert physical address into virtual address.
        !           237:                 */
        !           238:                paddr = TNSEL[i] << 4L;
        !           239:                faddr = ptov( paddr, (fsize_t) 2048 );
        !           240: 
        !           241:                /*
        !           242:                 * Verify dual-port memory existence.
        !           243:                 * NOTE: Do not overwrite first two bytes [0xD1,nid].
        !           244:                 */
        !           245:                sfword( faddr+8, 0x1234 );
        !           246:                if ( ffword( faddr+8 ) != 0x1234 ) {
        !           247:                        vrelse( faddr );
        !           248:                        tp->tnport = 0;
        !           249:                        continue;
        !           250:                }
        !           251: 
        !           252:                /*
        !           253:                 * Allocate statistics segment.
        !           254:                 */
        !           255:                tp->statseg = salloc( (fsize_t) (256*NTNST*4), SFSYST|SFHIGH );
        !           256: 
        !           257:                /*
        !           258:                 * Out of memory.
        !           259:                 */
        !           260:                if ( ! tp->statseg ) {
        !           261:                        printf( "tn%d: out of memory\n", i );
        !           262:                        vrelse( faddr );
        !           263:                        tp->tnport = 0;
        !           264:                        continue;
        !           265:                }
        !           266: 
        !           267:                tp->tnbuf[0].tn_sel =
        !           268:                tp->tnbuf[1].tn_sel =
        !           269:                tp->tnbuf[2].tn_sel =
        !           270:                tp->tnbuf[3].tn_sel = FP_SEL(faddr);
        !           271: 
        !           272:                tp->tnbuf[0].tn_ena  = NC_TxENA(0);
        !           273:                tp->tnbuf[1].tn_ena  = NC_TxENA(1);
        !           274:                tp->tnbuf[2].tn_ena  = NC_RxENA(2);
        !           275:                tp->tnbuf[3].tn_ena  = NC_RxENA(3);
        !           276: 
        !           277:                tp->tnbuf[0].tn_base = 0 * 512;
        !           278:                tp->tnbuf[1].tn_base = 1 * 512;
        !           279:                tp->tnbuf[2].tn_base = 2 * 512;
        !           280:                tp->tnbuf[3].tn_base = 3 * 512;
        !           281: 
        !           282:                /*
        !           283:                 * Initialize transmit idle queue.
        !           284:                 */
        !           285:                tp->TxIdle              = &tp->tnbuf[0];
        !           286:                tp->tnbuf[0].tn_next    = &tp->tnbuf[1];
        !           287: 
        !           288:                /*
        !           289:                 * Initialize receive idle queue.
        !           290:                 */
        !           291:                tp->RxIdle              = &tp->tnbuf[2];
        !           292:                tp->tnbuf[2].tn_next    = &tp->tnbuf[3];
        !           293: 
        !           294:                /*
        !           295:                 * Validate Node Id.
        !           296:                 */
        !           297:                np = &tp->tnbuf[0];
        !           298:                np->tn_off = 0;
        !           299:                if ( tngetc(np) != 0xD1 ) {
        !           300: 
        !           301:                        /*
        !           302:                         * Initiate Power On Reset.
        !           303:                         */
        !           304:                        outb( NZR, 1 );
        !           305: 
        !           306:                        /*
        !           307:                         * Wait minimimum of 180 [suggest 250] milli-seconds.
        !           308:                         * Should function properly up to at least 16 Mhz clock.
        !           309:                         */
        !           310:                        for ( delay = 250000L; --delay != 0; )
        !           311:                                ;
        !           312:                }
        !           313: 
        !           314:                /*
        !           315:                 * Validate and Remember Node Id.
        !           316:                 */
        !           317:                np->tn_off = 0;
        !           318:                if ( tngetc(np) == 0xD1 )
        !           319:                        tp->tnaddr[0] = tngetc( np );
        !           320: 
        !           321:                /*
        !           322:                 * Record starting time of statistics collection.
        !           323:                 */
        !           324:                faddr = tp->statseg->s_faddr + TnELAPSED*4;
        !           325:                for ( nid = 0; nid < 256; nid++, faddr += NTNST*4 )
        !           326:                        kfcopy( &lbolt, faddr, sizeof(lbolt) );
        !           327: 
        !           328:                memset( tp->bad, -1, 32 );      /* Assume LAN is down      */
        !           329:                memset( tp->mod,  0, 32 );      /* Assume no node changes  */
        !           330:                tp->tnmask = NI_Rx | NI_RECON;  /* Interrupts to enable    */
        !           331:                outb( NIR, 0 );                 /* Disable Interrupts      */
        !           332:                outb( NCR, NC_POR );            /* Clear POR Flag          */
        !           333:                outb( NCR, NC_DFC );            /* Define 2K buf config    */
        !           334:                outb( NCR, NC_TxDIS );          /* Disable Transmitter     */
        !           335:                outb( NCR, tp->RxIdle->tn_ena); /* Enable receiver         */
        !           336:                setivec( TNIRQ[i], tnintf[i] ); /* Seize Interrupt Vector  */
        !           337:                outb( NIR, tp->tnmask );        /* Enable Interrupts       */
        !           338:        }
        !           339: 
        !           340:        /*
        !           341:         * Enable watchdog timer
        !           342:         */
        !           343:        drvl[TN_MAJOR].d_time = 1;
        !           344: }
        !           345: 
        !           346: /*
        !           347:  * Unload Routine.
        !           348:  */
        !           349: void
        !           350: tnuload( dev )
        !           351: dev_t dev;
        !           352: {
        !           353:        register struct tnet_s  * tp;
        !           354:        register int i;
        !           355:        faddr_t faddr;
        !           356: 
        !           357:        /*
        !           358:         * Disable watchdog timer.
        !           359:         */
        !           360:        drvl[TN_MAJOR].d_time = 0;
        !           361: 
        !           362:        /*
        !           363:         * Scan network adaptors.
        !           364:         */
        !           365:        for ( tp = &tnet[0], i = 0; i < 4; i++, tp++ ) {
        !           366: 
        !           367:                if ( tp->tnport == 0 )
        !           368:                        continue;
        !           369: 
        !           370:                /*
        !           371:                 * Disable Interrupts
        !           372:                 */
        !           373:                outb( NIR, 0 );
        !           374: 
        !           375:                /*
        !           376:                 * Release interrupt vector.
        !           377:                 */
        !           378:                clrivec( TNIRQ[i] );
        !           379: 
        !           380:                /*
        !           381:                 * Release virtual address AFTER disabling interrupts.
        !           382:                 */
        !           383:                if ( FP_SEL(faddr) = tp->tnbuf[0].tn_sel )
        !           384:                        vrelse( faddr );
        !           385: 
        !           386:                /*
        !           387:                 * Release stats segment.
        !           388:                 */
        !           389:                if ( tp->statseg != NULL )
        !           390:                        sfree( tp->statseg );
        !           391:        }
        !           392: }
        !           393: 
        !           394: /*
        !           395:  * Open Routine.
        !           396:  *
        !           397:  *     Low nibble  of minor device is card identifier 0 to 3.
        !           398:  *     High nibble of minor device is code identifier 0 to 3.
        !           399:  */
        !           400: void
        !           401: tnopen( dev, mode )
        !           402: dev_t dev;
        !           403: {
        !           404:        register struct tnet_s * tp;
        !           405:        int card = (dev & 0x0F);
        !           406:        int code = (dev & 0xF0) >> 4;
        !           407: 
        !           408:        /*
        !           409:         * Validate minor device and card existence.
        !           410:         */
        !           411:        if ( (card > 3) || (code > 3) || (tnet[card].tnport == 0)) {
        !           412:                u.u_error = ENXIO;
        !           413:                return;
        !           414:        }
        !           415: 
        !           416:        /*
        !           417:         * Code identifiers 1 to 3 are only valid if a prefix code is known.
        !           418:         */
        !           419:        if ( (code > 0) && (TNPREFIX[code] == 0) ) {
        !           420:                u.u_error = ENXIO;
        !           421:                return;
        !           422:        }
        !           423: 
        !           424:        /*
        !           425:         * Access network information.
        !           426:         */
        !           427:        tp = &tnet[card];
        !           428: 
        !           429:        /*
        !           430:         * Increment reference count (# opens).
        !           431:         */
        !           432:        tp->refc[code]++;
        !           433: }
        !           434: 
        !           435: /*
        !           436:  * Close Routine.
        !           437:  */
        !           438: void
        !           439: tnclose( dev )
        !           440: dev_t dev;
        !           441: {
        !           442:        register struct tnet_s  * tp =tp = &tnet[ dev & 3];
        !           443:        register struct tnbuf_s * np;
        !           444:        int code = (dev & 0x30) >> 4;
        !           445:        int s;
        !           446: 
        !           447:        /*
        !           448:         * Decrement reference count.
        !           449:         */
        !           450:        if ( --tp->refc[code] != 0 )
        !           451:                return;
        !           452: 
        !           453:        /*
        !           454:         * Last close.
        !           455:         * Release all queued packets.
        !           456:         */
        !           457:        while ( np = tp->RxBusy[code] ) {
        !           458:                s = sphi( );
        !           459:                tp->RxBusy[code] = np->tn_next;
        !           460:                tn_rxena( tp, np );
        !           461:                spl( s );
        !           462:        }
        !           463: }
        !           464: 
        !           465: /*
        !           466:  * Watchdog Timing Routine
        !           467:  *
        !           468:  *     If transmit has been enabled for 1-2 seconds:
        !           469:  *             Abort transmission of packet, forcing interrupt.
        !           470:  */
        !           471: void
        !           472: tncycle( )
        !           473: {
        !           474:        register struct tnet_s * tp;
        !           475:        register int code;
        !           476:        int s;
        !           477: 
        !           478:        /*
        !           479:         * Scan all network cards.
        !           480:         */
        !           481:        for ( tp = &tnet[0]; tp <= &tnet[3]; tp++ ) {
        !           482: 
        !           483:                if ( ! tp->tnport )
        !           484:                        continue;
        !           485: 
        !           486:                /*
        !           487:                 * Disable interrupts.
        !           488:                 */
        !           489:                s = sphi();
        !           490: 
        !           491:                /*
        !           492:                 * Enable broadcasts after 5 seconds without reconfiguration.
        !           493:                 */
        !           494:                if ( (tp->recon > 0) && ((lbolt - tp->rbolt) > (5*HZ)) ) {
        !           495:                        /*
        !           496:                         * LAN was previously down.
        !           497:                         */
        !           498:                        if ( tp->bad[0] & 1 ) {
        !           499:                                faddr_t fp = tp->statseg->s_faddr;
        !           500:                                aflong( fp+TnSTATMOD*4, 1 );
        !           501:                                tp->mod[0] |= 1;
        !           502:                                tp->pri = 1;
        !           503:                        }
        !           504:                        tp->bad[0] &= ~1;
        !           505:                        tp->recon   =  0;
        !           506:                }
        !           507: 
        !           508:                /*
        !           509:                 * Discard bad packet on transmit watchdog timeout.
        !           510:                 */
        !           511:                if ( (tp->tntime > 0) && (--(tp->tntime) == 0) )
        !           512:                        outb( NCR, NC_TxDIS );
        !           513: 
        !           514:                /*
        !           515:                 * Enable interrupts.
        !           516:                 */
        !           517:                spl( s );
        !           518: 
        !           519:                /*
        !           520:                 * LAN/DEVICE UP/DOWN event has occurred.
        !           521:                 */
        !           522:                if ( tp->pri == 1 ) {
        !           523: 
        !           524:                        tp->pri = 2;
        !           525: 
        !           526:                        for ( code = 0; code < 4; code++ )
        !           527:                                if ( tp->RxPoll[code].e_procp )
        !           528:                                        pollwake( &tp->RxPoll[code] );
        !           529:                }
        !           530:        }
        !           531: }
        !           532: 
        !           533: static
        !           534: tnioctl( dev, com, arg )
        !           535: dev_t dev;
        !           536: int com;
        !           537: register tnattr_t * arg;
        !           538: {
        !           539:        register struct tnet_s * tp = &tnet[dev & 3];
        !           540:        faddr_t fp;
        !           541:        int nid;
        !           542:        long t;
        !           543:        tnattr_t local;                 /* to avoid fucopy() problems */
        !           544: 
        !           545:        switch ( com ) {
        !           546: 
        !           547:        case TNGETA:
        !           548:        case TNGETAF:
        !           549:                /*
        !           550:                 * Access node statistics.
        !           551:                 */
        !           552:                nid = getubd( &arg->host[5] );
        !           553:                fp  = tp->statseg->s_faddr + nid * (NTNST*4);
        !           554: 
        !           555:                /*
        !           556:                 * Disable interrupts to avoid race condition with tnintr().
        !           557:                 */
        !           558:                sphi();
        !           559: 
        !           560:                /*
        !           561:                 * Copy node status.
        !           562:                 */
        !           563:                if ( tp->bad[nid/8] & bitm[nid%8] )
        !           564:                        putubd( &arg->bad, 1 );
        !           565:                else
        !           566:                        putubd( &arg->bad, 0 );
        !           567: 
        !           568:                /*
        !           569:                 * Copy network reconfigurations to user space.
        !           570:                 * NOTE: This is not a node statistic, but a network stat.
        !           571:                 */
        !           572:                kucopy( &tp->recons, &arg->recons, sizeof(tp->recons) );
        !           573: 
        !           574:                /*
        !           575:                 * Copy node statistics to user space.
        !           576:                 */
        !           577:                fkcopy( fp, &local.stats[0], sizeof(local.stats) );
        !           578:                kucopy( &local.stats[0], &arg->stats[0], sizeof(arg->stats) );
        !           579: 
        !           580:                /*
        !           581:                 * Copy true elapsed time of statistics collection.
        !           582:                 */
        !           583:                fkcopy( fp+TnELAPSED*4, &t, sizeof(t) );
        !           584:                t = lbolt - t;
        !           585:                kucopy( &t, &arg->stats[TnELAPSED], sizeof(arg->stats[0]) );
        !           586: 
        !           587:                /*
        !           588:                 * Clear node statistics.
        !           589:                 * NOTE: Elapsed time statistic is time of last clear.
        !           590:                 */
        !           591:                if ( com == TNGETAF ) {
        !           592:                        fclear( fp, NTNST * 4 );
        !           593:                        kfcopy( &lbolt, fp+TnELAPSED*4, sizeof(lbolt) );
        !           594:                        if ( nid == 0 )
        !           595:                                tp->recons = 0;
        !           596:                }
        !           597: 
        !           598:                /*
        !           599:                 * Enable interrupts.
        !           600:                 */
        !           601:                splo();
        !           602: 
        !           603:                return( 0 );
        !           604: 
        !           605:        default:
        !           606:                u.u_error = EINVAL;
        !           607:        }
        !           608: }
        !           609: 
        !           610: /*
        !           611:  * Polling Routine.
        !           612:  *
        !           613:  *     Note:   Double-looks are performed to prevent critical race with
        !           614:  *             interrupt handlers,  without having to disable interrupts.
        !           615:  */
        !           616: static
        !           617: tnpoll( dev, ev, msec )
        !           618: dev_t dev;
        !           619: int ev;
        !           620: int msec;
        !           621: {
        !           622:        register struct tnet_s * tp = &tnet[dev & 3];
        !           623:        int code = (dev & 0x30) >> 4;
        !           624:        int rev = 0;
        !           625: 
        !           626:        /*
        !           627:         * Fast check for priority, input, and output polls.
        !           628:         * Priority poll checks for LAN UP/DOWN transition.
        !           629:         * Input    poll checks for a full receive buffer.
        !           630:         * Output   poll checks for an empty transmit buffer, or LAN down.
        !           631:         */
        !           632:        if ( (ev & POLLPRI) && (tp->pri != 0) )
        !           633:                rev |= POLLPRI;
        !           634:        if ( (ev & POLLIN) && (tp->RxBusy[code] != NULL) )
        !           635:                rev |= POLLIN;
        !           636:        if ( (ev & POLLOUT) && ((tp->TxIdle != 0) || (tp->bad[0] & 1)) )
        !           637:                rev |= POLLOUT;
        !           638: 
        !           639:        /*
        !           640:         * Fast check found an event, or this is a non-blocking poll.
        !           641:         */
        !           642:        if ( (rev != 0) || (msec == 0) )
        !           643:                return( rev );
        !           644: 
        !           645:        /*
        !           646:         * Blocking Input poll.
        !           647:         */
        !           648:        if ( ev & POLLIN ) {
        !           649: 
        !           650:                pollopen( &tp->RxPoll[code] );
        !           651: 
        !           652:                /*
        !           653:                 * Second look to avoid interrupt race.
        !           654:                 */
        !           655:                if ( tp->RxBusy[code] )
        !           656:                        return( POLLIN );
        !           657:        }
        !           658: 
        !           659:        /*
        !           660:         * Blocking Output poll.
        !           661:         */
        !           662:        if ( ev & POLLOUT ) {
        !           663: 
        !           664:                pollopen( &tp->TxPoll );
        !           665: 
        !           666:                /*
        !           667:                 * Second look to avoid interrupt race.
        !           668:                 * NOTE: When the LAN is down broadcasts [nid 0] are disabled.
        !           669:                 */
        !           670:                if ( (tp->TxIdle != 0) || (tp->bad[0] & 1) )
        !           671:                        return( POLLOUT );
        !           672:        }
        !           673: 
        !           674:        return( rev );
        !           675: }
        !           676: 
        !           677: /*
        !           678:  * Interrupt Entry Point - Card 0.
        !           679:  */
        !           680: void
        !           681: tn0intr()
        !           682: {
        !           683:        tnintr( &tnet[0] );
        !           684: }
        !           685: 
        !           686: /*
        !           687:  * Interrupt Entry Point - Card 1.
        !           688:  */
        !           689: void
        !           690: tn1intr()
        !           691: {
        !           692:        tnintr( &tnet[1] );
        !           693: }
        !           694: 
        !           695: /*
        !           696:  * Interrupt Entry Point - Card 2.
        !           697:  */
        !           698: void
        !           699: tn2intr()
        !           700: {
        !           701:        tnintr( &tnet[2] );
        !           702: }
        !           703: 
        !           704: /*
        !           705:  * Interrupt Entry Point - Card 3.
        !           706:  */
        !           707: void
        !           708: tn3intr()
        !           709: {
        !           710:        tnintr( &tnet[3] );
        !           711: }
        !           712: 
        !           713: /*
        !           714:  * Interrupt Handler.
        !           715:  *
        !           716:  *     Process transmit/receive interrupts.
        !           717:  */
        !           718: void
        !           719: tnintr( tp )
        !           720: register struct tnet_s * tp;
        !           721: {
        !           722:        register struct tnbuf_s * np;
        !           723:        register int csr;
        !           724:        int nid;
        !           725:        int n;
        !           726:        int bit;
        !           727: 
        !           728:        /*
        !           729:         * Read interrupt status.
        !           730:         * Disable interrupts to ensure edge occurs later.
        !           731:         */
        !           732:        csr = inb( NSR );
        !           733:        tp->tnmask = NI_RECON;
        !           734:        outb( NIR, 0 );
        !           735: 
        !           736:        /*
        !           737:         * Reconfigurations with a period of 840 msec [600-1100]
        !           738:         * increment tp->recon.  Other periods clear tp->recon.
        !           739:         * After 5 reconfigurations at 840 msecs, the network is down.
        !           740:         * After 1 reconfiguration at another interval, the network is up.
        !           741:         * Network also comes up in tncycle() 5 seconds after last reconfig.
        !           742:         */
        !           743:        if ( csr & NS_RECON ) {
        !           744: 
        !           745:                outb( NCR, NC_RECON );
        !           746:                nid = (unsigned) (lbolt - tp->rbolt) * (1000/HZ);
        !           747:                tp->rbolt = lbolt;
        !           748:                tp->recons++;
        !           749: 
        !           750:                /*
        !           751:                 * Not a chained reconfiguration.
        !           752:                 * Assume the network is up.
        !           753:                 * NOTE: Expect 840 msecs, but allow interrupt latency slip.
        !           754:                 */
        !           755:                if ( (nid < 700) || (nid > 1000) ) {
        !           756:                        if ( tp->bad[0] & 1 ) {
        !           757:                                tp->mod[0] |=  1;
        !           758:                                tp->bad[0] &= ~1;
        !           759:                                tp->pri = 1;
        !           760:                        }
        !           761:                        tp->recon   =  0;
        !           762:                }
        !           763: 
        !           764:                /*
        !           765:                 * Chained reconfiguration - threshold exceeded.
        !           766:                 */
        !           767:                else if ( (++(tp->recon) == 5) && ((tp->bad[0] & 1) == 0) ) {
        !           768:                        faddr_t fp = tp->statseg->s_faddr;
        !           769:                        aflong( fp+TnSTATMOD*4, 1 );
        !           770:                        memset( tp->bad, -1, sizeof(tp->bad) );
        !           771:                        tp->mod[0] |= 1;
        !           772:                        tp->pri = 1;
        !           773:                }
        !           774:        }
        !           775: 
        !           776:        /*
        !           777:         * Service Power on Resets.
        !           778:         */
        !           779:        if ( csr & NS_POR ) {
        !           780: 
        !           781:                csr &= ~(NS_RxRDY|NS_TxRDY);    /* Ignore receive/transmit */
        !           782:                outb( NCR, NC_DFC );            /* Define 2K buf config    */
        !           783:                outb( NCR, NC_POR );            /* Clear POR flag          */
        !           784: 
        !           785:                /*
        !           786:                 * Enable receiver
        !           787:                 */
        !           788:                if ( np = tp->RxIdle )
        !           789:                        outb( NCR, np->tn_ena );
        !           790: 
        !           791:                /*
        !           792:                 * Enable transmitter
        !           793:                 */
        !           794:                if ( np = tp->TxBusy )
        !           795:                        outb( NCR, np->tn_ena );
        !           796:        }
        !           797: 
        !           798:        /*
        !           799:         * Service transmit interupts if transmit is pending.
        !           800:         */
        !           801:        if ( np = tp->TxBusy ) {
        !           802: 
        !           803:                tp->tnmask |= NI_Tx;
        !           804: 
        !           805:                /*
        !           806:                 * Check for transmission completed.
        !           807:                 */
        !           808:                if ( csr & NS_TxRDY ) {
        !           809: 
        !           810:                        /*
        !           811:                         * Destination Node Id is in 2nd byte of packet.
        !           812:                         */
        !           813:                        np->tn_off = np->tn_base + 1;
        !           814:                        nid = tngetc( np );
        !           815: 
        !           816:                        /*
        !           817:                         * Get length of short/long packets.
        !           818:                         */
        !           819:                        n = 256 - tngetc(np);
        !           820:                        if ( n == 256 )
        !           821:                                n = 512 - tngetc(np);
        !           822: 
        !           823:                        /*
        !           824:                         * Transmitted packet was acknowledged.
        !           825:                         */
        !           826:                        if ( csr & NS_TxACK ) {
        !           827:                                /*
        !           828:                                 * Adjust global and node statistics.
        !           829:                                 */
        !           830:                                faddr_t fp = tp->statseg->s_faddr;
        !           831:                                aflong( fp+TnTxPACKS*4, 1 );
        !           832:                                aflong( fp+TnTxBYTES*4, n );
        !           833:                                fp += nid * (NTNST * 4);
        !           834:                                aflong( fp+TnTxPACKS*4, 1 );
        !           835:                                aflong( fp+TnTxBYTES*4, n );
        !           836:                        }
        !           837: 
        !           838:                        /*
        !           839:                         * Transmitted packet was discarded.
        !           840:                         * NOTE: Do not flag broadcast [nid 0] as bad.
        !           841:                         */
        !           842:                        else if ( nid != 0 ) {
        !           843:                                /*
        !           844:                                 * Adjust global and node statistics.
        !           845:                                 */
        !           846:                                faddr_t fp = tp->statseg->s_faddr;
        !           847:                                aflong( fp+TnDISCARD*4, 1 );
        !           848:                                fp += nid * (NTNST * 4);
        !           849:                                aflong( fp+TnDISCARD*4, 1 );
        !           850:                                aflong( fp+TnSTATMOD*4, 1 );
        !           851: 
        !           852:                                /*
        !           853:                                 * Flag node as being bad.
        !           854:                                 */
        !           855:                                bit = bitm[ nid % 8 ];
        !           856:                                tp->bad[ nid / 8 ] |= bit;
        !           857:                                tp->mod[ nid / 8 ] |= bit;
        !           858:                                tp->pri = 1;
        !           859:                        }
        !           860: 
        !           861:                        /*
        !           862:                         * Move packet buffer to idle transmit queue.
        !           863:                         */
        !           864:                        tp->TxBusy  = np->tn_next;
        !           865:                        np->tn_next = tp->TxIdle;
        !           866:                        tp->TxIdle  = np;
        !           867: 
        !           868:                        /*
        !           869:                         * Check for another packet to transmit.
        !           870:                         */
        !           871:                        if ( np = tp->TxBusy ) {
        !           872: 
        !           873:                                /*
        !           874:                                 * Enable transmitter, start watchdog timer.
        !           875:                                 */
        !           876:                                outb( NCR, np->tn_ena );
        !           877:                                tp->tntime = TNTIME;
        !           878:                        }
        !           879: 
        !           880:                        /*
        !           881:                         * Disable Transmit Interrupt, clear watchdog timer.
        !           882:                         */
        !           883:                        else {
        !           884:                                tp->tnmask &= ~NI_Tx;
        !           885:                                tp->tntime  =  0;
        !           886:                        }
        !           887: 
        !           888:                        /*
        !           889:                         * Wake processes waiting to transmit.
        !           890:                         */
        !           891:                        if ( tp->TxReq ) {
        !           892:                                tp->TxReq = 0;
        !           893:                                defer( wakeup, &tp->TxReq );
        !           894:                        }
        !           895: 
        !           896:                        if ( tp->TxPoll.e_procp )
        !           897:                                defer( pollwake, &tp->TxPoll );
        !           898:                }
        !           899:        }
        !           900: 
        !           901:        /*
        !           902:         * Check for receive request.
        !           903:         */
        !           904:        if ( np = tp->RxIdle ) {
        !           905: 
        !           906:                tp->tnmask |= NI_Rx;
        !           907: 
        !           908:                /*
        !           909:                 * Check for packet received.
        !           910:                 */
        !           911:                if ( csr & NS_RxRDY ) {
        !           912: 
        !           913:                        /*
        !           914:                         * Remove first packet from receive ready queue.
        !           915:                         * Re-enable receiver or disable receive interrupts.
        !           916:                         */
        !           917:                        if ( tp->RxIdle = np->tn_next ) {
        !           918:                                outb( NCR, np->tn_next->tn_ena );
        !           919:                                np->tn_next = 0;
        !           920:                        }
        !           921:                        else
        !           922:                                tp->tnmask &= ~NI_Rx;
        !           923: 
        !           924:                        /*
        !           925:                         * Source Node Id is in 1st byte of packet.
        !           926:                         */
        !           927:                        np->tn_off = np->tn_base;
        !           928:                        nid = tngetc( np );
        !           929: 
        !           930:                        /*
        !           931:                         * Try to establish our Node Id if not already set.
        !           932:                         * Destination Node Id (our station)
        !           933:                         * is in 2nd byte of the received packet.
        !           934:                         * NOTE: Always read node id byte.
        !           935:                         *       This ensures offset bytes can be read.
        !           936:                         */
        !           937:                        if ( (n = tngetc(np)) && (tp->tnaddr[0] == 0) )
        !           938:                                tp->tnaddr[0] = n;
        !           939: 
        !           940:                        /*
        !           941:                         * Get offset to first data byte in short/long packet.
        !           942:                         * Short packet offset is in 3rd byte of packet.
        !           943:                         * Long  packet offset is in 4th byte of packet.
        !           944:                         */
        !           945:                        if ( n = tngetc(np) )
        !           946:                                np->tn_off = np->tn_base + n;
        !           947:                        else
        !           948:                                np->tn_off = np->tn_base + tngetc(np);
        !           949: 
        !           950:                        /*
        !           951:                         * LAN has come up.
        !           952:                         * Clear bad flag for the broadcast node.
        !           953:                         */
        !           954:                        if ( tp->bad[0] & 1 ) {
        !           955:                                tp->bad[ 0 ] &= ~1;
        !           956:                                tp->mod[ 0 ] |=  1;
        !           957:                                tp->pri = 1;
        !           958:                        }
        !           959: 
        !           960:                        /*
        !           961:                         * Node has come up.
        !           962:                         * Clear bad flag for the Source Node.
        !           963:                         */
        !           964:                        bit = bitm[ nid % 8 ];
        !           965:                        if ( tp->bad[ nid / 8 ] & bit ) {
        !           966:                                faddr_t fp = tp->statseg->s_faddr;
        !           967:                                aflong( fp+TnSTATMOD*4, 1 );
        !           968:                                fp += nid * (NTNST * 4);
        !           969:                                aflong( fp+TnSTATMOD*4, 1 );
        !           970:                                tp->bad[ nid / 8 ] &= ~bit;
        !           971:                                tp->mod[ nid / 8 ] |=  bit;
        !           972:                                tp->pri = 1;
        !           973:                        }
        !           974: 
        !           975:                        /*
        !           976:                         * Get first data byte from packet.
        !           977:                         */
        !           978:                        bit = tngetc( np );
        !           979: 
        !           980:                        /*
        !           981:                         * Determine prefix code associated with packet.
        !           982:                         */
        !           983:                        for ( n = 3; n > 0; n-- ) {
        !           984:                                if ( TNPREFIX[n] == bit )
        !           985:                                        break;
        !           986:                        }
        !           987: 
        !           988:                        /*
        !           989:                         * Interface is open.
        !           990:                         */
        !           991:                        if ( tp->refc[n] ) {
        !           992: 
        !           993:                                /*
        !           994:                                 * Append received packet to received queue.
        !           995:                                 * NOTE: At most 2 packets in any queue.
        !           996:                                 */
        !           997:                                if ( tp->RxBusy[n] )
        !           998:                                        tp->RxBusy[n]->tn_next = np;
        !           999:                                else
        !          1000:                                        tp->RxBusy[n] = np;
        !          1001:        
        !          1002:                                /*
        !          1003:                                 * Wake processes waiting to read.
        !          1004:                                 */
        !          1005:                                if ( tp->RxReq[n] ) {
        !          1006:                                        tp->RxReq[n] = 0;
        !          1007:                                        defer( wakeup, &tp->RxReq[n] );
        !          1008:                                }
        !          1009:        
        !          1010:                                if ( tp->RxPoll[n].e_procp )
        !          1011:                                        defer( pollwake, &tp->RxPoll[n] );
        !          1012:                        }
        !          1013: 
        !          1014:                        /*
        !          1015:                         * Interface is closed.
        !          1016:                         * Return packet to end of receive idle queue.
        !          1017:                         */
        !          1018:                        else
        !          1019:                                tn_rxena( tp, np );
        !          1020:                }
        !          1021:        }
        !          1022: 
        !          1023:        /*
        !          1024:         * Restore interrupt mask.
        !          1025:         */
        !          1026:        outb( NIR, tp->tnmask );
        !          1027: }
        !          1028: 
        !          1029: /*
        !          1030:  * Read Routine.
        !          1031:  *
        !          1032:  *     Wait for a packet to be received.
        !          1033:  *     Transform packet header and copy packet body.
        !          1034:  *     Place packet buffer on receive idle queue.
        !          1035:  *     If receiver was inhibited, enable receiver.
        !          1036:  */
        !          1037: 
        !          1038: 
        !          1039: tnread ( dev, iop )
        !          1040: 
        !          1041: dev_t dev;
        !          1042: register IO * iop;
        !          1043: 
        !          1044: {
        !          1045:        register struct tnet_s  * tp = &tnet[ dev & 3 ];
        !          1046:        register struct tnbuf_s * np;
        !          1047:        int code = (dev & 0x30) >> 4;
        !          1048:        unsigned len;
        !          1049:        unsigned cnt;
        !          1050:        unsigned srcid;
        !          1051:        int s;
        !          1052: 
        !          1053:        /*
        !          1054:         * Driver information requested.
        !          1055:         */
        !          1056:        if ( iop->io_ioc <= 2 + sizeof(tp->bad) + sizeof(tp->mod) ) {
        !          1057: 
        !          1058:                /*
        !          1059:                 * Supply null byte, then our node id.
        !          1060:                 */
        !          1061:                ioputc( 0, iop );
        !          1062:                ioputc( tp->tnaddr[0], iop );
        !          1063: 
        !          1064:                /*
        !          1065:                 * Bad and modified node bit masks requested.
        !          1066:                 * Disable interrupts during transfer to prevent
        !          1067:                 * critical race with tnintr().
        !          1068:                 */
        !          1069:                if ( iop->io_ioc == sizeof(tp->bad) + sizeof(tp->mod) ) {
        !          1070:                        sphi();
        !          1071:                        iowrite( iop, tp->bad, sizeof(tp->bad) );
        !          1072:                        iowrite( iop, tp->mod, sizeof(tp->mod) );
        !          1073:                        kclear( tp->mod, sizeof(tp->mod) );
        !          1074:                        tp->pri = 0;
        !          1075:                        splo();
        !          1076:                }
        !          1077: 
        !          1078:                /*
        !          1079:                 * Bad node bit mask requested.
        !          1080:                 */
        !          1081:                else if ( iop->io_ioc == sizeof(tp->bad) )
        !          1082:                        iowrite( iop, tp->bad, sizeof(tp->bad) );
        !          1083: 
        !          1084:                return;
        !          1085:        }
        !          1086: 
        !          1087:        /*
        !          1088:         * Wait for packet reception.
        !          1089:         */
        !          1090:        for ( ; ; ) {
        !          1091: 
        !          1092:                s = sphi( );
        !          1093: 
        !          1094:                /*
        !          1095:                 * Check for received packet.
        !          1096:                 */
        !          1097:                if ( np = tp->RxBusy[code] ) {
        !          1098:                        tp->RxBusy[code] = np->tn_next;
        !          1099:                        np->tn_next = 0;
        !          1100:                        spl( s );
        !          1101:                        break;
        !          1102:                }
        !          1103: 
        !          1104:                /*
        !          1105:                 * Non-blocking reads.
        !          1106:                 */
        !          1107:                if ( iop->io_flag & IONDLY ) {
        !          1108:                        u.u_error = EAGAIN;
        !          1109:                        spl( s );
        !          1110:                        return;
        !          1111:                }
        !          1112: 
        !          1113:                tp->RxReq[code] = 1;
        !          1114: 
        !          1115:                sleep( &tp->RxReq[code], CVTTIN, IVTTIN, SVTTIN );
        !          1116:                spl( s );
        !          1117: 
        !          1118:                /*
        !          1119:                 * Check for pending signal.
        !          1120:                 */
        !          1121:                if ( nondsig() ) {
        !          1122:                        u.u_error = EINTR;
        !          1123:                        return;
        !          1124:                }
        !          1125:        }
        !          1126: 
        !          1127:        /*
        !          1128:         * Copy source and destination node ids
        !          1129:         */
        !          1130:        np->tn_off = np->tn_base;
        !          1131:        ioputc( srcid = tngetc(np), iop );
        !          1132:        ioputc( tngetc(np), iop );
        !          1133: 
        !          1134:        /*
        !          1135:         * Check for short packet.
        !          1136:         */
        !          1137:        if ( cnt = tngetc(np) ) {
        !          1138: 
        !          1139:                np->tn_off = np->tn_base + cnt;
        !          1140:                len = 256 - cnt;
        !          1141:        }
        !          1142: 
        !          1143:        /*
        !          1144:         * Check for long packet.
        !          1145:         */
        !          1146:        else if ( cnt = tngetc(np) ) {
        !          1147: 
        !          1148:                np->tn_off = np->tn_base + cnt;
        !          1149:                len = 512 - cnt;
        !          1150:        }
        !          1151: 
        !          1152:        /*
        !          1153:         * Check for non-empty packet.
        !          1154:         */
        !          1155:        if ( cnt != 0 ) {
        !          1156: 
        !          1157:                /*
        !          1158:                 * Truncate packet if necessary.
        !          1159:                 */
        !          1160:                if ( iop->io_ioc < len )
        !          1161:                        len = iop->io_ioc;
        !          1162: 
        !          1163:                /*
        !          1164:                 * Copy packet body.
        !          1165:                 */
        !          1166:                tucopy( np, iop->io_base, len );
        !          1167:                iop->io_ioc  -= len;
        !          1168:                iop->io_base += len;
        !          1169:        }
        !          1170: 
        !          1171:        /*
        !          1172:         * Adjust received data statistics.
        !          1173:         */
        !          1174:        if ( tp->statseg != NULL ) {
        !          1175:                faddr_t fp = tp->statseg->s_faddr;
        !          1176:                aflong( fp+TnRxPACKS*4, 1 );
        !          1177:                aflong( fp+TnRxBYTES*4, len );
        !          1178:                fp += srcid * (NTNST * 4);
        !          1179:                aflong( fp+TnRxPACKS*4, 1 );
        !          1180:                aflong( fp+TnRxBYTES*4, len );
        !          1181:        }
        !          1182: 
        !          1183:        /*
        !          1184:         * Enable packet reception with buffer.
        !          1185:         */
        !          1186:        tn_rxena( tp, np );
        !          1187: }
        !          1188: 
        !          1189: 
        !          1190: /*
        !          1191:  * Write Routine.
        !          1192:  *
        !          1193:  *     Wait for a empty transmit buffer to become available.
        !          1194:  *     Format the buffer and place on transmit queue.
        !          1195:  *     If transmit queue was empty, start transmitter.
        !          1196:  */
        !          1197: 
        !          1198: tnwrite ( dev, iop )
        !          1199: 
        !          1200: dev_t dev;
        !          1201: register IO * iop;
        !          1202: 
        !          1203: {
        !          1204:        register struct tnet_s  * tp = &tnet[ dev & 3 ];
        !          1205:        register struct tnbuf_s * np;
        !          1206:        unsigned len, cnt;
        !          1207:        int dstid;
        !          1208:        int s;
        !          1209: 
        !          1210:        /*
        !          1211:         * Validate size of write.
        !          1212:         */
        !          1213:        if ( ( iop->io_ioc < 3 ) || ( iop->io_ioc > 510 ) ) {
        !          1214:                u.u_error = EINVAL;
        !          1215:                return;
        !          1216:        }
        !          1217: 
        !          1218:        /*
        !          1219:         * Destination Node Id is 2nd byte of write.
        !          1220:         */
        !          1221:        iogetc( iop );
        !          1222:        dstid = iogetc( iop );
        !          1223: 
        !          1224:        /*
        !          1225:         * Wait for empty transmit buffer.
        !          1226:         */
        !          1227:        for ( ; ; ) {
        !          1228: 
        !          1229:                /*
        !          1230:                 * If Destination Node appears bad, set errno to EDATTN.
        !          1231:                 */
        !          1232:                if ( tp->bad[ dstid / 8 ] & (1 << (dstid % 8)) ) {
        !          1233:                        u.u_error = EDATTN;
        !          1234:                        return;
        !          1235:                }
        !          1236: 
        !          1237:                s = sphi( );
        !          1238: 
        !          1239:                /*
        !          1240:                 * Check for empty transmit buffer.
        !          1241:                 */
        !          1242:                if ( np = tp->TxIdle ) {
        !          1243: 
        !          1244:                        tp->TxIdle  = np->tn_next;
        !          1245:                        np->tn_next = 0;
        !          1246:                        spl( s );
        !          1247:                        break;
        !          1248:                }
        !          1249: 
        !          1250:                /*
        !          1251:                 * Non-blocking writes.
        !          1252:                 */
        !          1253:                if ( iop->io_flag & IONDLY ) {
        !          1254:                        /*
        !          1255:                         * Adjust delayed write stats.
        !          1256:                         */
        !          1257:                        faddr_t fp = tp->statseg->s_faddr;
        !          1258:                        aflong( fp+TnWRTDLYS*4, 1 );
        !          1259:                        fp += dstid * (NTNST * 4);
        !          1260:                        aflong( fp+TnWRTDLYS*4, 1 );
        !          1261: 
        !          1262:                        u.u_error = EAGAIN;
        !          1263:                        spl( s );
        !          1264:                        return;
        !          1265:                }
        !          1266: 
        !          1267:                tp->TxReq = 1;
        !          1268:                sleep( &tp->TxReq, CVTTOUT, IVTTOUT, SVTTOUT );
        !          1269:                spl( s );
        !          1270: 
        !          1271:                /*
        !          1272:                 * Check for pending signal.
        !          1273:                 */
        !          1274:                if ( nondsig() ) {
        !          1275:                        u.u_error = EINTR;
        !          1276:                        return;
        !          1277:                }
        !          1278:        }
        !          1279: 
        !          1280:        /*
        !          1281:         * Copy source and destination node ids
        !          1282:         * NOTE: Hardware inserts source node id automatically.
        !          1283:         */
        !          1284:        np->tn_off = np->tn_base;
        !          1285:        tnputc( np, 0 );
        !          1286:        tnputc( np, dstid );
        !          1287: 
        !          1288:        len = iop->io_ioc;
        !          1289: 
        !          1290:        /*
        !          1291:         * Check for long packet.
        !          1292:         */
        !          1293:        if ( len > 253 ) {
        !          1294:                tnputc( np, 0 );
        !          1295:                tnputc( np, cnt = 512 - len );
        !          1296:                np->tn_off = np->tn_base + cnt;
        !          1297:        }
        !          1298: 
        !          1299:        /*
        !          1300:         * Short packet.
        !          1301:         */
        !          1302:        else {
        !          1303:                tnputc( np, cnt = 256 - len );
        !          1304:                np->tn_off = np->tn_base + cnt;
        !          1305:        }
        !          1306: 
        !          1307:        /*
        !          1308:         * Copy packet body.
        !          1309:         */
        !          1310:        utcopy( iop->io_base, np, len );
        !          1311:        iop->io_base += len;
        !          1312:        iop->io_ioc  -= len;
        !          1313: 
        !          1314:        /*
        !          1315:         * Record length in header structure.
        !          1316:         */
        !          1317:        np->tn_xlen = iop->io_ioc;
        !          1318: 
        !          1319:        sphi();
        !          1320: 
        !          1321:        /*
        !          1322:         * Put packet on transmit ready queue, prime transmitter if necessary.
        !          1323:         */
        !          1324:        if ( ! tp->TxBusy ) {
        !          1325:                tp->TxBusy = np;
        !          1326:                outb( NCR, np->tn_ena );         /* enable transmitter  */
        !          1327:                outb( NIR, tp->tnmask |= NI_Tx); /* enable xmit intr    */
        !          1328:                tp->tntime = TNTIME;             /* restart watchdog    */
        !          1329:        }
        !          1330:        else
        !          1331:                tp->TxBusy->tn_next = np;
        !          1332: 
        !          1333:        spl(s);
        !          1334: }
        !          1335: 
        !          1336: /*
        !          1337:  * Enable packet reception with buffer.
        !          1338:  */
        !          1339: tn_rxena( tp, np )
        !          1340: register struct tnet_s  * tp;
        !          1341: register struct tnbuf_s * np;
        !          1342: {
        !          1343:        int s;
        !          1344: 
        !          1345:        s = sphi( );
        !          1346: 
        !          1347:        /*
        !          1348:         * Put packet on receive ready queue, prime receiver if necessary.
        !          1349:         */
        !          1350:        if ( tp->RxIdle == NULL ) {
        !          1351:                tp->RxIdle = np;
        !          1352:                outb( NCR, np->tn_ena );
        !          1353:                outb( NIR, tp->tnmask |= NI_Rx );
        !          1354:        }
        !          1355:        else
        !          1356:                tp->RxIdle->tn_next = np;
        !          1357: 
        !          1358:        np->tn_next = 0;
        !          1359:        spl( s );
        !          1360: }
        !          1361: 
        !          1362: /*
        !          1363:  * Adjust far long.
        !          1364:  */
        !          1365: static
        !          1366: aflong( fp, i )
        !          1367: faddr_t fp;
        !          1368: int i;
        !          1369: {
        !          1370:        long lw;
        !          1371: 
        !          1372:        fkcopy( fp, &lw, sizeof(lw) );
        !          1373:        lw += i;
        !          1374:        kfcopy( &lw, fp, sizeof(lw) );
        !          1375: }

unix.superglobalmegacorp.com

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