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

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