root/net/tcp/we.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. max
  2. wd_start
  3. wd8003_open
  4. wdget
  5. wd8003_start_xmit
  6. wd_put_bnd
  7. wd_get_bnd
  8. wd_get_cur
  9. wd_rcv
  10. wd_rx_over
  11. wd_trs
  12. wd8003_interrupt
  13. wd8003_init

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

/* [previous][next][first][last][top][bottom][index][help] */