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            return (1);
 226          }
 227 
 228        printk ("wd8003 transmit timed out. \n");
 229     }
 230   dev->tbusy = 1;
 231 
 232   if (skb == NULL)
 233     {
 234       sti();
 235       wd_trs(dev);
 236       return (0);
 237     }
 238 
 239   /* this should check to see if it's been killed. */
 240   if (skb->dev != dev)
 241     {
 242       sti();
 243       return (0);
 244     }
 245 
 246 
 247   if (!skb->arp)
 248     {
 249       if ( dev->rebuild_header (skb+1, dev)) 
 250         {
 251           cli();
 252           if (skb->dev == dev)
 253             {
 254               arp_queue (skb);
 255             }
 256            cli (); /* arp_queue turns them back on. */
 257           dev->tbusy = 0;
 258            sti();
 259            return (0);
 260         }
 261     }
 262 
 263   memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);
 264 
 265   len = skb->len;
 266 
 267   /* now we need to set up the card info. */
 268   dev->trans_start = jiffies;
 269   len=max(len, ETHER_MIN_LEN); /* actually we should zero out
 270                                   the extra memory. */
 271 /*  printk ("start_xmit len - %d\n", len);*/
 272 
 273   cmd=inb_p(WD_COMM);
 274   cmd &= ~CPAGE;
 275   outb_p(cmd, WD_COMM);
 276 
 277   interrupt_mask |= TRANS_MASK;
 278   if (!(dev->interrupt))
 279     outb (interrupt_mask, WD_IMR);
 280 
 281   outb_p(len&0xff,WD_TB0);
 282   outb_p(len>>8,WD_TB1);
 283   cmd |= CTRANS;
 284   outb_p(cmd,WD_COMM);
 285   sti();
 286   
 287   if (skb->free)
 288     {
 289             kfree_skb (skb, FREE_WRITE);
 290     }
 291 
 292   return (0);
 293 }
 294 
 295 /* tell the card about the new boundary. */
 296 
 297 static  void
 298 wd_put_bnd(unsigned char bnd, struct device *dev )
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300 
 301         unsigned char cmd;
 302 
 303         /* Ensure page 0 selected */
 304         cmd = inb_p( CR );
 305         if (cmd & 0x40) {
 306                 outb_p(cmd & (~CPAGE1), WD_COMM);       /* select page 0 */
 307                 outb_p(bnd, WD_BNDR);
 308                 outb_p(cmd | CPAGE1, WD_COMM);  /* reselect page 1 */
 309         } else {
 310                 outb_p(bnd, WD_BNDR);
 311         }
 312 }
 313 
 314 static  unsigned char
 315 wd_get_bnd( struct device *dev )
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317 
 318         unsigned char   cmd, bnd;
 319 
 320         /* Ensure page 0 selected */
 321         cmd = inb_p(WD_COMM);
 322         if (cmd & 0x40) {
 323                 outb_p(cmd & (~CPAGE1), WD_COMM);       /* select page 0 */
 324                 bnd = inb_p(WD_BNDR);
 325                 outb_p(cmd | CPAGE1, WD_COMM);  /* reselect page 1 */
 326                 return (bnd);
 327         } else {
 328                 return (inb_p(WD_BNDR));
 329         }
 330 }
 331 
 332 static  unsigned char
 333 wd_get_cur( struct device *dev )
     /* [previous][next][first][last][top][bottom][index][help] */
 334 {
 335 
 336         unsigned char   cmd, cur;
 337 
 338         /* Ensure page 1 selected */
 339         cmd = inb_p(WD_COMM);
 340         if (cmd & 0x40) {
 341                 return (inb_p(WD_CUR));
 342         } else {
 343                 outb_p(cmd | CPAGE1, WD_COMM);  /* select page 1 */
 344                 cur = inb_p(WD_CUR);
 345                 outb_p(cmd & (~CPAGE1), WD_COMM);       /* reselect page 0 */
 346                 return (cur);
 347         }
 348 }
 349 
 350 /* This routine handles the packet recieved interrupt. */
 351 /* Debug routines slow things down, but reveal bugs... */
 352 /* Modified Boundry Page Register to follow Current Page */
 353 
 354 static  void
 355 wd_rcv( struct device *dev )
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357    
 358    unsigned char   pkt; /* Next packet page start */
 359    unsigned char   bnd; /* Last packet page end */
 360    unsigned char   cur; /* Future packet page start */
 361    unsigned char   cmd; /* Command register save */
 362    volatile struct wd_ring *ring;
 363    int             done=0;
 364    
 365    /* Calculate next packet location */
 366    cur = wd_get_cur( dev );
 367    bnd = wd_get_bnd( dev );
 368    if( (pkt = bnd + 1) == max_pages )
 369      pkt = WD_TXBS;
 370    
 371    while( done != 1)
 372      {
 373         if (pkt != cur)
 374           {
 375 
 376              /* Position pointer to packet in card ring buffer */
 377              ring = (volatile struct wd_ring *) (dev->mem_start + (pkt << 8));
 378              
 379              /* Ensure a valid packet */
 380              if( ring->status & 1 )
 381                { 
 382                   /* Too small and too big packets are
 383                      filtered by the board */
 384                   if( wd_debug )
 385                     printk("\nwd8013 - wdget: bnd = %d, pkt = %d, "
 386                            "cur = %d, status = %d, len = %d, next = %d",
 387                            bnd, pkt, cur, ring->status, ring->count,
 388                            ring->next);
 389                   
 390                   stats.rx_packets++; /* count all receives */
 391                   done = wdget( ring, dev ); /* get the packet */
 392                   
 393                   /* Calculate next packet location */
 394                   pkt = ring->next;
 395                   
 396                   /* Compute new boundry - tell the chip */
 397                   if( (bnd = pkt - 1) < WD_TXBS )
 398                     bnd = max_pages - 1;
 399                   wd_put_bnd(bnd, dev);
 400                   
 401                   /* update our copy of cur. */
 402                   cur = wd_get_cur(dev);
 403                }
 404              else 
 405                {        /* Bad packet in ring buffer -
 406                            should not happen due to hardware filtering */
 407                   printk("wd8013 - bad packet: len = %d, status = x%x, "
 408                          "bnd = %d, pkt = %d, cur = %d\n"
 409                          "trashing receive buffer!",
 410                          ring->count, ring->status, bnd, pkt,
 411                          cur);
 412                   /* Reset bnd = cur-1 */
 413                   if( ( bnd = wd_get_cur( dev ) - 1 ) < WD_TXBS )
 414                     bnd = max_pages - 1;
 415                   wd_put_bnd( bnd, dev );
 416                   break; /* return */
 417                }
 418              
 419           }
 420         else
 421           {
 422              done = dev_rint(NULL, 0,0, dev);
 423           }
 424      }
 425    
 426    /* reset to page 0 */
 427    cmd = inb_p(WD_COMM);
 428    if (cmd & 0x40)
 429      {
 430         outb_p(cmd & ~(CPAGE1), WD_COMM);       /* select page 0 */
 431      }
 432 }
 433 
 434 /* This routine handles the interrupt case of receiver overruns */
 435 
 436 static  void
 437 wd_rx_over( struct device *dev )
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439         unsigned char cmd, dummy;
 440 
 441         /* Nothing actually has been overwritten */
 442         /* the chip has stopped at the boundry */
 443         /* but we must get it going again - according to National Semiconductor */
 444         printk ("wd_rx_over\n");
 445         cmd = inb_p( CR ); /* get current command register */
 446         cmd = (cmd&~(STA|PS0|PS1))|STOP; /* toggle start and stop bits, select page 0 */
 447         outb_p( cmd, CR );
 448         dummy = inb_p( RBCR0 ); /* required to detect reset status */
 449         dummy = inb_p( RBCR1 );
 450         wd_rcv( dev );  /* clear out received packets */
 451         
 452         if( inb_p( ISR ) & PRX )
 453                 outb_p( PRX, ISR ); /* acknowledge RX interrupt */
 454         while( ( inb_p( ISR ) & RST ) == 0 ); /* wait for reset to be completed */
 455         outb_p( RST, ISR ); /* acknowledge RST interrupt */
 456         outb_p( (cmd&~STOP)|STA, CR ); /* Start NIC */  
 457         outb_p( WD_TCONFIG, TCR ); /* resume normal mode */
 458 }
 459 
 460 /*
 461  * This get's the transmit interrupts. It assumes command page 0 is set, and
 462  * returns with command page 0 set.
 463  */
 464 
 465 static  void
 466 wd_trs( struct device *dev )
     /* [previous][next][first][last][top][bottom][index][help] */
 467 {
 468         unsigned char errors;
 469 
 470         if( wd_debug )
 471                 printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
 472 
 473         if( ( errors = inb_p( TSR ) & PTXOK  ) || tx_aborted ){
 474                 if( (errors&~0x02) == 0 ){
 475                         stats.tx_packets++;
 476                         tx_aborted = 0;
 477                 }
 478                 dev->tbusy = 0;
 479                 mark_bh (INET_BH);
 480                 
 481 #if 0           
 482                 /* attempt to start a new transmission. */
 483                 len = dev_tint( (unsigned char *)dev->mem_start, dev );
 484                 if( len != 0 ){
 485                         len=max(len, ETHER_MIN_LEN);
 486                         cmd=inb_p(WD_COMM);
 487                         outb_p(len&0xff,WD_TB0);
 488                         outb_p(len>>8,WD_TB1);
 489                         cmd |= CTRANS;
 490                         outb_p(cmd,WD_COMM);
 491                         interrupt_mask |= TRANS_MASK;
 492                 }
 493                 else
 494                 {
 495                         dev->tbusy = 0
 496                         interrupt_mask &= ~TRANS_MASK;
 497                         return;
 498                 }
 499 #endif
 500       }
 501         else{ /* TX error occurred! - H/W will reschedule */
 502                 if( errors & CRS ){
 503                         stats.tx_carrier_errors++;
 504                         printk("\nwd8013 - network cable short!");
 505                 }
 506                 if (errors & COL )
 507                         stats.collisions += inb_p( NCR );
 508                 if (errors & CDH )
 509                         stats.tx_heartbeat_errors++;
 510                 if (errors & OWC )
 511                         stats.tx_window_errors++;
 512         }
 513 }
 514 
 515 void
 516 wd8003_interrupt(int reg_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518         unsigned char   cmd;
 519         unsigned char   errors;
 520         unsigned char   isr;
 521         struct device *dev;
 522         struct pt_regs *ptr;
 523         int irq;
 524         int count = 0;
 525 
 526         ptr = (struct pt_regs *)reg_ptr;
 527         irq = -(ptr->orig_eax+2);
 528         for (dev = dev_base; dev != NULL; dev = dev->next)
 529           {
 530              if (dev->irq == irq) break;
 531           }
 532         if (dev == NULL) 
 533           {
 534              printk ("we.c: irq %d for unknown device\n", irq);
 535              return;
 536           }
 537         sti(); /* this could take a long time, we should have interrupts on. */
 538 
 539         cmd = inb_p( CR );/* Select page 0 */  
 540         if( cmd & (PS0|PS1 ) ){
 541                 cmd &= ~(PS0|PS1);
 542                 outb_p(cmd, CR );
 543         }
 544         
 545         if (wd_debug)
 546                 printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
 547 
 548         dev->interrupt = 1;
 549 
 550         do{ /* find out who called */ 
 551           sti();
 552                 /* Check for overrunning receive buffer first */
 553                 if ( ( isr = inb_p( ISR ) ) & OVW ) {   /* Receiver overwrite warning */
 554                         stats.rx_over_errors++;
 555                         if( wd_debug )
 556                                 printk("\nwd8013 overrun bnd = %d, cur = %d", wd_get_bnd( dev ), wd_get_cur( dev ) );
 557                         wd_rx_over( dev ); /* performs wd_rcv() as well */
 558                         outb_p( OVW, ISR ); /* acknowledge interrupt */
 559                 } 
 560                 else if ( isr & PRX ) { /* got a packet. */
 561                         wd_rcv( dev );
 562                         outb_p( PRX, ISR ); /* acknowledge interrupt */
 563                 }
 564                 /* This completes rx processing... whats next */
 565 
 566                 if ( inb_p( ISR ) & PTX ) {     /* finished sending a packet. */
 567                         wd_trs( dev );
 568                         outb_p( PTX, ISR ); /* acknowledge interrupt */
 569                 }
 570 
 571                 if (inb_p( ISR ) & RXE ) {      /* recieve error */
 572                         stats.rx_errors++; /* general errors */
 573                         errors = inb_p( RSR ); /* detailed errors */
 574                         if (errors & CRC )
 575                                 stats.rx_crc_errors++;
 576                         if (errors & FAE )
 577                                 stats.rx_frame_errors++;
 578                         if (errors & FO )
 579                                 stats.rx_fifo_errors++;
 580                         if (errors & MPA )
 581                                 stats.rx_missed_errors++;
 582                         outb_p( RXE, ISR ); /* acknowledge interrupt */
 583                 }
 584 
 585                 if (inb_p( ISR ) & TXE ) {      /* transmit aborted! */
 586                         stats.tx_errors++; /* general errors */
 587                         errors = inb_p( TSR ); /* get detailed errors */
 588                         if (errors & ABT ){
 589                                 stats.tx_aborted_errors++;
 590                                 printk("\nwd8013 - network cable open!");
 591                         }
 592                         if (errors & FU )
 593                           {
 594                             stats.tx_fifo_errors++;
 595                             printk("\nwd8013 - TX FIFO underrun!");
 596                           }
 597 
 598                         /* Cannot do anymore - empty the bit bucket */
 599                         tx_aborted = 1;
 600                         wd_trs( dev );
 601                         tx_aborted = 0;
 602 
 603                         outb_p( TXE, ISR ); /* acknowledge interrupt */
 604                 }
 605 
 606                 if( inb_p( ISR ) & CNTE ){ /* Tally counters overflowing */
 607                         errors = inb_p( CNTR0 );
 608                         errors = inb_p( CNTR1 );
 609                         errors = inb_p( CNTR2 );
 610                         outb_p( CNTE, ISR ); /* acknowledge interrupt */
 611                 }
 612                 if( inb_p( ISR ) & RST ) /* Reset has been performed */
 613                         outb_p( RST, ISR ); /* acknowledge interrupt */
 614 
 615                 if( wd_debug ){
 616                         if( ( isr = inb_p( ISR ) ) != 0 )
 617                                 printk("\nwd8013 - ISR not cleared = x%x", isr );
 618                 }
 619                 if( ++count > max_pages + 1 ){
 620                         printk("\nwd8013_interrupt - infinite loop detected, isr = x%x, count = %d", isr, count );
 621                 }
 622                 cli();
 623         } while( inb_p( ISR ) != 0 );
 624 
 625         dev->interrupt = 0;
 626 }
 627 
 628 
 629 static struct sigaction wd8003_sigaction = 
 630 {
 631    wd8003_interrupt,
 632    0,
 633    0,
 634    NULL
 635 };
 636 
 637 int
 638 wd8003_init(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 639 {
 640   unsigned char csum;
 641   int i;
 642   csum = 0;
 643   for (i = 0; i < 8; i++)
 644     {
 645       csum += inb_p(WD_ROM+i);
 646     }
 647   if (csum != WD_CHECK)
 648     {
 649       printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
 650 
 651       /* make sure no one can attempt to open the device. */
 652       return (1);
 653     }
 654   printk("wd8013");
 655   /* initialize the rest of the device structure. */
 656   dev->mtu = 1500; /* eth_mtu */
 657   dev->hard_start_xmit = wd8003_start_xmit;
 658   dev->open = wd8003_open;
 659   dev->hard_header = eth_hard_header;
 660   dev->add_arp = eth_add_arp;
 661   dev->type_trans = eth_type_trans;
 662   dev->hard_header_len = sizeof (struct enet_header);
 663   dev->addr_len = ETHER_ADDR_LEN;
 664   dev->type = ETHER_TYPE;
 665   dev->queue_xmit = dev_queue_xmit;
 666   dev->rebuild_header = eth_rebuild_header;
 667   for (i = 0; i < DEV_NUMBUFFS; i++)
 668     dev->buffs[i] = NULL;
 669 
 670 #ifndef FORCE_8BIT
 671   /* check for 16 bit board - it doesn't have register 0/8 aliasing */
 672   for (i = 0; i < 8; i++) {
 673         if( inb_p( EN_SAPROM+i ) != inb_p( EN_CMD+i) ){
 674                 csum = inb_p( EN_REG1 ); /* fiddle with 16bit bit */
 675                 outb( csum ^ BUS16, EN_REG1 ); /* attempt to clear 16bit bit */
 676                 if( (csum & BUS16) == (inb_p( EN_REG1 ) & BUS16) ) {
 677                         printk(", using 16 bit I/F ");
 678                         dconfig |= 1; /* use word mode of operation */
 679                         outb_p( LAN16ENABLE|MEMMASK, EN_REG5);
 680                         outb( csum , EN_REG1 );
 681                         break; /* We have a 16bit board here! */
 682                 }
 683                 outb( csum , EN_REG1 );
 684         }
 685     }
 686 #endif /* FORCE_8BIT */
 687 
 688   /* mapin the interface memory. */
 689   outb_p(WD_IMEM,WD_CTL);
 690 
 691   /* clear the interface memory */
 692   for (i = dev->mem_start; i < dev->mem_end; i++)
 693     {
 694       *((unsigned char *)i) = 0;
 695       if (*((unsigned char *)i) != 0) 
 696         {
 697           printk ("WD Memory error.\n");
 698           if( (i - dev->mem_start) > 4096 )
 699                 break;
 700           else
 701                 return (1);
 702         }
 703     }
 704   /* Calculate how many pages of memory on board */
 705   max_pages = ( i - dev->mem_start )/256;
 706 
 707   /* need to set up the dev->mem_end and dev->rmem_end */
 708   dev->rmem_end = i;
 709   dev->mem_end = i;
 710 
 711   /* print the initialization message, and the
 712      ethernet address. */
 713   printk (", %d pages memory, ethernet Address: ", max_pages );
 714   for (i = 0; i <ETHER_ADDR_LEN; i++)
 715     {
 716       dev->dev_addr[i]=inb_p(WD_ROM+i);
 717       dev->broadcast[i]=0xff;
 718       printk ("%2.2X ",dev->dev_addr[i]);
 719     }
 720 
 721   /* Clear the statistics */
 722   for( i = 0; i < sizeof( struct enet_statistics ); i++ )
 723         ((char *)&stats)[i] = 0;
 724 
 725   printk ("\n");
 726   dev->tbusy = 0;
 727   dev->interrupt = 0;
 728 
 729   if (irqaction (dev->irq, &wd8003_sigaction))
 730     {
 731        printk ("Unable to get IRQ%d for wd8013 board\n", dev->irq);
 732        return (1);
 733     }
 734   return (0);
 735 }

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