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

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