Annotation of linux/net/tcp/we.c, revision 1.1.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.