linux/drivers/net/ethernet/8390/wd.c
<<
>>
Prefs
   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 General Public License, incorporated herein by reference.
  10
  11        The author may be reached as becker@scyld.com, or C/O
  12        Scyld Computing Corporation
  13        410 Severn Ave., Suite 210
  14        Annapolis MD 21403
  15
  16        This is a driver for WD8003 and WD8013 "compatible" ethercards.
  17
  18        Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
  19
  20        Changelog:
  21
  22        Paul Gortmaker  : multiple card support for module users, support
  23                          for non-standard memory sizes.
  24
  25
  26*/
  27
  28static const char version[] =
  29        "wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
  30
  31#include <linux/module.h>
  32#include <linux/kernel.h>
  33#include <linux/errno.h>
  34#include <linux/string.h>
  35#include <linux/init.h>
  36#include <linux/interrupt.h>
  37#include <linux/delay.h>
  38#include <linux/netdevice.h>
  39#include <linux/etherdevice.h>
  40
  41#include <asm/io.h>
  42
  43#include "8390.h"
  44
  45#define DRV_NAME "wd"
  46
  47/* A zero-terminated list of I/O addresses to be probed. */
  48static unsigned int wd_portlist[] __initdata =
  49{0x300, 0x280, 0x380, 0x240, 0};
  50
  51static int wd_probe1(struct net_device *dev, int ioaddr);
  52
  53static int wd_open(struct net_device *dev);
  54static void wd_reset_8390(struct net_device *dev);
  55static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
  56                                                int ring_page);
  57static void wd_block_input(struct net_device *dev, int count,
  58                                                  struct sk_buff *skb, int ring_offset);
  59static void wd_block_output(struct net_device *dev, int count,
  60                                                        const unsigned char *buf, int start_page);
  61static int wd_close(struct net_device *dev);
  62
  63static u32 wd_msg_enable;
  64
  65#define WD_START_PG             0x00    /* First page of TX buffer */
  66#define WD03_STOP_PG    0x20    /* Last page +1 of RX ring */
  67#define WD13_STOP_PG    0x40    /* Last page +1 of RX ring */
  68
  69#define WD_CMDREG               0               /* Offset to ASIC command register. */
  70#define  WD_RESET               0x80    /* Board reset, in WD_CMDREG. */
  71#define  WD_MEMENB              0x40    /* Enable the shared memory. */
  72#define WD_CMDREG5              5               /* Offset to 16-bit-only ASIC register 5. */
  73#define  ISA16                  0x80    /* Enable 16 bit access from the ISA bus. */
  74#define  NIC16                  0x40    /* Enable 16 bit access from the 8390. */
  75#define WD_NIC_OFFSET   16              /* Offset to the 8390 from the base_addr. */
  76#define WD_IO_EXTENT    32
  77
  78
  79/*      Probe for the WD8003 and WD8013.  These cards have the station
  80        address PROM at I/O ports <base>+8 to <base>+13, with a checksum
  81        following. A Soundblaster can have the same checksum as an WDethercard,
  82        so we have an extra exclusionary check for it.
  83
  84        The wd_probe1() routine initializes the card and fills the
  85        station address field. */
  86
  87static int __init do_wd_probe(struct net_device *dev)
  88{
  89        int i;
  90        struct resource *r;
  91        int base_addr = dev->base_addr;
  92        int irq = dev->irq;
  93        int mem_start = dev->mem_start;
  94        int mem_end = dev->mem_end;
  95
  96        if (base_addr > 0x1ff) {        /* Check a user specified location. */
  97                r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
  98                if ( r == NULL)
  99                        return -EBUSY;
 100                i = wd_probe1(dev, base_addr);
 101                if (i != 0)
 102                        release_region(base_addr, WD_IO_EXTENT);
 103                else
 104                        r->name = dev->name;
 105                return i;
 106        }
 107        else if (base_addr != 0)        /* Don't probe at all. */
 108                return -ENXIO;
 109
 110        for (i = 0; wd_portlist[i]; i++) {
 111                int ioaddr = wd_portlist[i];
 112                r = request_region(ioaddr, WD_IO_EXTENT, "wd-probe");
 113                if (r == NULL)
 114                        continue;
 115                if (wd_probe1(dev, ioaddr) == 0) {
 116                        r->name = dev->name;
 117                        return 0;
 118                }
 119                release_region(ioaddr, WD_IO_EXTENT);
 120                dev->irq = irq;
 121                dev->mem_start = mem_start;
 122                dev->mem_end = mem_end;
 123        }
 124
 125        return -ENODEV;
 126}
 127
 128#ifndef MODULE
 129struct net_device * __init wd_probe(int unit)
 130{
 131        struct net_device *dev = alloc_ei_netdev();
 132        int err;
 133
 134        if (!dev)
 135                return ERR_PTR(-ENOMEM);
 136
 137        sprintf(dev->name, "eth%d", unit);
 138        netdev_boot_setup_check(dev);
 139
 140        err = do_wd_probe(dev);
 141        if (err)
 142                goto out;
 143        return dev;
 144out:
 145        free_netdev(dev);
 146        return ERR_PTR(err);
 147}
 148#endif
 149
 150static const struct net_device_ops wd_netdev_ops = {
 151        .ndo_open               = wd_open,
 152        .ndo_stop               = wd_close,
 153        .ndo_start_xmit         = ei_start_xmit,
 154        .ndo_tx_timeout         = ei_tx_timeout,
 155        .ndo_get_stats          = ei_get_stats,
 156        .ndo_set_rx_mode        = ei_set_multicast_list,
 157        .ndo_validate_addr      = eth_validate_addr,
 158        .ndo_set_mac_address    = eth_mac_addr,
 159#ifdef CONFIG_NET_POLL_CONTROLLER
 160        .ndo_poll_controller    = ei_poll,
 161#endif
 162};
 163
 164static int __init wd_probe1(struct net_device *dev, int ioaddr)
 165{
 166        int i;
 167        int err;
 168        int checksum = 0;
 169        int ancient = 0;                        /* An old card without config registers. */
 170        int word16 = 0;                         /* 0 = 8 bit, 1 = 16 bit */
 171        const char *model_name;
 172        static unsigned version_printed;
 173        struct ei_device *ei_local = netdev_priv(dev);
 174
 175        for (i = 0; i < 8; i++)
 176                checksum += inb(ioaddr + 8 + i);
 177        if (inb(ioaddr + 8) == 0xff     /* Extra check to avoid soundcard. */
 178                || inb(ioaddr + 9) == 0xff
 179                || (checksum & 0xff) != 0xFF)
 180                return -ENODEV;
 181
 182        /* Check for semi-valid mem_start/end values if supplied. */
 183        if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
 184                netdev_warn(dev,
 185                            "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
 186                dev->mem_start = 0;
 187                dev->mem_end = 0;
 188        }
 189
 190        if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
 191                netdev_info(dev, version);
 192
 193        for (i = 0; i < 6; i++)
 194                dev->dev_addr[i] = inb(ioaddr + 8 + i);
 195
 196        netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr);
 197
 198        /* The following PureData probe code was contributed by
 199           Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
 200           configuration differently from others so we have to check for them.
 201           This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
 202           */
 203        if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
 204                unsigned char reg5 = inb(ioaddr+5);
 205
 206                switch (inb(ioaddr+2)) {
 207                case 0x03: word16 = 0; model_name = "PDI8023-8";        break;
 208                case 0x05: word16 = 0; model_name = "PDUC8023"; break;
 209                case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
 210                        /* Either 0x01 (dumb) or they've released a new version. */
 211                default:         word16 = 0; model_name = "PDI8023";    break;
 212                }
 213                dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
 214                dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
 215        } else {                                                                /* End of PureData probe */
 216                /* This method of checking for a 16-bit board is borrowed from the
 217                   we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
 218                   I'm comparing the two method in alpha test to make certain they
 219                   return the same result. */
 220                /* Check for the old 8 bit board - it has register 0/8 aliasing.
 221                   Do NOT check i>=6 here -- it hangs the old 8003 boards! */
 222                for (i = 0; i < 6; i++)
 223                        if (inb(ioaddr+i) != inb(ioaddr+8+i))
 224                                break;
 225                if (i >= 6) {
 226                        ancient = 1;
 227                        model_name = "WD8003-old";
 228                        word16 = 0;
 229                } else {
 230                        int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
 231                        outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
 232                        if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
 233                                && (tmp & 0x01) == 0x01 ) {                             /* In a 16 slot. */
 234                                int asic_reg5 = inb(ioaddr+WD_CMDREG5);
 235                                /* Magic to set ASIC to word-wide mode. */
 236                                outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
 237                                outb(tmp, ioaddr+1);
 238                                model_name = "WD8013";
 239                                word16 = 1;             /* We have a 16bit board here! */
 240                        } else {
 241                                model_name = "WD8003";
 242                                word16 = 0;
 243                        }
 244                        outb(tmp, ioaddr+1);                    /* Restore original reg1 value. */
 245                }
 246#ifndef final_version
 247                if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
 248                        pr_cont("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
 249                                word16 ? 16 : 8,
 250                                (inb(ioaddr+1) & 0x01) ? 16 : 8);
 251#endif
 252        }
 253
 254#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
 255        /* Allow a compile-time override.        */
 256        dev->mem_start = WD_SHMEM;
 257#else
 258        if (dev->mem_start == 0) {
 259                /* Sanity and old 8003 check */
 260                int reg0 = inb(ioaddr);
 261                if (reg0 == 0xff || reg0 == 0) {
 262                        /* Future plan: this could check a few likely locations first. */
 263                        dev->mem_start = 0xd0000;
 264                        pr_cont(" assigning address %#lx", dev->mem_start);
 265                } else {
 266                        int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
 267                        /* Some boards don't have the register 5 -- it returns 0xff. */
 268                        if (high_addr_bits == 0x1f || word16 == 0)
 269                                high_addr_bits = 0x01;
 270                        dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
 271                }
 272        }
 273#endif
 274
 275        /* The 8390 isn't at the base address -- the ASIC regs are there! */
 276        dev->base_addr = ioaddr+WD_NIC_OFFSET;
 277
 278        if (dev->irq < 2) {
 279                static const int irqmap[] = {9, 3, 5, 7, 10, 11, 15, 4};
 280                int reg1 = inb(ioaddr+1);
 281                int reg4 = inb(ioaddr+4);
 282                if (ancient || reg1 == 0xff) {  /* Ack!! No way to read the IRQ! */
 283                        short nic_addr = ioaddr+WD_NIC_OFFSET;
 284                        unsigned long irq_mask;
 285
 286                        /* We have an old-style ethercard that doesn't report its IRQ
 287                           line.  Do autoirq to find the IRQ line. Note that this IS NOT
 288                           a reliable way to trigger an interrupt. */
 289                        outb_p(E8390_NODMA + E8390_STOP, nic_addr);
 290                        outb(0x00, nic_addr+EN0_IMR);   /* Disable all intrs. */
 291
 292                        irq_mask = probe_irq_on();
 293                        outb_p(0xff, nic_addr + EN0_IMR);       /* Enable all interrupts. */
 294                        outb_p(0x00, nic_addr + EN0_RCNTLO);
 295                        outb_p(0x00, nic_addr + EN0_RCNTHI);
 296                        outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
 297                        mdelay(20);
 298                        dev->irq = probe_irq_off(irq_mask);
 299
 300                        outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
 301
 302                        if (wd_msg_enable & NETIF_MSG_PROBE)
 303                                pr_cont(" autoirq is %d", dev->irq);
 304                        if (dev->irq < 2)
 305                                dev->irq = word16 ? 10 : 5;
 306                } else
 307                        dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
 308        } else if (dev->irq == 2)               /* Fixup bogosity: IRQ2 is really IRQ9 */
 309                dev->irq = 9;
 310
 311        /* Snarf the interrupt now.  There's no point in waiting since we cannot
 312           share and the board will usually be enabled. */
 313        i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 314        if (i) {
 315                pr_cont(" unable to get IRQ %d.\n", dev->irq);
 316                return i;
 317        }
 318
 319        /* OK, were are certain this is going to work.  Setup the device. */
 320        ei_status.name = model_name;
 321        ei_status.word16 = word16;
 322        ei_status.tx_start_page = WD_START_PG;
 323        ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 324
 325        /* Don't map in the shared memory until the board is actually opened. */
 326
 327        /* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
 328        if (dev->mem_end != 0) {
 329                ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
 330                ei_status.priv = dev->mem_end - dev->mem_start;
 331        } else {
 332                ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
 333                dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
 334                ei_status.priv = (ei_status.stop_page - WD_START_PG)*256;
 335        }
 336
 337        ei_status.mem = ioremap(dev->mem_start, ei_status.priv);
 338        if (!ei_status.mem) {
 339                free_irq(dev->irq, dev);
 340                return -ENOMEM;
 341        }
 342
 343        pr_cont(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 344                model_name, dev->irq, dev->mem_start, dev->mem_end-1);
 345
 346        ei_status.reset_8390 = wd_reset_8390;
 347        ei_status.block_input = wd_block_input;
 348        ei_status.block_output = wd_block_output;
 349        ei_status.get_8390_hdr = wd_get_8390_hdr;
 350
 351        dev->netdev_ops = &wd_netdev_ops;
 352        NS8390_init(dev, 0);
 353        ei_local->msg_enable = wd_msg_enable;
 354
 355#if 1
 356        /* Enable interrupt generation on softconfig cards -- M.U */
 357        /* .. but possibly potentially unsafe - Donald */
 358        if (inb(ioaddr+14) & 0x20)
 359                outb(inb(ioaddr+4)|0x80, ioaddr+4);
 360#endif
 361
 362        err = register_netdev(dev);
 363        if (err) {
 364                free_irq(dev->irq, dev);
 365                iounmap(ei_status.mem);
 366        }
 367        return err;
 368}
 369
 370static int
 371wd_open(struct net_device *dev)
 372{
 373  int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 374
 375  /* Map in the shared memory. Always set register 0 last to remain
 376         compatible with very old boards. */
 377  ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
 378  ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
 379
 380  if (ei_status.word16)
 381          outb(ei_status.reg5, ioaddr+WD_CMDREG5);
 382  outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 383
 384  return ei_open(dev);
 385}
 386
 387static void
 388wd_reset_8390(struct net_device *dev)
 389{
 390        int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 391        struct ei_device *ei_local = netdev_priv(dev);
 392
 393        outb(WD_RESET, wd_cmd_port);
 394        netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=%lu...\n",
 395                  jiffies);
 396        ei_status.txing = 0;
 397
 398        /* Set up the ASIC registers, just in case something changed them. */
 399        outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
 400        if (ei_status.word16)
 401                outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
 402
 403        netif_dbg(ei_local, hw, dev, "reset done\n");
 404}
 405
 406/* Grab the 8390 specific header. Similar to the block_input routine, but
 407   we don't need to be concerned with ring wrap as the header will be at
 408   the start of a page, so we optimize accordingly. */
 409
 410static void
 411wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 412{
 413
 414        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 415        void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8);
 416
 417        /* We'll always get a 4 byte header read followed by a packet read, so
 418           we enable 16 bit mode before the header, and disable after the body. */
 419        if (ei_status.word16)
 420                outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 421
 422#ifdef __BIG_ENDIAN
 423        /* Officially this is what we are doing, but the readl() is faster */
 424        /* unfortunately it isn't endian aware of the struct               */
 425        memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 426        hdr->count = le16_to_cpu(hdr->count);
 427#else
 428        ((unsigned int*)hdr)[0] = readl(hdr_start);
 429#endif
 430}
 431
 432/* Block input and output are easy on shared memory ethercards, and trivial
 433   on the Western digital card where there is no choice of how to do it.
 434   The only complications are that the ring buffer wraps, and need to map
 435   switch between 8- and 16-bit modes. */
 436
 437static void
 438wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 439{
 440        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 441        unsigned long offset = ring_offset - (WD_START_PG<<8);
 442        void __iomem *xfer_start = ei_status.mem + offset;
 443
 444        if (offset + count > ei_status.priv) {
 445                /* We must wrap the input move. */
 446                int semi_count = ei_status.priv - offset;
 447                memcpy_fromio(skb->data, xfer_start, semi_count);
 448                count -= semi_count;
 449                memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 450        } else {
 451                /* Packet is in one chunk -- we can copy + cksum. */
 452                memcpy_fromio(skb->data, xfer_start, count);
 453        }
 454
 455        /* Turn off 16 bit access so that reboot works.  ISA brain-damage */
 456        if (ei_status.word16)
 457                outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 458}
 459
 460static void
 461wd_block_output(struct net_device *dev, int count, const unsigned char *buf,
 462                                int start_page)
 463{
 464        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 465        void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8);
 466
 467
 468        if (ei_status.word16) {
 469                /* Turn on and off 16 bit access so that reboot works. */
 470                outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 471                memcpy_toio(shmem, buf, count);
 472                outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 473        } else
 474                memcpy_toio(shmem, buf, count);
 475}
 476
 477
 478static int
 479wd_close(struct net_device *dev)
 480{
 481        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 482        struct ei_device *ei_local = netdev_priv(dev);
 483
 484        netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n");
 485        ei_close(dev);
 486
 487        /* Change from 16-bit to 8-bit shared memory so reboot works. */
 488        if (ei_status.word16)
 489                outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
 490
 491        /* And disable the shared memory. */
 492        outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 493
 494        return 0;
 495}
 496
 497
 498#ifdef MODULE
 499#define MAX_WD_CARDS    4       /* Max number of wd cards per module */
 500static struct net_device *dev_wd[MAX_WD_CARDS];
 501static int io[MAX_WD_CARDS];
 502static int irq[MAX_WD_CARDS];
 503static int mem[MAX_WD_CARDS];
 504static int mem_end[MAX_WD_CARDS];       /* for non std. mem size */
 505
 506module_param_hw_array(io, int, ioport, NULL, 0);
 507module_param_hw_array(irq, int, irq, NULL, 0);
 508module_param_hw_array(mem, int, iomem, NULL, 0);
 509module_param_hw_array(mem_end, int, iomem, NULL, 0);
 510module_param_named(msg_enable, wd_msg_enable, uint, 0444);
 511MODULE_PARM_DESC(io, "I/O base address(es)");
 512MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
 513MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
 514MODULE_PARM_DESC(mem_end, "memory end address(es)");
 515MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
 516MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
 517MODULE_LICENSE("GPL");
 518
 519/* This is set up so that only a single autoprobe takes place per call.
 520ISA device autoprobes on a running machine are not recommended. */
 521
 522int __init init_module(void)
 523{
 524        struct net_device *dev;
 525        int this_dev, found = 0;
 526
 527        for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
 528                if (io[this_dev] == 0)  {
 529                        if (this_dev != 0) break; /* only autoprobe 1st one */
 530                        printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
 531                }
 532                dev = alloc_ei_netdev();
 533                if (!dev)
 534                        break;
 535                dev->irq = irq[this_dev];
 536                dev->base_addr = io[this_dev];
 537                dev->mem_start = mem[this_dev];
 538                dev->mem_end = mem_end[this_dev];
 539                if (do_wd_probe(dev) == 0) {
 540                        dev_wd[found++] = dev;
 541                        continue;
 542                }
 543                free_netdev(dev);
 544                printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
 545                break;
 546        }
 547        if (found)
 548                return 0;
 549        return -ENXIO;
 550}
 551
 552static void cleanup_card(struct net_device *dev)
 553{
 554        free_irq(dev->irq, dev);
 555        release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
 556        iounmap(ei_status.mem);
 557}
 558
 559void __exit
 560cleanup_module(void)
 561{
 562        int this_dev;
 563
 564        for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
 565                struct net_device *dev = dev_wd[this_dev];
 566                if (dev) {
 567                        unregister_netdev(dev);
 568                        cleanup_card(dev);
 569                        free_netdev(dev);
 570                }
 571        }
 572}
 573#endif /* MODULE */
 574