root/net/inet/wd.c

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

DEFINITIONS

This source file includes following definitions.
  1. wdprobe
  2. wdprobe1
  3. wd_reset_8390
  4. wd_block_input
  5. wd_block_output
  6. wd_close_card

   1 /* wd.c: A WD80x3 ethernet driver for linux. */
   2 /*
   3     Written 1993 by Donald Becker.
   4     Copyright 1993 United States Government as represented by the
   5     Director, National Security Agency.  This software may be used and
   6     distributed according to the terms of the GNU Public License,
   7     incorporated herein by reference.
   8     
   9     This is a driver for the WD8003 and WD8013 ethercards.
  10 
  11     The Author may be reached as becker@super.org or
  12     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
  13 
  14     Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
  15 */
  16 
  17 static char *version =
  18     "wd.c:v0.99-10 5/28/93 Donald Becker (becker@super.org)\n";
  19 
  20 #include <linux/config.h>
  21 #include <linux/kernel.h>
  22 #include <linux/sched.h>
  23 #include <asm/io.h>
  24 #include <asm/system.h>
  25 #include <memory.h>
  26 
  27 #include "dev.h"
  28 #include "8390.h"
  29 
  30 
  31 extern void NS8390_init(struct device *dev, int startp);
  32 extern int ei_debug;
  33 extern struct sigaction ei_sigaction;
  34 
  35 int wdprobe(int ioaddr, struct device *dev);
  36 int wdprobe1(int ioaddr, struct device *dev);
  37 
  38 static void wd_reset_8390(struct device *dev);
  39 static int wd_block_input(struct device *dev, int count,
  40                           char *buf, int ring_offset);
  41 static void wd_block_output(struct device *dev, int count,
  42                             const unsigned char *buf, const start_page);
  43 static int wd_close_card(struct device *dev);
  44 
  45 
  46 #define WD_START_PG     0x00    /* First page of TX buffer */
  47 #define WD03_STOP_PG    0x20    /* Last page +1 of RX ring */
  48 #define WD13_STOP_PG    0x40    /* Last page +1 of RX ring */
  49 
  50 #define WD_CMDREG       0       /* Offset to ASIC command register. */
  51 #define  WD_RESET       0x80    /* Board reset, in WD_CMDREG. */
  52 #define  WD_MEMENB      0x40    /* Enable the shared memory. */
  53 #define WD_CMDREG5      5       /* Offset to 16-bit-only ASIC register 5. */
  54 #define  ISA16          0x80    /* Enable 16 bit access from the ISA bus. */
  55 #define  NIC16          0x40    /* Enable 16 bit access from the 8390. */
  56 #define WD_NIC_OFFSET   16      /* Offset to the 8390 NIC from the base_addr. */
  57 
  58 /*  Probe for the WD8003 and WD8013.  These cards have the station
  59     address PROM at I/O ports <base>+8 to <base>+13, with a checksum
  60     following. A Soundblaster can have the same checksum as an WDethercard,
  61     so we have an extra exclusionary check for it.
  62 
  63     The wdprobe1() routine initializes the card and fills the
  64     station address field. */
  65 
  66 int wdprobe(int ioaddr,  struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68     int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
  69 
  70     if (ioaddr > 0x100)
  71         return wdprobe1(ioaddr, dev);
  72 
  73     for (port = &ports[0]; *port; port++)
  74         if (inb(*port + 8) != 0xff
  75             && inb(*port + 9) != 0xff /* Extra check to avoid soundcard. */
  76             && wdprobe1(*port, dev))
  77             return *port;
  78     return 0;
  79 }
  80 
  81 int wdprobe1(int ioaddr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83   int i;
  84   unsigned char *station_addr = dev->dev_addr;
  85   int checksum = 0;
  86   int ancient = 0;              /* An old card without config registers. */
  87 
  88 #if defined(EI_DEBUG) && EI_DEBUG > 2
  89   printk("WD80x3 ethercard at %#3x:", ioaddr);
  90   for (i = 0; i < 16; i++) {
  91       printk(" %2.2X", inb(ioaddr+i));
  92   }  
  93   printk("\n");
  94   printk("WD80x3 ethercard at %#3x:", ioaddr+i);
  95   for (;i < 33; i++) {
  96       printk(" %2.2X", inb(ioaddr+i));
  97   }  
  98   printk("\n");
  99 #endif
 100   printk("WD80x3 ethercard probe at %#3x:", ioaddr);
 101   for (i = 0; i < 8; i++) {
 102       int inval = inb(ioaddr + 8 + i);
 103       checksum += inval;
 104       if (i < 6)
 105           printk(" %2.2X", (station_addr[i] = inval));
 106   }
 107   
 108   if ((checksum & 0xff) != 0xFF) {
 109       printk(" not found (%#2.2x).\n", checksum);
 110       return 0;
 111   }
 112 
 113   ei_status.name = "WD8003";
 114   ei_status.word16 = 0;
 115 
 116   /* The following PureData probe code was contributed by
 117      Mike Jagdis <jaggy@purplet.demon.co.uk>. */
 118   /* Puredata seem to do software configuration differently from
 119    * others so we have to check for them.
 120    */
 121   if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
 122       ei_status.name = "PDI8023";
 123 
 124       /* We can also check whether it is an 8 bit (-8), 16 bit (-16)
 125        * or dumb (Toshiba) card. The Toshiba version doesn't support
 126        * anything except jumper configuration.
 127        */
 128       switch (inb(ioaddr+2)) {
 129           case 0x03:
 130               ei_status.word16 = 0;
 131               ei_status.name = "PDI8023-8";
 132               break;
 133 
 134           case 0x05:
 135               /* Not sure really... */
 136               ei_status.word16 = 0;
 137               ei_status.name = "PDUC8023";
 138               break;
 139 
 140           case 0x0a:
 141               ei_status.word16 = 1;
 142               ei_status.name = "PDI8023-16";
 143               break;
 144 
 145           default:
 146               /* Either 0x01 (dumb) or they've released a new version. */
 147               ei_status.word16 = 0;
 148               ei_status.name = "PDI8023";
 149               break;
 150       }
 151       dev->mem_start = ((inb(ioaddr+5) & 0x1c) + 0xc0) << 12;
 152       dev->irq = (inb(ioaddr+5) >> 5) & 0x07;
 153       if (dev->irq == 7)
 154           dev->irq = 10;
 155       else
 156           dev->irq++;
 157   }                             /* End of PureData probe */
 158 
 159   /* This method of checking for a 16-bit board is borrowed from the
 160      we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
 161      I'm comparing the two method in alpha test to make certain they
 162      return the same result. */
 163 #ifndef FORCE_8BIT              /* Same define as we.c. */
 164   /* Check for 16 bit board - it doesn't have register 0/8 aliasing.
 165      Do NOT check i>=6 here -- it hangs some old 8003 boards! */
 166   for (i = 0; i < 6; i++)
 167       if (inb(ioaddr+i) != inb(ioaddr+8+i))
 168           break;
 169   if (i >= 6) {
 170       ancient = 1;
 171       ei_status.name = "WD8003-old";
 172   } else {
 173       int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
 174       outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
 175       if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
 176           && (tmp & 0x01) == 0x01   ) {         /* In a 16 slot. */
 177           int asic_reg5 = inb(ioaddr+WD_CMDREG5);
 178           /* Magic to set ASIC to word-wide mode. */
 179           outb( ISA16 | NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
 180           outb(tmp, ioaddr+1);
 181           ei_status.name = "WD8013";
 182           ei_status.word16 = 1;         /* We have a 16bit board here! */
 183       }
 184       outb(tmp, ioaddr+1);              /* Restore original reg1 value. */
 185   }
 186 #endif /* not FORCE_8BIT */
 187 
 188 #ifndef final_version
 189   if ( !ancient && (inb(ioaddr+1) & 0x01) != (ei_status.word16 & 0x01))
 190       printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
 191              ei_status.word16 ? 16:8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
 192 #endif
 193 
 194 #if defined(WD_SHMEM) && WD_SHMEM > 0x80000
 195   /* Allow an override.  */
 196   dev->mem_start = WD_SHMEM;
 197 #else
 198   if (dev->mem_start == 0) {
 199       /* Sanity and old 8003 check */
 200       int reg0 = inb(ioaddr);
 201       if (reg0 == 0xff) {
 202           /* Future plan: this could check a few likely locations first. */
 203           dev->mem_start = 0xd0000;
 204           printk(" assigning address %#x", dev->mem_start);
 205       } else {
 206           int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
 207           /* Some boards don't have the register 5 -- it returns 0xff. */
 208           if (high_addr_bits == 0x1f || ei_status.word16 == 0)
 209               high_addr_bits = 0x01;
 210           dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
 211       }
 212   }
 213 #endif
 214 
 215   /* The 8390 isn't at the base address -- the ASIC regs are there! */
 216   dev->base_addr = ioaddr+WD_NIC_OFFSET;
 217 
 218   ei_status.tx_start_page = WD_START_PG;
 219   ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 220   ei_status.stop_page = ei_status.word16 ? WD13_STOP_PG : WD03_STOP_PG;
 221 
 222   dev->rmem_start = dev->mem_start + TX_PAGES*256;
 223   dev->mem_end = dev->rmem_end
 224       = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
 225 
 226   if (dev->irq < 2) {
 227       int irqmap[] = {9,3,5,7,10,11,15,4};
 228       int reg1 = inb(ioaddr+1);
 229       int reg4 = inb(ioaddr+4);
 230       if (reg1 == 0xff){        /* Ack!! No way to read the IRQ! */
 231           dev->irq = ei_status.word16 ? 10 : 5;
 232       } else
 233           dev->irq = irqmap[((reg4 >> 5) & 0x03)
 234                             + (reg1 & 0x04)];
 235   } else if (dev->irq == 2)
 236       /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
 237          or don't know which one to set. */
 238       dev->irq = 9;
 239 
 240   /* Snarf the interrupt now.  There's no point in waiting since we cannot
 241      share and the board will usually be enabled. */
 242   { int irqval = irqaction (dev->irq, &ei_sigaction);
 243     if (irqval) {
 244         printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
 245         return 0;
 246     }
 247   }
 248 
 249   printk("\n%s: %s using IRQ %d with shared memory at %#x-%#x.\n",
 250          dev->name, ei_status.name, dev->irq, dev->mem_start, dev->mem_end-1);
 251   if (ei_debug > 1)
 252       printk(version);
 253 
 254 #if defined(EI_DEBUG) && EI_DEBUG > 2
 255   printk("%s: Address read from register is %#x, setting address %#x\n",
 256          ei_status.name,
 257          ((inb(ioaddr+WD_CMDREG5)&0x1f)<<19) + ((inb(ioaddr)&0x3f) << 13),
 258          dev->mem_start);
 259 #endif
 260 
 261   /* Map in the shared memory. Always set register 0 last to remain
 262      compatible with very old boards. */
 263   if (ei_status.word16)
 264       outb( ISA16 | NIC16 | ((dev->mem_start>>19) & 0x1f), ioaddr+WD_CMDREG5);
 265   outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), ioaddr); /* WD_CMDREG */
 266 
 267   ei_status.reset_8390 = &wd_reset_8390;
 268   ei_status.block_input = &wd_block_input;
 269   ei_status.block_output = &wd_block_output;
 270   dev->stop = &wd_close_card;
 271   NS8390_init(dev, 0);
 272 
 273   return dev->base_addr;
 274 }
 275 
 276 static void
 277 wd_reset_8390(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279     int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 280     int reset_start_time = jiffies;
 281 
 282     outb(WD_RESET, wd_cmd_port);
 283     if (ei_debug > 1) printk("resetting the WD80x3 t=%d...", jiffies);
 284     ei_status.txing = 0;
 285 
 286     sti();
 287     /* We shouldn't use the boguscount for timing, but this hasn't been
 288        checked yet, and you could hang your machine if jiffies break... */
 289     {
 290         int boguscount = 150000;
 291         while(jiffies - reset_start_time < 2)
 292             if (boguscount-- < 0) {
 293                 printk("jiffy failure (t=%d)...", jiffies);
 294                 break;
 295             }
 296     }
 297 
 298     /* Set up the ASIC registers, just in case something changed them. */
 299     if (ei_status.word16)
 300         outb(NIC16 | ((dev->mem_start>>19) & 0x1f),
 301              wd_cmd_port+WD_CMDREG5);
 302     outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
 303 
 304     while ((inb(dev->base_addr+EN0_ISR) & ENISR_RESET) == 0)
 305         if (jiffies - reset_start_time > 2) {
 306             printk("%s: wd_reset_8390() did not complete.\n", dev->name);
 307             break;
 308         }
 309 #if defined(EI_DEBUG) && EI_DEBUG > 2
 310     {
 311         int i;
 312         printk("\nWD80x3 ethercard at %#3x:", wd_cmd_port);
 313         for (i = 0; i < 16; i++) {
 314             printk(" %2.2X", inb(wd_cmd_port+i));
 315         }  
 316         printk("\nWD80x3 ethercard at %#3x:", wd_cmd_port+i);
 317         for (;i < 33; i++) {
 318             printk(" %2.2X", inb(wd_cmd_port+i));
 319         }  
 320         printk("\n");
 321     }
 322 #endif
 323 }
 324 
 325 /* Block input and output are easy on shared memory ethercards, and trivial
 326    on the Western digital card where there is no choice of how to do it. */
 327 
 328 static int
 329 wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331     void *xfer_start = (void *)(dev->mem_start + ring_offset - (WD_START_PG<<8));
 332 #if !defined(WD_no_mapout)
 333     int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 334     int reg5_val = ((dev->mem_start>>19) & 0x1f) | NIC16;
 335 
 336     /* Map in the shared memory. */
 337     if (ei_status.word16)
 338         outb(ISA16 | reg5_val, wd_cmdreg + WD_CMDREG5 );
 339     outb((((dev->mem_start>>13) & 0x3f) | WD_MEMENB), wd_cmdreg);
 340 #endif
 341     if (xfer_start + count > (void*) dev->rmem_end) {
 342         /* We must wrap the input move. */
 343         int semi_count = (void*)dev->rmem_end - xfer_start;
 344         memcpy(buf, xfer_start, semi_count);
 345         count -= semi_count;
 346         memcpy(buf + semi_count, (char *)dev->rmem_start, count);
 347         return dev->rmem_start + count;
 348     }
 349     memcpy(buf, xfer_start, count);
 350     if (ei_debug > 4) {
 351         unsigned short *board = xfer_start;
 352         printk("%s: wd8013 block_input(cnt=%d offset=%3x addr=%#x) = %2x %2x %2x...\n",
 353                dev->name, count, ring_offset, xfer_start,
 354                board[-1], board[0], board[1]);
 355     }
 356 #if !defined(WD_no_mapout)
 357     /* Turn off 16 bit access so that reboot works. */
 358     if (ei_status.word16)
 359         outb(reg5_val, wd_cmdreg + WD_CMDREG5 );
 360 #endif
 361     return ring_offset + count;
 362 }
 363 
 364 /* This could only be outputting to the transmit buffer.  The
 365    ping-pong transmit setup doesn't work with this yet. */
 366 static void
 367 wd_block_output(struct device *dev, int count, const unsigned char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 368                 int start_page)
 369 {
 370     unsigned char *shmem
 371         = (void *)dev->mem_start + ((start_page - WD_START_PG)<<8);
 372 #if !defined(WD_no_mapout)
 373     int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 374     int reg5_val = ((dev->mem_start>>19) & 0x1f) | NIC16;
 375 
 376     /* Map in the shared memory. */
 377     if (ei_status.word16)
 378         outb(ISA16 | reg5_val, wd_cmdreg + WD_CMDREG5 );
 379     outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmdreg);
 380 #endif
 381     memcpy(shmem, buf, count);
 382     if (ei_debug > 4)
 383         printk("%s: wd80*3 block_output(addr=%#x cnt=%d) -> %2x=%2x %2x=%2x %d...\n",
 384                shmem, count, shmem[23], buf[23], shmem[24], buf[24], memcmp(shmem,buf,count));
 385 #if !defined(WD_no_mapout)
 386     /* Turn off 16 bit access so that reboot works. */
 387     if (ei_status.word16)
 388         outb(reg5_val, wd_cmdreg + WD_CMDREG5 );
 389 #endif
 390 }
 391 
 392 /* This function resets the ethercard if something screws up. */
 393 static int
 394 wd_close_card(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 395 {
 396     int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 397 
 398     if (ei_debug > 1)
 399         printk("%s: Shutting down ethercard.\n", dev->name);
 400     NS8390_init(dev, 0);
 401 
 402     /* Turn off 16-bit shared memory so reboot works. */
 403     outb(((dev->mem_start>>19) & 0x1f) | NIC16, wd_cmdreg + WD_CMDREG5 );
 404     outb((((dev->mem_start>>13) & 0x3f)), wd_cmdreg);
 405 
 406     return 0;
 407 }
 408 
 409 
 410 /*
 411  * Local variables:
 412  *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c wd.c"
 413  *  version-control: t
 414  *  kept-new-versions: 5
 415  * End:
 416  */

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