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

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