Annotation of linux/net/tcp/we.c, revision 1.1

1.1     ! root        1: /* we.c an wd8003 and wd8013 ethernet driver for linux. */
        !             2: /*
        !             3:     Copyright (C) 1992  Ross Biro
        !             4: 
        !             5:     This program is free software; you can redistribute it and/or modify
        !             6:     it under the terms of the GNU General Public License as published by
        !             7:     the Free Software Foundation; either version 2, or (at your option)
        !             8:     any later version.
        !             9: 
        !            10:     This program is distributed in the hope that it will be useful,
        !            11:     but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            12:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            13:     GNU General Public License for more details.
        !            14: 
        !            15:     You should have received a copy of the GNU General Public License
        !            16:     along with this program; if not, write to the Free Software
        !            17:     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
        !            18: 
        !            19:     The Author may be reached as [email protected] or
        !            20:     C/O Department of Mathematics; Stanford University; Stanford, CA 94305
        !            21: */
        !            22: /* The bsd386 version was used as an example in order to write this
        !            23:    code */
        !            24: 
        !            25: /*
        !            26:        The driver was significantly modified by Bob Harris to allow the
        !            27:        software to operate with either the wd8003 or wd8013 boards.  The
        !            28:        wd8013 boards will operate using full memory on board (as specified
        !            29:        by the user in Space.c) and the 16 bit wide interface.  The driver
        !            30:        will autodetect which board it is using on boot (i.e. "using 16 bit I/F").
        !            31:        In addition, the interrupts structure was significantly modified to 
        !            32:        respond to all the chips interrupts and to keep track of statistics.
        !            33:        The statistics are not currently used.  Debug messages can be toggled
        !            34:        by setting the wd_debug variable to a non-zero number.   The driver 
        !            35:        can detect an open or shorted cable - the wd8013 board functions after
        !            36:        the problem is corrected, but the wd8003 board does not always recover.
        !            37:        The driver is gradually being migrated toward the National Semiconductor
        !            38:        recommendations.  Constructive comments or suggestions can be sent to:
        !            39: 
        !            40:                Bob Harris, [email protected]
        !            41:                7926 Jones Branch Drive, Suite 900
        !            42:                McLean, Va. 22102
        !            43: */
        !            44: /* Note:  My driver was full of bugs.  Basically if it works, credit
        !            45:    Bob Harris.  If it's broken blame me.  -RAB */
        !            46: 
        !            47: #include <linux/config.h>
        !            48: #include <linux/kernel.h>
        !            49: #include <linux/sched.h>
        !            50: #include <linux/fs.h>
        !            51: #include <linux/tty.h>
        !            52: #include <linux/types.h>
        !            53: #include <linux/ptrace.h>
        !            54: #include <asm/system.h>
        !            55: #include <asm/segment.h>
        !            56: #include <asm/io.h>
        !            57: #include <asm/memory.h>
        !            58: #include <errno.h>
        !            59: #include <linux/fcntl.h>
        !            60: #include <netinet/in.h>
        !            61: 
        !            62: #include "dev.h"
        !            63: #include "eth.h"
        !            64: #include "timer.h"
        !            65: #include "ip.h"
        !            66: #include "tcp.h"
        !            67: #include "sock.h"
        !            68: #include "arp.h"
        !            69: 
        !            70: #include "wereg.h"
        !            71: 
        !            72: static unsigned char interrupt_mask;
        !            73: /* format of status byte. 
        !            74:    bit 
        !            75:     0  start
        !            76:     1  open
        !            77:     2   transmitter in use */
        !            78: 
        !            79: #define START 1
        !            80: #define OPEN  2
        !            81: #define TRS_BUSY 0x400
        !            82: #define IN_INT 8
        !            83: 
        !            84: /* We need to get rid of all these statics and move them into the
        !            85:    device structure that way we can have more than one wd8003 board
        !            86:    in the system at once. */
        !            87: 
        !            88: static volatile unsigned int status;
        !            89: 
        !            90: static struct enet_statistics stats;   /* Statistics collection */
        !            91: static unsigned char max_pages;                /* Board memory/256 */
        !            92: static unsigned char wd_debug = 0;     /* turns on/off debug messages */
        !            93: static unsigned char dconfig = WD_DCONFIG;     /* default data configuration */
        !            94: static int tx_aborted = 0;                     /* Empties tx bit bucket */
        !            95: 
        !            96: static  int
        !            97: max(int a, int b)
        !            98: {
        !            99:   if (a>b) return (a);
        !           100:   return (b);
        !           101: }
        !           102: 
        !           103: static  void
        !           104: wd_start(struct device *dev)
        !           105: {
        !           106:   unsigned char cmd;
        !           107:   interrupt_mask=RECV_MASK|TRANS_MASK;
        !           108:   cli();
        !           109:   cmd = inb_p(WD_COMM);
        !           110:   cmd &= ~(CSTOP|CPAGE);
        !           111:   cmd |= CSTART;
        !           112:   outb_p(cmd, WD_COMM);
        !           113:   outb_p(interrupt_mask,WD_IMR);
        !           114:   sti();
        !           115:   status |= START;
        !           116: }
        !           117: 
        !           118: int
        !           119: wd8003_open(struct device *dev)
        !           120: {
        !           121:   unsigned char cmd;
        !           122:   int i;
        !           123:   /* we probably don't want to be interrupted here. */
        !           124:   cli();
        !           125:   /* This section of code is mostly copied from the bsd driver which is
        !           126:      mostly copied from somewhere else. */
        !           127:   /* The somewhere else is probably the cmwymr(sp?) dos packet driver */
        !           128: 
        !           129:   cmd=inb_p(WD_COMM);
        !           130:   cmd|=CSTOP;
        !           131:   cmd &= ~(CSTART|CPAGE);
        !           132:   outb_p(cmd, WD_COMM);
        !           133:   outb_p(0, WD_IMR);
        !           134:   sti();
        !           135:   outb_p( dconfig,WD_DCR);
        !           136:   /*Zero the remote byte count. */
        !           137:   outb_p(0, WD_RBY0);
        !           138:   outb_p(0, WD_RBY1);
        !           139:   outb_p(WD_MCONFIG,WD_RCC);
        !           140:   outb_p(WD_TCONFIG,WD_TRC);
        !           141:   outb_p(0,WD_TRPG);            /* Set the transmit page start = 0 */
        !           142:   outb_p( max_pages,WD_PSTOP); /* (read) page stop = top of board memory */
        !           143:   outb_p(WD_TXBS,WD_PSTRT);    /* (read) page start = cur = bnd = top of tx memory */
        !           144:   outb_p(WD_TXBS,WD_BNDR);
        !           145:   /* clear interrupt status. */
        !           146:   outb_p(0xff,WD_ISR);
        !           147:   /* we don't want no stinking interrupts. */
        !           148:   outb_p(0 ,WD_IMR);
        !           149:   cmd|=1<<CPAGE_SHIFT;
        !           150:   outb_p(cmd,WD_COMM);
        !           151:   /* set the ether address. */
        !           152:   for (i=0; i < ETHER_ADDR_LEN; i++)
        !           153:     {
        !           154:       outb_p(dev->dev_addr[i],WD_PAR0+i);
        !           155:     }
        !           156:   /* National recommends setting the boundry < current page register */
        !           157:   outb_p(WD_TXBS+1,WD_CUR);    /* Set the current page = page start + 1 */
        !           158:   /* set the multicast address. */
        !           159:   for (i=0; i < ETHER_ADDR_LEN; i++)
        !           160:     {
        !           161:       outb_p(dev->broadcast[i],WD_MAR0+i);
        !           162:     }
        !           163: 
        !           164:   cmd&=~(CPAGE|CRDMA);
        !           165:   cmd|= 4<<CRDMA_SHIFT;
        !           166:   outb_p(cmd, WD_COMM);
        !           167:   outb_p(WD_RCONFIG,WD_RCC);
        !           168:   status = OPEN;
        !           169:   wd_start(dev); 
        !           170:   return (0);
        !           171: }
        !           172: 
        !           173: /* This routine just calls the ether rcv_int. */
        !           174: static  int
        !           175: wdget(struct wd_ring *ring, struct device *dev)
        !           176: {
        !           177:   unsigned char *fptr;
        !           178:   unsigned long len;
        !           179:   fptr = (unsigned char *)(ring +1);
        !           180:   len = ring->count-4;
        !           181:   return (dev_rint(fptr, len, 0, dev));
        !           182: }
        !           183: 
        !           184: int
        !           185: wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
        !           186: {
        !           187:   unsigned char cmd;
        !           188:   int len;
        !           189:   cli();
        !           190:   if (status & TRS_BUSY)
        !           191:     {
        !           192:        /* put in a time out. */
        !           193:        if (jiffies - dev->trans_start < 30)
        !           194:         return (1);
        !           195:        printk ("wd8003 transmit timed out. \n");
        !           196:     }
        !           197:   status |= TRS_BUSY;
        !           198:   sti();
        !           199: 
        !           200:   if (!skb->arp)
        !           201:     {
        !           202:       if ( dev->rebuild_header (skb+1, dev)) 
        !           203:        {
        !           204:           skb->dev = dev;
        !           205:           arp_queue (skb);
        !           206:           status &= ~TRS_BUSY;
        !           207:           return (0);
        !           208:        }
        !           209:     }
        !           210: 
        !           211:   memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);
        !           212: 
        !           213:   len = skb->len;
        !           214: 
        !           215:   /* now we need to set up the card info. */
        !           216:   dev->trans_start = jiffies;
        !           217:   len=max(len, ETHER_MIN_LEN); /* actually we should zero out
        !           218:                                  the extra memory. */
        !           219: /*  printk ("start_xmit len - %d\n", len);*/
        !           220:   cli();
        !           221:   cmd=inb_p(WD_COMM);
        !           222:   cmd &= ~CPAGE;
        !           223:   outb_p(cmd, WD_COMM);
        !           224: 
        !           225:   interrupt_mask |= TRANS_MASK;
        !           226:   if (!(status & IN_INT))
        !           227:     outb (interrupt_mask, WD_IMR);
        !           228: 
        !           229:   outb_p(len&0xff,WD_TB0);
        !           230:   outb_p(len>>8,WD_TB1);
        !           231:   cmd |= CTRANS;
        !           232:   outb_p(cmd,WD_COMM);
        !           233:   sti();
        !           234:   
        !           235:   if (skb->free)
        !           236:     {
        !           237:            free_skb (skb, FREE_WRITE);
        !           238:     }
        !           239: 
        !           240:   return (0);
        !           241: }
        !           242: 
        !           243: /* tell the card about the new boundary. */
        !           244: 
        !           245: static  void
        !           246: wd_put_bnd(unsigned char bnd, struct device *dev )
        !           247: {
        !           248: 
        !           249:        unsigned char cmd;
        !           250: 
        !           251:        /* Ensure page 0 selected */
        !           252:        cmd = inb_p( CR );
        !           253:        if (cmd & 0x40) {
        !           254:                outb_p(cmd & (~CPAGE1), WD_COMM);       /* select page 0 */
        !           255:                outb_p(bnd, WD_BNDR);
        !           256:                outb_p(cmd | CPAGE1, WD_COMM);  /* reselect page 1 */
        !           257:        } else {
        !           258:                outb_p(bnd, WD_BNDR);
        !           259:        }
        !           260: }
        !           261: 
        !           262: static  unsigned char
        !           263: wd_get_bnd( struct device *dev )
        !           264: {
        !           265: 
        !           266:        unsigned char   cmd, bnd;
        !           267: 
        !           268:        /* Ensure page 0 selected */
        !           269:        cmd = inb_p(WD_COMM);
        !           270:        if (cmd & 0x40) {
        !           271:                outb_p(cmd & (~CPAGE1), WD_COMM);       /* select page 0 */
        !           272:                bnd = inb_p(WD_BNDR);
        !           273:                outb_p(cmd | CPAGE1, WD_COMM);  /* reselect page 1 */
        !           274:                return (bnd);
        !           275:        } else {
        !           276:                return (inb_p(WD_BNDR));
        !           277:        }
        !           278: }
        !           279: 
        !           280: static  unsigned char
        !           281: wd_get_cur( struct device *dev )
        !           282: {
        !           283: 
        !           284:        unsigned char   cmd, cur;
        !           285: 
        !           286:        /* Ensure page 1 selected */
        !           287:        cmd = inb_p(WD_COMM);
        !           288:        if (cmd & 0x40) {
        !           289:                return (inb_p(WD_CUR));
        !           290:        } else {
        !           291:                outb_p(cmd | CPAGE1, WD_COMM);  /* select page 1 */
        !           292:                cur = inb_p(WD_CUR);
        !           293:                outb_p(cmd & (~CPAGE1), WD_COMM);       /* reselect page 0 */
        !           294:                return (cur);
        !           295:        }
        !           296: }
        !           297: 
        !           298: /* This routine handles the packet recieved interrupt. */
        !           299: /* Debug routines slow things down, but reveal bugs... */
        !           300: /* Modified Boundry Page Register to follow Current Page */
        !           301: 
        !           302: static  void
        !           303: wd_rcv( struct device *dev )
        !           304: {
        !           305:    
        !           306:    unsigned char   pkt;        /* Next packet page start */
        !           307:    unsigned char   bnd;        /* Last packet page end */
        !           308:    unsigned char   cur;        /* Future packet page start */
        !           309:    unsigned char   cmd;        /* Command register save */
        !           310:    struct wd_ring *ring;
        !           311:    int            done=0;
        !           312:    
        !           313:    /* Calculate next packet location */
        !           314:    cur = wd_get_cur( dev );
        !           315:    bnd = wd_get_bnd( dev );
        !           316:    if( (pkt = bnd + 1) == max_pages )
        !           317:      pkt = WD_TXBS;
        !           318:    
        !           319:    while( done != 1)
        !           320:      {
        !           321:        if (pkt != cur)
        !           322:          {
        !           323: 
        !           324:             /* Position pointer to packet in card ring buffer */
        !           325:             ring = (struct wd_ring *) (dev->mem_start + (pkt << 8));
        !           326:             
        !           327:             /* Ensure a valid packet */
        !           328:             if( ring->status & 1 )
        !           329:               { 
        !           330:                  /* Too small and too big packets are
        !           331:                     filtered by the board */
        !           332:                  if( wd_debug )
        !           333:                    printk("\nwd8013 - wdget: bnd = %d, pkt = %d, "
        !           334:                           "cur = %d, status = %d, len = %d, next = %d",
        !           335:                           bnd, pkt, cur, ring->status, ring->count,
        !           336:                           ring->next);
        !           337:                  
        !           338:                  stats.rx_packets++; /* count all receives */
        !           339:                  done = wdget( ring, dev ); /* get the packet */
        !           340:                  
        !           341:                  /* see if we need to process this packet again. */
        !           342:                  if (done == -1) continue;
        !           343: 
        !           344:                  /* Calculate next packet location */
        !           345:                  pkt = ring->next;
        !           346:                  
        !           347:                  /* Compute new boundry - tell the chip */
        !           348:                  if( (bnd = pkt - 1) < WD_TXBS )
        !           349:                    bnd = max_pages - 1;
        !           350:                  wd_put_bnd(bnd, dev);
        !           351:                  
        !           352:                  /* update our copy of cur. */
        !           353:                  cur = wd_get_cur(dev);
        !           354:               }
        !           355:             else 
        !           356:               {        /* Bad packet in ring buffer -
        !           357:                           should not happen due to hardware filtering */
        !           358:                  printk("wd8013 - bad packet: len = %d, status = x%x, "
        !           359:                         "bnd = %d, pkt = %d, cur = %d\n"
        !           360:                         "trashing receive buffer!",
        !           361:                         ring->count, ring->status, bnd, pkt,
        !           362:                         cur);
        !           363:                  /* Reset bnd = cur-1 */
        !           364:                  if( ( bnd = wd_get_cur( dev ) - 1 ) < WD_TXBS )
        !           365:                    bnd = max_pages - 1;
        !           366:                  wd_put_bnd( bnd, dev );
        !           367:                  break; /* return */
        !           368:               }
        !           369:             
        !           370:          }
        !           371:        else
        !           372:          {
        !           373:             done = dev_rint(NULL, 0,0, dev);
        !           374:          }
        !           375:      }
        !           376:    
        !           377:    /* reset to page 0 */
        !           378:    cmd = inb_p(WD_COMM);
        !           379:    if (cmd & 0x40)
        !           380:      {
        !           381:        outb_p(cmd & ~(CPAGE1), WD_COMM);       /* select page 0 */
        !           382:      }
        !           383: }
        !           384: 
        !           385: /* This routine handles the interrupt case of receiver overruns */
        !           386: 
        !           387: static  void
        !           388: wd_rx_over( struct device *dev )
        !           389: {
        !           390:        unsigned char cmd, dummy;
        !           391: 
        !           392:        /* Nothing actually has been overwritten */
        !           393:        /* the chip has stopped at the boundry */
        !           394:        /* but we must get it going again - according to National Semiconductor */
        !           395:        printk ("wd_rx_over\n");
        !           396:        cmd = inb_p( CR ); /* get current command register */
        !           397:        cmd = (cmd&~(STA|PS0|PS1))|STOP; /* toggle start and stop bits, select page 0 */
        !           398:        outb_p( cmd, CR );
        !           399:        dummy = inb_p( RBCR0 ); /* required to detect reset status */
        !           400:        dummy = inb_p( RBCR1 );
        !           401:        wd_rcv( dev );  /* clear out received packets */
        !           402:        
        !           403:        if( inb_p( ISR ) & PRX )
        !           404:                outb_p( PRX, ISR ); /* acknowledge RX interrupt */
        !           405:        while( ( inb_p( ISR ) & RST ) == 0 ); /* wait for reset to be completed */
        !           406:        outb_p( RST, ISR ); /* acknowledge RST interrupt */
        !           407:        outb_p( (cmd&~STOP)|STA, CR ); /* Start NIC */  
        !           408:        outb_p( WD_TCONFIG, TCR ); /* resume normal mode */
        !           409: }
        !           410: 
        !           411: /*
        !           412:  * This get's the transmit interrupts. It assumes command page 0 is set, and
        !           413:  * returns with command page 0 set.
        !           414:  */
        !           415: 
        !           416: static  void
        !           417: wd_trs( struct device *dev )
        !           418: {
        !           419:        unsigned char cmd, errors;
        !           420:        int len;
        !           421: 
        !           422:        if( wd_debug )
        !           423:                printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
        !           424: 
        !           425:        if( ( errors = inb_p( TSR ) & PTXOK  ) || tx_aborted ){
        !           426:                if( (errors&~0x02) == 0 ){
        !           427:                        stats.tx_packets++;
        !           428:                        tx_aborted = 0;
        !           429:                }
        !           430:                
        !           431:                /* attempt to start a new transmission. */
        !           432:                len = dev_tint( (unsigned char *)dev->mem_start, dev );
        !           433:                if( len != 0 ){
        !           434:                        len=max(len, ETHER_MIN_LEN);
        !           435:                        cmd=inb_p(WD_COMM);
        !           436:                        outb_p(len&0xff,WD_TB0);
        !           437:                        outb_p(len>>8,WD_TB1);
        !           438:                        cmd |= CTRANS;
        !           439:                        outb_p(cmd,WD_COMM);
        !           440:                        interrupt_mask |= TRANS_MASK;
        !           441:                }
        !           442:                else
        !           443:                {
        !           444:                        status &= ~TRS_BUSY;
        !           445:                        interrupt_mask &= ~TRANS_MASK;
        !           446:                        return;
        !           447:                }
        !           448:        }
        !           449:        else{ /* TX error occurred! - H/W will reschedule */
        !           450:                if( errors & CRS ){
        !           451:                        stats.tx_carrier_errors++;
        !           452:                        printk("\nwd8013 - network cable short!");
        !           453:                }
        !           454:                if (errors & COL )
        !           455:                        stats.collisions += inb_p( NCR );
        !           456:                if (errors & CDH )
        !           457:                        stats.tx_heartbeat_errors++;
        !           458:                if (errors & OWC )
        !           459:                        stats.tx_window_errors++;
        !           460:        }
        !           461: }
        !           462: 
        !           463: void
        !           464: wd8003_interrupt(int reg_ptr)
        !           465: {
        !           466:        unsigned char   cmd;
        !           467:        unsigned char   errors;
        !           468:        unsigned char   isr;
        !           469:        struct device *dev;
        !           470:        struct pt_regs *ptr;
        !           471:        int irq;
        !           472:        int count = 0;
        !           473: 
        !           474:        ptr = (struct pt_regs *)reg_ptr;
        !           475:        irq = -(ptr->orig_eax+2);
        !           476:        for (dev = dev_base; dev != NULL; dev = dev->next)
        !           477:          {
        !           478:             if (dev->irq == irq) break;
        !           479:          }
        !           480:        if (dev == NULL) 
        !           481:          {
        !           482:             printk ("we.c: irq %d for unknown device\n", irq);
        !           483:             return;
        !           484:          }
        !           485:        sti(); /* this could take a long time, we should have interrupts on. */
        !           486: 
        !           487:        cmd = inb_p( CR );/* Select page 0 */  
        !           488:        if( cmd & (PS0|PS1 ) ){
        !           489:                cmd &= ~(PS0|PS1);
        !           490:                outb_p(cmd, CR );
        !           491:        }
        !           492:        
        !           493:        if (wd_debug)
        !           494:                printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
        !           495: 
        !           496:        status |= IN_INT;
        !           497: 
        !           498:        do{ /* find out who called */ 
        !           499: 
        !           500:                /* Check for overrunning receive buffer first */
        !           501:                if ( ( isr = inb_p( ISR ) ) & OVW ) {   /* Receiver overwrite warning */
        !           502:                        stats.rx_over_errors++;
        !           503:                        if( wd_debug )
        !           504:                                printk("\nwd8013 overrun bnd = %d, cur = %d", wd_get_bnd( dev ), wd_get_cur( dev ) );
        !           505:                        wd_rx_over( dev ); /* performs wd_rcv() as well */
        !           506:                        outb_p( OVW, ISR ); /* acknowledge interrupt */
        !           507:                } 
        !           508:                else if ( isr & PRX ) { /* got a packet. */
        !           509:                        wd_rcv( dev );
        !           510:                        outb_p( PRX, ISR ); /* acknowledge interrupt */
        !           511:                }
        !           512:                /* This completes rx processing... whats next */
        !           513: 
        !           514:                if ( inb_p( ISR ) & PTX ) {     /* finished sending a packet. */
        !           515:                        wd_trs( dev );
        !           516:                        outb_p( PTX, ISR ); /* acknowledge interrupt */
        !           517:                }
        !           518: 
        !           519:                if (inb_p( ISR ) & RXE ) {      /* recieve error */
        !           520:                        stats.rx_errors++; /* general errors */
        !           521:                        errors = inb_p( RSR ); /* detailed errors */
        !           522:                        if (errors & CRC )
        !           523:                                stats.rx_crc_errors++;
        !           524:                        if (errors & FAE )
        !           525:                                stats.rx_frame_errors++;
        !           526:                        if (errors & FO )
        !           527:                                stats.rx_fifo_errors++;
        !           528:                        if (errors & MPA )
        !           529:                                stats.rx_missed_errors++;
        !           530:                        outb_p( RXE, ISR ); /* acknowledge interrupt */
        !           531:                }
        !           532: 
        !           533:                if (inb_p( ISR ) & TXE ) {      /* transmit aborted! */
        !           534:                        stats.tx_errors++; /* general errors */
        !           535:                        errors = inb_p( TSR ); /* get detailed errors */
        !           536:                        if (errors & ABT ){
        !           537:                                stats.tx_aborted_errors++;
        !           538:                                printk("\nwd8013 - network cable open!");
        !           539:                        }
        !           540:                        if (errors & FU )
        !           541:                                stats.tx_fifo_errors++;
        !           542:                                printk("\nwd8013 - TX FIFO underrun!");
        !           543: 
        !           544:                        /* Cannot do anymore - empty the bit bucket */
        !           545:                        tx_aborted = 1;
        !           546:                        wd_trs( dev );
        !           547:                        tx_aborted = 0;
        !           548: 
        !           549:                        outb_p( TXE, ISR ); /* acknowledge interrupt */
        !           550:                }
        !           551: 
        !           552:                if( inb_p( ISR ) & CNTE ){ /* Tally counters overflowing */
        !           553:                        errors = inb_p( CNTR0 );
        !           554:                        errors = inb_p( CNTR1 );
        !           555:                        errors = inb_p( CNTR2 );
        !           556:                        outb_p( CNTE, ISR ); /* acknowledge interrupt */
        !           557:                }
        !           558:                if( inb_p( ISR ) & RST ) /* Reset has been performed */
        !           559:                        outb_p( RST, ISR ); /* acknowledge interrupt */
        !           560: 
        !           561:                if( wd_debug ){
        !           562:                        if( ( isr = inb_p( ISR ) ) != 0 )
        !           563:                                printk("\nwd8013 - ISR not cleared = x%x", isr );
        !           564:                }
        !           565:                if( ++count > max_pages + 1 ){
        !           566:                        printk("\nwd8013_interrupt - infinite loop detected, isr = x%x, count = %d", isr, count );
        !           567:                }
        !           568: 
        !           569:        } while( inb_p( ISR ) != 0 );
        !           570: 
        !           571:        status &= ~IN_INT;
        !           572: }
        !           573: 
        !           574: 
        !           575: static struct sigaction wd8003_sigaction = 
        !           576: {
        !           577:    wd8003_interrupt,
        !           578:    0,
        !           579:    0,
        !           580:    NULL
        !           581: };
        !           582: 
        !           583: void
        !           584: wd8003_init(struct device *dev)
        !           585: {
        !           586:   unsigned char csum;
        !           587:   int i;
        !           588:   csum = 0;
        !           589:   for (i = 0; i < 8; i++)
        !           590:     {
        !           591:       csum += inb_p(WD_ROM+i);
        !           592:     }
        !           593:   if (csum != WD_CHECK)
        !           594:     {
        !           595:       printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
        !           596: 
        !           597:       /* make sure no one can attempt to open the device. */
        !           598:       status = OPEN;
        !           599:       return;
        !           600:     }
        !           601:   printk("wd8013");
        !           602:   /* initialize the rest of the device structure. */
        !           603:   dev->mtu = 1500; /* eth_mtu */
        !           604:   dev->hard_start_xmit = wd8003_start_xmit;
        !           605:   dev->open = wd8003_open;
        !           606:   dev->hard_header = eth_hard_header;
        !           607:   dev->add_arp = eth_add_arp;
        !           608:   dev->type_trans = eth_type_trans;
        !           609:   dev->hard_header_len = sizeof (struct enet_header);
        !           610:   dev->addr_len = ETHER_ADDR_LEN;
        !           611:   dev->type = ETHER_TYPE;
        !           612:   dev->queue_xmit = dev_queue_xmit;
        !           613:   dev->rebuild_header = eth_rebuild_header;
        !           614:   for (i = 0; i < DEV_NUMBUFFS; i++)
        !           615:     dev->buffs[i] = NULL;
        !           616: 
        !           617: #ifndef FORCE_8BIT
        !           618:   /* check for 16 bit board - it doesn't have register 0/8 aliasing */
        !           619:   for (i = 0; i < 8; i++) {
        !           620:        if( inb_p( EN_SAPROM+i ) != inb_p( EN_CMD+i) ){
        !           621:                csum = inb_p( EN_REG1 ); /* fiddle with 16bit bit */
        !           622:                outb( csum ^ BUS16, EN_REG1 ); /* attempt to clear 16bit bit */
        !           623:                if( (csum & BUS16) == (inb_p( EN_REG1 ) & BUS16) ) {
        !           624:                        printk(", using 16 bit I/F ");
        !           625:                        dconfig |= 1; /* use word mode of operation */
        !           626:                        outb_p( LAN16ENABLE|MEMMASK, EN_REG5);
        !           627:                        outb( csum , EN_REG1 );
        !           628:                        break; /* We have a 16bit board here! */
        !           629:                }
        !           630:                outb( csum , EN_REG1 );
        !           631:        }
        !           632:     }
        !           633: #endif /* FORCE_8BIT */
        !           634: 
        !           635:   /* mapin the interface memory. */
        !           636:   outb_p(WD_IMEM,WD_CTL);
        !           637: 
        !           638:   /* clear the interface memory */
        !           639:   for (i = dev->mem_start; i < dev->mem_end; i++)
        !           640:     {
        !           641:       *((unsigned char *)i) = 0;
        !           642:       if (*((unsigned char *)i) != 0) 
        !           643:        {
        !           644:          printk ("WD Memory error.\n");
        !           645:          if( (i - dev->mem_start) > 4096 )
        !           646:                break;
        !           647:          else
        !           648:                status = OPEN;
        !           649:        }
        !           650:     }
        !           651:   /* Calculate how many pages of memory on board */
        !           652:   max_pages = ( i - dev->mem_start )/256;
        !           653: 
        !           654:   /* need to set up the dev->mem_end and dev->rmem_end */
        !           655:   dev->rmem_end = i;
        !           656:   dev->mem_end = i;
        !           657: 
        !           658:   /* print the initialization message, and the
        !           659:      ethernet address. */
        !           660:   printk (", %d pages memory, ethernet Address: ", max_pages );
        !           661:   for (i = 0; i <ETHER_ADDR_LEN; i++)
        !           662:     {
        !           663:       dev->dev_addr[i]=inb_p(WD_ROM+i);
        !           664:       dev->broadcast[i]=0xff;
        !           665:       printk ("%2.2X ",dev->dev_addr[i]);
        !           666:     }
        !           667: 
        !           668:   /* Clear the statistics */
        !           669:   for( i = 0; i < sizeof( struct enet_statistics ); i++ )
        !           670:        ((char *)&stats)[i] = 0;
        !           671: 
        !           672:   printk ("\n");
        !           673:   status = 0;
        !           674: 
        !           675:   if (irqaction (dev->irq, &wd8003_sigaction))
        !           676:     {
        !           677:        printk ("Unable to get IRQ%d for wd8013 board\n", dev->irq);
        !           678:     }
        !           679: }

unix.superglobalmegacorp.com

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