root/drivers/net/wd.c

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

DEFINITIONS

This source file includes following definitions.
  1. wd_probe
  2. wd_probe1
  3. wd_open
  4. wd_reset_8390
  5. wd_get_8390_hdr
  6. wd_block_input
  7. wd_block_output
  8. wd_close_card
  9. init_module
  10. cleanup_module

   1 /* wd.c: A WD80x3 ethernet driver for linux. */
   2 /*
   3         Written 1993-94 by Donald Becker.
   4 
   5         Copyright 1993 United States Government as represented by the
   6         Director, National Security Agency.
   7 
   8         This software may be used and distributed according to the terms
   9         of the GNU Public License, incorporated herein by reference.
  10 
  11         The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
  12         Center of Excellence in Space Data and Information Sciences
  13            Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  14 
  15         This is a driver for WD8003 and WD8013 "compatible" ethercards.
  16 
  17         Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
  18 
  19         Changelog:
  20 
  21         Paul Gortmaker  : multiple card support for module users
  22 
  23 */
  24 
  25 static const char *version =
  26         "wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
  27 
  28 #include <linux/module.h>
  29 
  30 #include <linux/kernel.h>
  31 #include <linux/sched.h>
  32 #include <linux/errno.h>
  33 #include <linux/string.h>
  34 #include <asm/io.h>
  35 #include <asm/system.h>
  36 
  37 #include <linux/netdevice.h>
  38 #include <linux/etherdevice.h>
  39 #include "8390.h"
  40 
  41 /* A zero-terminated list of I/O addresses to be probed. */
  42 static unsigned int wd_portlist[] =
  43 {0x300, 0x280, 0x380, 0x240, 0};
  44 
  45 int wd_probe(struct device *dev);
  46 int wd_probe1(struct device *dev, int ioaddr);
  47 
  48 static int wd_open(struct device *dev);
  49 static void wd_reset_8390(struct device *dev);
  50 static void wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
  51                                                 int ring_page);
  52 static void wd_block_input(struct device *dev, int count,
  53                                                   struct sk_buff *skb, int ring_offset);
  54 static void wd_block_output(struct device *dev, int count,
  55                                                         const unsigned char *buf, const start_page);
  56 static int wd_close_card(struct device *dev);
  57 
  58 
  59 #define WD_START_PG             0x00    /* First page of TX buffer */
  60 #define WD03_STOP_PG    0x20    /* Last page +1 of RX ring */
  61 #define WD13_STOP_PG    0x40    /* Last page +1 of RX ring */
  62 
  63 #define WD_CMDREG               0               /* Offset to ASIC command register. */
  64 #define  WD_RESET               0x80    /* Board reset, in WD_CMDREG. */
  65 #define  WD_MEMENB              0x40    /* Enable the shared memory. */
  66 #define WD_CMDREG5              5               /* Offset to 16-bit-only ASIC register 5. */
  67 #define  ISA16                  0x80    /* Enable 16 bit access from the ISA bus. */
  68 #define  NIC16                  0x40    /* Enable 16 bit access from the 8390. */
  69 #define WD_NIC_OFFSET   16              /* Offset to the 8390 from the base_addr. */
  70 #define WD_IO_EXTENT    32
  71 
  72 
  73 /*      Probe for the WD8003 and WD8013.  These cards have the station
  74         address PROM at I/O ports <base>+8 to <base>+13, with a checksum
  75         following. A Soundblaster can have the same checksum as an WDethercard,
  76         so we have an extra exclusionary check for it.
  77 
  78         The wd_probe1() routine initializes the card and fills the
  79         station address field. */
  80 
  81 #ifdef HAVE_DEVLIST
  82 struct netdev_entry wd_drv =
  83 {"wd", wd_probe1, WD_IO_EXTENT, wd_portlist};
  84 #else
  85 
  86 int wd_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         int i;
  89         int base_addr = dev ? dev->base_addr : 0;
  90 
  91         if (base_addr > 0x1ff)          /* Check a single specified location. */
  92                 return wd_probe1(dev, base_addr);
  93         else if (base_addr != 0)        /* Don't probe at all. */
  94                 return ENXIO;
  95 
  96         for (i = 0; wd_portlist[i]; i++) {
  97                 int ioaddr = wd_portlist[i];
  98                 if (check_region(ioaddr, WD_IO_EXTENT))
  99                         continue;
 100                 if (wd_probe1(dev, ioaddr) == 0)
 101                         return 0;
 102         }
 103 
 104         return ENODEV;
 105 }
 106 #endif
 107 
 108 int wd_probe1(struct device *dev, int ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110         int i;
 111         int checksum = 0;
 112         int ancient = 0;                        /* An old card without config registers. */
 113         int word16 = 0;                         /* 0 = 8 bit, 1 = 16 bit */
 114         const char *model_name;
 115         static unsigned version_printed = 0;
 116 
 117         for (i = 0; i < 8; i++)
 118                 checksum += inb(ioaddr + 8 + i);
 119         if (inb(ioaddr + 8) == 0xff     /* Extra check to avoid soundcard. */
 120                 || inb(ioaddr + 9) == 0xff
 121                 || (checksum & 0xff) != 0xFF)
 122                 return ENODEV;
 123 
 124         if (dev == NULL)
 125                 dev = init_etherdev(0, sizeof(struct ei_device));
 126 
 127         if (ei_debug  &&  version_printed++ == 0)
 128                 printk(version);
 129 
 130         printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
 131         for (i = 0; i < 6; i++)
 132                 printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
 133 
 134         /* The following PureData probe code was contributed by
 135            Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
 136            configuration differently from others so we have to check for them.
 137            This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
 138            */
 139         if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
 140                 unsigned char reg5 = inb(ioaddr+5);
 141 
 142                 switch (inb(ioaddr+2)) {
 143                 case 0x03: word16 = 0; model_name = "PDI8023-8";        break;
 144                 case 0x05: word16 = 0; model_name = "PDUC8023"; break;
 145                 case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
 146                         /* Either 0x01 (dumb) or they've released a new version. */
 147                 default:         word16 = 0; model_name = "PDI8023";    break;
 148                 }
 149                 dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
 150                 dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
 151         } else {                                                                /* End of PureData probe */
 152                 /* This method of checking for a 16-bit board is borrowed from the
 153                    we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
 154                    I'm comparing the two method in alpha test to make certain they
 155                    return the same result. */
 156                 /* Check for the old 8 bit board - it has register 0/8 aliasing.
 157                    Do NOT check i>=6 here -- it hangs the old 8003 boards! */
 158                 for (i = 0; i < 6; i++)
 159                         if (inb(ioaddr+i) != inb(ioaddr+8+i))
 160                                 break;
 161                 if (i >= 6) {
 162                         ancient = 1;
 163                         model_name = "WD8003-old";
 164                         word16 = 0;
 165                 } else {
 166                         int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
 167                         outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
 168                         if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
 169                                 && (tmp & 0x01) == 0x01 ) {                             /* In a 16 slot. */
 170                                 int asic_reg5 = inb(ioaddr+WD_CMDREG5);
 171                                 /* Magic to set ASIC to word-wide mode. */
 172                                 outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
 173                                 outb(tmp, ioaddr+1);
 174                                 model_name = "WD8013";
 175                                 word16 = 1;             /* We have a 16bit board here! */
 176                         } else {
 177                                 model_name = "WD8003";
 178                                 word16 = 0;
 179                         }
 180                         outb(tmp, ioaddr+1);                    /* Restore original reg1 value. */
 181                 }
 182 #ifndef final_version
 183                 if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
 184                         printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
 185                                    word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
 186 #endif
 187         }
 188 
 189 #if defined(WD_SHMEM) && WD_SHMEM > 0x80000
 190         /* Allow a compile-time override.        */
 191         dev->mem_start = WD_SHMEM;
 192 #else
 193         if (dev->mem_start == 0) {
 194                 /* Sanity and old 8003 check */
 195                 int reg0 = inb(ioaddr);
 196                 if (reg0 == 0xff || reg0 == 0) {
 197                         /* Future plan: this could check a few likely locations first. */
 198                         dev->mem_start = 0xd0000;
 199                         printk(" assigning address %#lx", dev->mem_start);
 200                 } else {
 201                         int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
 202                         /* Some boards don't have the register 5 -- it returns 0xff. */
 203                         if (high_addr_bits == 0x1f || word16 == 0)
 204                                 high_addr_bits = 0x01;
 205                         dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
 206                 }
 207         }
 208 #endif
 209 
 210         /* The 8390 isn't at the base address -- the ASIC regs are there! */
 211         dev->base_addr = ioaddr+WD_NIC_OFFSET;
 212 
 213         if (dev->irq < 2) {
 214                 int irqmap[] = {9,3,5,7,10,11,15,4};
 215                 int reg1 = inb(ioaddr+1);
 216                 int reg4 = inb(ioaddr+4);
 217                 if (ancient || reg1 == 0xff) {  /* Ack!! No way to read the IRQ! */
 218                         short nic_addr = ioaddr+WD_NIC_OFFSET;
 219 
 220                         /* We have an old-style ethercard that doesn't report its IRQ
 221                            line.  Do autoirq to find the IRQ line. Note that this IS NOT
 222                            a reliable way to trigger an interrupt. */
 223                         outb_p(E8390_NODMA + E8390_STOP, nic_addr);
 224                         outb(0x00, nic_addr+EN0_IMR);   /* Disable all intrs. */
 225                         autoirq_setup(0);
 226                         outb_p(0xff, nic_addr + EN0_IMR);       /* Enable all interrupts. */
 227                         outb_p(0x00, nic_addr + EN0_RCNTLO);
 228                         outb_p(0x00, nic_addr + EN0_RCNTHI);
 229                         outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
 230                         dev->irq = autoirq_report(2);
 231                         outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
 232 
 233                         if (ei_debug > 2)
 234                                 printk(" autoirq is %d", dev->irq);
 235                         if (dev->irq < 2)
 236                                 dev->irq = word16 ? 10 : 5;
 237                 } else
 238                         dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
 239         } else if (dev->irq == 2)               /* Fixup bogosity: IRQ2 is really IRQ9 */
 240                 dev->irq = 9;
 241 
 242         /* Snarf the interrupt now.  There's no point in waiting since we cannot
 243            share and the board will usually be enabled. */
 244         if (request_irq(dev->irq, ei_interrupt, 0, "wd")) {
 245                 printk (" unable to get IRQ %d.\n", dev->irq);
 246                 return EAGAIN;
 247         }
 248 
 249         /* OK, were are certain this is going to work.  Setup the device. */
 250         request_region(ioaddr, WD_IO_EXTENT,"wd");
 251         ethdev_init(dev);
 252 
 253         ei_status.name = model_name;
 254         ei_status.word16 = word16;
 255         ei_status.tx_start_page = WD_START_PG;
 256         ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 257         ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
 258 
 259         /* Don't map in the shared memory until the board is actually opened. */
 260         dev->rmem_start = dev->mem_start + TX_PAGES*256;
 261         dev->mem_end = dev->rmem_end
 262                 = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
 263 
 264         printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 265                    model_name, dev->irq, dev->mem_start, dev->mem_end-1);
 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         ei_status.get_8390_hdr = &wd_get_8390_hdr;
 271         dev->open = &wd_open;
 272         dev->stop = &wd_close_card;
 273         NS8390_init(dev, 0);
 274 
 275 #if 1
 276         /* Enable interrupt generation on softconfig cards -- M.U */
 277         /* .. but possibly potentially unsafe - Donald */
 278         if (inb(ioaddr+14) & 0x20)
 279                 outb(inb(ioaddr+4)|0x80, ioaddr+4);
 280 #endif
 281 
 282         return 0;
 283 }
 284 
 285 static int
 286 wd_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 287 {
 288   int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 289   int rc;
 290 
 291   /* Map in the shared memory. Always set register 0 last to remain
 292          compatible with very old boards. */
 293   ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
 294   ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
 295 
 296   if (ei_status.word16)
 297           outb(ei_status.reg5, ioaddr+WD_CMDREG5);
 298   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 299 
 300   rc = ei_open(dev);
 301   if (rc != 0) return rc;
 302   MOD_INC_USE_COUNT;
 303   return 0;
 304 }
 305 
 306 static void
 307 wd_reset_8390(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 310 
 311         outb(WD_RESET, wd_cmd_port);
 312         if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies);
 313         ei_status.txing = 0;
 314 
 315         /* Set up the ASIC registers, just in case something changed them. */
 316         outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
 317         if (ei_status.word16)
 318                 outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
 319 
 320         if (ei_debug > 1) printk("reset done\n");
 321         return;
 322 }
 323 
 324 /* Grab the 8390 specific header. Similar to the block_input routine, but
 325    we don't need to be concerned with ring wrap as the header will be at
 326    the start of a page, so we optimize accordingly. */
 327 
 328 static void
 329 wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331 
 332         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 333         unsigned long hdr_start = dev->mem_start + ((ring_page - WD_START_PG)<<8);
 334 
 335         /* We'll always get a 4 byte header read followed by a packet read, so
 336            we enable 16 bit mode before the header, and disable after the body. */
 337         if (ei_status.word16)
 338                 outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 339 
 340         memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 341 }
 342 
 343 /* Block input and output are easy on shared memory ethercards, and trivial
 344    on the Western digital card where there is no choice of how to do it.
 345    The only complications are that the ring buffer wraps, and need to map
 346    switch between 8- and 16-bit modes. */
 347 
 348 static void
 349 wd_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 350 {
 351         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 352         unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
 353 
 354         if (xfer_start + count > dev->rmem_end) {
 355                 /* We must wrap the input move. */
 356                 int semi_count = dev->rmem_end - xfer_start;
 357                 memcpy_fromio(skb->data, xfer_start, semi_count);
 358                 count -= semi_count;
 359                 memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
 360         } else {
 361                 /* Packet is in one chunk -- we can copy + cksum. */
 362                 eth_io_copy_and_sum(skb, xfer_start, count, 0);
 363         }
 364 
 365         /* Turn off 16 bit access so that reboot works.  ISA brain-damage */
 366         if (ei_status.word16)
 367                 outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 368 }
 369 
 370 static void
 371 wd_block_output(struct device *dev, int count, const unsigned char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 372                                 int start_page)
 373 {
 374         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 375         long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8);
 376 
 377 
 378         if (ei_status.word16) {
 379                 /* Turn on and off 16 bit access so that reboot works. */
 380                 outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 381                 memcpy_toio(shmem, buf, count);
 382                 outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 383         } else
 384                 memcpy_toio(shmem, buf, count);
 385 }
 386 
 387 
 388 static int
 389 wd_close_card(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391         int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 392 
 393         if (ei_debug > 1)
 394                 printk("%s: Shutting down ethercard.\n", dev->name);
 395         NS8390_init(dev, 0);
 396         dev->start = 0;
 397 
 398         /* Change from 16-bit to 8-bit shared memory so reboot works. */
 399         outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
 400 
 401         /* And disable the shared memory. */
 402         outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 403 
 404         MOD_DEC_USE_COUNT;
 405 
 406         return 0;
 407 }
 408 
 409 
 410 #ifdef MODULE
 411 #define MAX_WD_MODS     4       /* Max number of wd modules allowed */
 412 #define NAMELEN         9       /* # of chars for storing dev->name */
 413 static char namelist[NAMELEN * MAX_WD_MODS] = { 0, };
 414 static struct device dev_wd80x3[MAX_WD_MODS] = {
 415         {
 416                 NULL,           /* assign a chunk of namelist[] below */
 417                 0, 0, 0, 0,
 418                 0, 0,
 419                 0, 0, 0, NULL, NULL
 420         },
 421 };
 422 
 423 static int io[MAX_WD_MODS] = { 0, };
 424 static int irq[MAX_WD_MODS]  = { 0, };
 425 static int mem[MAX_WD_MODS] = { 0, };
 426 
 427 /* This is set up so that only a single autoprobe takes place per call.
 428 ISA device autoprobes on a running machine are not recommended. */
 429 int
 430 init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 431 {
 432         int this_dev;
 433 
 434         for (this_dev = 0; this_dev < MAX_WD_MODS; this_dev++) {
 435                 dev_wd80x3[this_dev].name = namelist+(NAMELEN*this_dev);
 436                 dev_wd80x3[this_dev].irq = irq[this_dev];
 437                 dev_wd80x3[this_dev].base_addr = io[this_dev];
 438                 dev_wd80x3[this_dev].mem_start = mem[this_dev];
 439                 dev_wd80x3[this_dev].init = wd_probe;
 440                 if (io[this_dev] == 0)  {
 441                         if (this_dev != 0) break; /* only autoprobe 1st one */
 442                         printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
 443                 }
 444                 if (register_netdev(&dev_wd80x3[this_dev]) != 0) {
 445                         printk(KERN_WARNING "modules: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
 446                         return -EIO;
 447                 }
 448         }
 449 
 450         return 0;
 451 }
 452 
 453 void
 454 cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 455 {
 456         int this_dev;
 457 
 458         for (this_dev = 0; this_dev < MAX_WD_MODS; this_dev++) {
 459                 if (dev_wd80x3[this_dev].priv != NULL) {
 460                         int ioaddr = dev_wd80x3[this_dev].base_addr - WD_NIC_OFFSET;
 461                         unregister_netdev(&dev_wd80x3[this_dev]);
 462                         free_irq(dev_wd80x3[this_dev].irq);
 463                         release_region(ioaddr, WD_IO_EXTENT);
 464                 }
 465         }
 466 }
 467 #endif /* MODULE */
 468 
 469 
 470 /*
 471  * Local variables:
 472  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c wd.c"
 473  *  version-control: t
 474  *  tab-width: 4
 475  *  kept-new-versions: 5
 476  * End:
 477  */

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