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