root/drivers/net/wd.c

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

DEFINITIONS

This source file includes following definitions.
  1. wd_probe
  2. wdprobe1
  3. wd_open
  4. wd_reset_8390
  5. wd_block_input
  6. wd_block_output
  7. 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 WD8003 and WD8013 "compatible" 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-14 11/21/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 <linux/errno.h>
  24 #include <linux/string.h>
  25 #include <asm/io.h>
  26 #include <asm/system.h>
  27 
  28 #include "dev.h"
  29 #include "8390.h"
  30 
  31 /* Compatibility definitions for earlier kernel versions. */
  32 #ifndef HAVE_PORTRESERVE
  33 #define check_region(ioaddr, size)              0
  34 #define snarf_region(ioaddr, size)              do ; while (0)
  35 #endif
  36 
  37 int wd_probe(struct device *dev);
  38 int wdprobe1(int ioaddr, struct device *dev);
  39 
  40 static int wd_open(struct device *dev);
  41 static void wd_reset_8390(struct device *dev);
  42 static int wd_block_input(struct device *dev, int count,
  43                                                   char *buf, int ring_offset);
  44 static void wd_block_output(struct device *dev, int count,
  45                                                         const unsigned char *buf, const start_page);
  46 static int wd_close_card(struct device *dev);
  47 
  48 
  49 #define WD_START_PG             0x00    /* First page of TX buffer */
  50 #define WD03_STOP_PG    0x20    /* Last page +1 of RX ring */
  51 #define WD13_STOP_PG    0x40    /* Last page +1 of RX ring */
  52 
  53 #define WD_CMDREG               0               /* Offset to ASIC command register. */
  54 #define  WD_RESET               0x80    /* Board reset, in WD_CMDREG. */
  55 #define  WD_MEMENB              0x40    /* Enable the shared memory. */
  56 #define WD_CMDREG5              5               /* Offset to 16-bit-only ASIC register 5. */
  57 #define  ISA16                  0x80    /* Enable 16 bit access from the ISA bus. */
  58 #define  NIC16                  0x40    /* Enable 16 bit access from the 8390. */
  59 #define WD_NIC_OFFSET   16              /* Offset to the 8390 NIC from the base_addr. */
  60 
  61 /*      Probe for the WD8003 and WD8013.  These cards have the station
  62         address PROM at I/O ports <base>+8 to <base>+13, with a checksum
  63         following. A Soundblaster can have the same checksum as an WDethercard,
  64         so we have an extra exclusionary check for it.
  65 
  66         The wdprobe1() routine initializes the card and fills the
  67         station address field. */
  68 
  69 int wd_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71         int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
  72         short ioaddr = dev->base_addr;
  73 
  74         if (ioaddr < 0)
  75                 return ENXIO;                   /* Don't probe at all. */
  76         if (ioaddr > 0x100)
  77                 return ! wdprobe1(ioaddr, dev);
  78 
  79         for (port = &ports[0]; *port; port++) {
  80                 if (check_region(*port, 32))
  81                         continue;
  82                 if (inb(*port + 8) != 0xff
  83                         && inb(*port + 9) != 0xff /* Extra check to avoid soundcard. */
  84                         && wdprobe1(*port, dev))
  85                         return 0;
  86         }
  87         dev->base_addr = ioaddr;
  88         return ENODEV;
  89 }
  90 
  91 int wdprobe1(int ioaddr, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93         int i;
  94         unsigned char *station_addr = dev->dev_addr;
  95         int checksum = 0;
  96         int ancient = 0;                        /* An old card without config registers. */
  97         int word16 = 0;                         /* 0 = 8 bit, 1 = 16 bit */
  98         char *model_name;
  99         
 100         for (i = 0; i < 8; i++)
 101                 checksum += inb(ioaddr + 8 + i);
 102         if ((checksum & 0xff) != 0xFF)
 103                 return 0;
 104         
 105         printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
 106         for (i = 0; i < 6; i++)
 107                 printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
 108         
 109         /* The following PureData probe code was contributed by
 110            Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
 111            configuration differently from others so we have to check for them.
 112            This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
 113            */
 114         if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
 115                 unsigned char reg5 = inb(ioaddr+5);
 116                 
 117                 switch (inb(ioaddr+2)) {
 118                 case 0x03: word16 = 0; model_name = "PDI8023-8";        break;
 119                 case 0x05: word16 = 0; model_name = "PDUC8023"; break;
 120                 case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
 121                         /* Either 0x01 (dumb) or they've released a new version. */
 122                 default:         word16 = 0; model_name = "PDI8023";    break;
 123                 }
 124                 dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
 125                 dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
 126         } else {                                                                /* End of PureData probe */
 127                 /* This method of checking for a 16-bit board is borrowed from the
 128                    we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
 129                    I'm comparing the two method in alpha test to make certain they
 130                    return the same result. */
 131                 /* Check for the old 8 bit board - it has register 0/8 aliasing.
 132                    Do NOT check i>=6 here -- it hangs the old 8003 boards! */
 133                 for (i = 0; i < 6; i++)
 134                         if (inb(ioaddr+i) != inb(ioaddr+8+i))
 135                                 break;
 136                 if (i >= 6) {
 137                         ancient = 1;
 138                         model_name = "WD8003-old";
 139                         word16 = 0;
 140                 } else {
 141                         int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
 142                         outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
 143                         if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
 144                                 && (tmp & 0x01) == 0x01 ) {                             /* In a 16 slot. */
 145                                 int asic_reg5 = inb(ioaddr+WD_CMDREG5);
 146                                 /* Magic to set ASIC to word-wide mode. */
 147                                 outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
 148                                 outb(tmp, ioaddr+1);
 149                                 model_name = "WD8013";
 150                                 word16 = 1;             /* We have a 16bit board here! */
 151                         } else {
 152                                 model_name = "WD8003";
 153                                 word16 = 0;
 154                         }
 155                         outb(tmp, ioaddr+1);                    /* Restore original reg1 value. */
 156                 }
 157 #ifndef final_version
 158                 if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
 159                         printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
 160                                    word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
 161 #endif
 162         }
 163         
 164 #if defined(WD_SHMEM) && WD_SHMEM > 0x80000
 165         /* Allow a compile-time override.        */
 166         dev->mem_start = WD_SHMEM;
 167 #else
 168         if (dev->mem_start == 0) {
 169                 /* Sanity and old 8003 check */
 170                 int reg0 = inb(ioaddr);
 171                 if (reg0 == 0xff || reg0 == 0) {
 172                         /* Future plan: this could check a few likely locations first. */
 173                         dev->mem_start = 0xd0000;
 174                         printk(" assigning address %#lx", dev->mem_start);
 175                 } else {
 176                         int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
 177                         /* Some boards don't have the register 5 -- it returns 0xff. */
 178                         if (high_addr_bits == 0x1f || word16 == 0)
 179                                 high_addr_bits = 0x01;
 180                         dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
 181                 }
 182         }
 183 #endif
 184         
 185         /* The 8390 isn't at the base address -- the ASIC regs are there! */
 186         dev->base_addr = ioaddr+WD_NIC_OFFSET;
 187         
 188         if (dev->irq < 2) {
 189                 int irqmap[] = {9,3,5,7,10,11,15,4};
 190                 int reg1 = inb(ioaddr+1);
 191                 int reg4 = inb(ioaddr+4);
 192                 if (ancient || reg1 == 0xff) {  /* Ack!! No way to read the IRQ! */
 193                         short nic_addr = ioaddr+WD_NIC_OFFSET;
 194                         
 195                         /* We have an old-style ethercard that doesn't report its IRQ
 196                            line.  Do autoirq to find the IRQ line. Note that this IS NOT
 197                            a reliable way to trigger an interrupt. */
 198                         outb_p(E8390_NODMA + E8390_STOP, nic_addr);
 199                         outb(0x00, nic_addr+EN0_IMR);   /* Disable all intrs. */
 200                         autoirq_setup(0);
 201                         outb_p(0xff, nic_addr + EN0_IMR);       /* Enable all interrupts. */
 202                         outb_p(0x00, nic_addr + EN0_RCNTLO);
 203                         outb_p(0x00, nic_addr + EN0_RCNTHI);
 204                         outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
 205                         dev->irq = autoirq_report(2);
 206                         outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
 207                         
 208                         if (ei_debug > 2)
 209                                 printk(" autoirq is %d", dev->irq);
 210                         if (dev->irq < 2)
 211                                 dev->irq = word16 ? 10 : 5;
 212                 } else
 213                         dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
 214         } else if (dev->irq == 2)               /* Fixup bogosity: IRQ2 is really IRQ9 */
 215                 dev->irq = 9;
 216         
 217         /* Snarf the interrupt now.  There's no point in waiting since we cannot
 218            share and the board will usually be enabled. */
 219         if (irqaction (dev->irq, &ei_sigaction)) {
 220                 printk (" unable to get IRQ %d.\n", dev->irq);
 221                 return 0;
 222         }
 223         
 224         /* OK, were are certain this is going to work.  Setup the device. */
 225         snarf_region(ioaddr, 32);
 226         ethdev_init(dev);
 227         
 228         ei_status.name = model_name;
 229         ei_status.word16 = word16;
 230         ei_status.tx_start_page = WD_START_PG;
 231         ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 232         ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
 233         
 234         /* Don't map in the shared memory until the board is actually opened. */
 235         dev->rmem_start = dev->mem_start + TX_PAGES*256;
 236         dev->mem_end = dev->rmem_end
 237                 = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
 238         
 239         printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 240                    model_name, dev->irq, dev->mem_start, dev->mem_end-1);
 241         if (ei_debug > 0)
 242                 printk(version);
 243         
 244         ei_status.reset_8390 = &wd_reset_8390;
 245         ei_status.block_input = &wd_block_input;
 246         ei_status.block_output = &wd_block_output;
 247         dev->open = &wd_open;
 248         dev->stop = &wd_close_card;
 249         NS8390_init(dev, 0);
 250         
 251         return dev->base_addr;
 252 }
 253 
 254 static int
 255 wd_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257   int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 258 
 259   /* Map in the shared memory. Always set register 0 last to remain
 260          compatible with very old boards. */
 261   ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
 262   ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
 263 
 264   if (ei_status.word16)
 265           outb(ei_status.reg5, ioaddr+WD_CMDREG5);
 266   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 267 
 268   return ei_open(dev);
 269 }
 270 
 271 static void
 272 wd_reset_8390(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274         int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 275 
 276         outb(WD_RESET, wd_cmd_port);
 277         if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies);
 278         ei_status.txing = 0;
 279 
 280         /* Set up the ASIC registers, just in case something changed them. */
 281         outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
 282         if (ei_status.word16)
 283                 outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
 284 
 285         if (ei_debug > 1) printk("reset done\n");
 286         return;
 287 }
 288 
 289 /* Block input and output are easy on shared memory ethercards, and trivial
 290    on the Western digital card where there is no choice of how to do it.
 291    The only complications are that the ring buffer wraps, and need to map
 292    switch between 8- and 16-bit modes. */
 293 
 294 static int
 295 wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 296 {
 297         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 298         long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
 299 
 300         /* We'll always get a 4 byte header read followed by a packet read, so
 301            we enable 16 bit mode before the header, and disable after the body. */
 302         if (count == 4) {
 303                 if (ei_status.word16)
 304                         outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 305                 ((int*)buf)[0] = ((int*)xfer_start)[0];
 306                 return 0;
 307         }
 308 
 309         if (xfer_start + count > dev->rmem_end) {
 310                 /* We must wrap the input move. */
 311                 int semi_count = dev->rmem_end - xfer_start;
 312                 memcpy(buf, (char *)xfer_start, semi_count);
 313                 count -= semi_count;
 314                 memcpy(buf + semi_count, (char *)dev->rmem_start, count);
 315         } else
 316                 memcpy(buf, (char *)xfer_start, count);
 317 
 318         /* Turn off 16 bit access so that reboot works.  ISA brain-damage */
 319         if (ei_status.word16)
 320                 outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 321 
 322         return 0;
 323 }
 324 
 325 static void
 326 wd_block_output(struct device *dev, int count, const unsigned char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 327                                 int start_page)
 328 {
 329         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 330         long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8);
 331 
 332 
 333         if (ei_status.word16) {
 334                 /* Turn on and off 16 bit access so that reboot works. */
 335                 outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 336                 memcpy((char *)shmem, buf, count);
 337                 outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 338         } else
 339                 memcpy((char *)shmem, buf, count);
 340 }
 341 
 342 
 343 static int
 344 wd_close_card(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 347 
 348         if (ei_debug > 1)
 349                 printk("%s: Shutting down ethercard.\n", dev->name);
 350         NS8390_init(dev, 0);
 351 
 352         /* Change from 16-bit to 8-bit shared memory so reboot works. */
 353         outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
 354 
 355         /* And disable the shared memory. */
 356         outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 357 
 358         return 0;
 359 }
 360 
 361 
 362 /*
 363  * Local variables:
 364  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c wd.c"
 365  *  version-control: t
 366  *  tab-width: 4
 367  *  kept-new-versions: 5
 368  * End:
 369  */

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