linux/drivers/net/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#include <asm/system.h>
  43
  44#include "8390.h"
  45
  46#define DRV_NAME "wd"
  47
  48/* A zero-terminated list of I/O addresses to be probed. */
  49static unsigned int wd_portlist[] __initdata =
  50{0x300, 0x280, 0x380, 0x240, 0};
  51
  52static int wd_probe1(struct net_device *dev, int ioaddr);
  53
  54static int wd_open(struct net_device *dev);
  55static void wd_reset_8390(struct net_device *dev);
  56static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
  57                                                int ring_page);
  58static void wd_block_input(struct net_device *dev, int count,
  59                                                  struct sk_buff *skb, int ring_offset);
  60static void wd_block_output(struct net_device *dev, int count,
  61                                                        const unsigned char *buf, int start_page);
  62static int wd_close(struct net_device *dev);
  63
  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_multicast_list = ei_set_multicast_list,
 157        .ndo_validate_addr      = eth_validate_addr,
 158        .ndo_set_mac_address    = eth_mac_addr,
 159        .ndo_change_mtu         = eth_change_mtu,
 160#ifdef CONFIG_NET_POLL_CONTROLLER
 161        .ndo_poll_controller    = ei_poll,
 162#endif
 163};
 164
 165static int __init wd_probe1(struct net_device *dev, int ioaddr)
 166{
 167        int i;
 168        int err;
 169        int checksum = 0;
 170        int ancient = 0;                        /* An old card without config registers. */
 171        int word16 = 0;                         /* 0 = 8 bit, 1 = 16 bit */
 172        const char *model_name;
 173        static unsigned version_printed;
 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                printk(KERN_WARNING "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
 185                dev->mem_start = 0;
 186                dev->mem_end = 0;
 187        }
 188
 189        if (ei_debug  &&  version_printed++ == 0)
 190                printk(version);
 191
 192        for (i = 0; i < 6; i++)
 193                dev->dev_addr[i] = inb(ioaddr + 8 + i);
 194
 195        printk("%s: WD80x3 at %#3x, %pM",
 196               dev->name, 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                        printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
 249                                   word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
 250#endif
 251        }
 252
 253#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
 254        /* Allow a compile-time override.        */
 255        dev->mem_start = WD_SHMEM;
 256#else
 257        if (dev->mem_start == 0) {
 258                /* Sanity and old 8003 check */
 259                int reg0 = inb(ioaddr);
 260                if (reg0 == 0xff || reg0 == 0) {
 261                        /* Future plan: this could check a few likely locations first. */
 262                        dev->mem_start = 0xd0000;
 263                        printk(" assigning address %#lx", dev->mem_start);
 264                } else {
 265                        int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
 266                        /* Some boards don't have the register 5 -- it returns 0xff. */
 267                        if (high_addr_bits == 0x1f || word16 == 0)
 268                                high_addr_bits = 0x01;
 269                        dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
 270                }
 271        }
 272#endif
 273
 274        /* The 8390 isn't at the base address -- the ASIC regs are there! */
 275        dev->base_addr = ioaddr+WD_NIC_OFFSET;
 276
 277        if (dev->irq < 2) {
 278                int irqmap[] = {9,3,5,7,10,11,15,4};
 279                int reg1 = inb(ioaddr+1);
 280                int reg4 = inb(ioaddr+4);
 281                if (ancient || reg1 == 0xff) {  /* Ack!! No way to read the IRQ! */
 282                        short nic_addr = ioaddr+WD_NIC_OFFSET;
 283                        unsigned long irq_mask;
 284
 285                        /* We have an old-style ethercard that doesn't report its IRQ
 286                           line.  Do autoirq to find the IRQ line. Note that this IS NOT
 287                           a reliable way to trigger an interrupt. */
 288                        outb_p(E8390_NODMA + E8390_STOP, nic_addr);
 289                        outb(0x00, nic_addr+EN0_IMR);   /* Disable all intrs. */
 290
 291                        irq_mask = probe_irq_on();
 292                        outb_p(0xff, nic_addr + EN0_IMR);       /* Enable all interrupts. */
 293                        outb_p(0x00, nic_addr + EN0_RCNTLO);
 294                        outb_p(0x00, nic_addr + EN0_RCNTHI);
 295                        outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
 296                        mdelay(20);
 297                        dev->irq = probe_irq_off(irq_mask);
 298
 299                        outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
 300
 301                        if (ei_debug > 2)
 302                                printk(" autoirq is %d", dev->irq);
 303                        if (dev->irq < 2)
 304                                dev->irq = word16 ? 10 : 5;
 305                } else
 306                        dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
 307        } else if (dev->irq == 2)               /* Fixup bogosity: IRQ2 is really IRQ9 */
 308                dev->irq = 9;
 309
 310        /* Snarf the interrupt now.  There's no point in waiting since we cannot
 311           share and the board will usually be enabled. */
 312        i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 313        if (i) {
 314                printk (" unable to get IRQ %d.\n", dev->irq);
 315                return i;
 316        }
 317
 318        /* OK, were are certain this is going to work.  Setup the device. */
 319        ei_status.name = model_name;
 320        ei_status.word16 = word16;
 321        ei_status.tx_start_page = WD_START_PG;
 322        ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 323
 324        /* Don't map in the shared memory until the board is actually opened. */
 325
 326        /* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
 327        if (dev->mem_end != 0) {
 328                ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
 329                ei_status.priv = dev->mem_end - dev->mem_start;
 330        } else {
 331                ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
 332                dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
 333                ei_status.priv = (ei_status.stop_page - WD_START_PG)*256;
 334        }
 335
 336        ei_status.mem = ioremap(dev->mem_start, ei_status.priv);
 337        if (!ei_status.mem) {
 338                free_irq(dev->irq, dev);
 339                return -ENOMEM;
 340        }
 341
 342        printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 343                   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
 344
 345        ei_status.reset_8390 = &wd_reset_8390;
 346        ei_status.block_input = &wd_block_input;
 347        ei_status.block_output = &wd_block_output;
 348        ei_status.get_8390_hdr = &wd_get_8390_hdr;
 349
 350        dev->netdev_ops = &wd_netdev_ops;
 351        NS8390_init(dev, 0);
 352
 353#if 1
 354        /* Enable interrupt generation on softconfig cards -- M.U */
 355        /* .. but possibly potentially unsafe - Donald */
 356        if (inb(ioaddr+14) & 0x20)
 357                outb(inb(ioaddr+4)|0x80, ioaddr+4);
 358#endif
 359
 360        err = register_netdev(dev);
 361        if (err)
 362                free_irq(dev->irq, dev);
 363        return err;
 364}
 365
 366static int
 367wd_open(struct net_device *dev)
 368{
 369  int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 370
 371  /* Map in the shared memory. Always set register 0 last to remain
 372         compatible with very old boards. */
 373  ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
 374  ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
 375
 376  if (ei_status.word16)
 377          outb(ei_status.reg5, ioaddr+WD_CMDREG5);
 378  outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 379
 380  return ei_open(dev);
 381}
 382
 383static void
 384wd_reset_8390(struct net_device *dev)
 385{
 386        int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 387
 388        outb(WD_RESET, wd_cmd_port);
 389        if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies);
 390        ei_status.txing = 0;
 391
 392        /* Set up the ASIC registers, just in case something changed them. */
 393        outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
 394        if (ei_status.word16)
 395                outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
 396
 397        if (ei_debug > 1) printk("reset done\n");
 398        return;
 399}
 400
 401/* Grab the 8390 specific header. Similar to the block_input routine, but
 402   we don't need to be concerned with ring wrap as the header will be at
 403   the start of a page, so we optimize accordingly. */
 404
 405static void
 406wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 407{
 408
 409        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 410        void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8);
 411
 412        /* We'll always get a 4 byte header read followed by a packet read, so
 413           we enable 16 bit mode before the header, and disable after the body. */
 414        if (ei_status.word16)
 415                outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 416
 417#ifdef __BIG_ENDIAN
 418        /* Officially this is what we are doing, but the readl() is faster */
 419        /* unfortunately it isn't endian aware of the struct               */
 420        memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 421        hdr->count = le16_to_cpu(hdr->count);
 422#else
 423        ((unsigned int*)hdr)[0] = readl(hdr_start);
 424#endif
 425}
 426
 427/* Block input and output are easy on shared memory ethercards, and trivial
 428   on the Western digital card where there is no choice of how to do it.
 429   The only complications are that the ring buffer wraps, and need to map
 430   switch between 8- and 16-bit modes. */
 431
 432static void
 433wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 434{
 435        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 436        unsigned long offset = ring_offset - (WD_START_PG<<8);
 437        void __iomem *xfer_start = ei_status.mem + offset;
 438
 439        if (offset + count > ei_status.priv) {
 440                /* We must wrap the input move. */
 441                int semi_count = ei_status.priv - offset;
 442                memcpy_fromio(skb->data, xfer_start, semi_count);
 443                count -= semi_count;
 444                memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
 445        } else {
 446                /* Packet is in one chunk -- we can copy + cksum. */
 447                memcpy_fromio(skb->data, xfer_start, count);
 448        }
 449
 450        /* Turn off 16 bit access so that reboot works.  ISA brain-damage */
 451        if (ei_status.word16)
 452                outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 453}
 454
 455static void
 456wd_block_output(struct net_device *dev, int count, const unsigned char *buf,
 457                                int start_page)
 458{
 459        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 460        void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8);
 461
 462
 463        if (ei_status.word16) {
 464                /* Turn on and off 16 bit access so that reboot works. */
 465                outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 466                memcpy_toio(shmem, buf, count);
 467                outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 468        } else
 469                memcpy_toio(shmem, buf, count);
 470}
 471
 472
 473static int
 474wd_close(struct net_device *dev)
 475{
 476        int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 477
 478        if (ei_debug > 1)
 479                printk("%s: Shutting down ethercard.\n", dev->name);
 480        ei_close(dev);
 481
 482        /* Change from 16-bit to 8-bit shared memory so reboot works. */
 483        if (ei_status.word16)
 484                outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
 485
 486        /* And disable the shared memory. */
 487        outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 488
 489        return 0;
 490}
 491
 492
 493#ifdef MODULE
 494#define MAX_WD_CARDS    4       /* Max number of wd cards per module */
 495static struct net_device *dev_wd[MAX_WD_CARDS];
 496static int io[MAX_WD_CARDS];
 497static int irq[MAX_WD_CARDS];
 498static int mem[MAX_WD_CARDS];
 499static int mem_end[MAX_WD_CARDS];       /* for non std. mem size */
 500
 501module_param_array(io, int, NULL, 0);
 502module_param_array(irq, int, NULL, 0);
 503module_param_array(mem, int, NULL, 0);
 504module_param_array(mem_end, int, NULL, 0);
 505MODULE_PARM_DESC(io, "I/O base address(es)");
 506MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
 507MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
 508MODULE_PARM_DESC(mem_end, "memory end address(es)");
 509MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
 510MODULE_LICENSE("GPL");
 511
 512/* This is set up so that only a single autoprobe takes place per call.
 513ISA device autoprobes on a running machine are not recommended. */
 514
 515int __init init_module(void)
 516{
 517        struct net_device *dev;
 518        int this_dev, found = 0;
 519
 520        for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
 521                if (io[this_dev] == 0)  {
 522                        if (this_dev != 0) break; /* only autoprobe 1st one */
 523                        printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
 524                }
 525                dev = alloc_ei_netdev();
 526                if (!dev)
 527                        break;
 528                dev->irq = irq[this_dev];
 529                dev->base_addr = io[this_dev];
 530                dev->mem_start = mem[this_dev];
 531                dev->mem_end = mem_end[this_dev];
 532                if (do_wd_probe(dev) == 0) {
 533                        dev_wd[found++] = dev;
 534                        continue;
 535                }
 536                free_netdev(dev);
 537                printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
 538                break;
 539        }
 540        if (found)
 541                return 0;
 542        return -ENXIO;
 543}
 544
 545static void cleanup_card(struct net_device *dev)
 546{
 547        free_irq(dev->irq, dev);
 548        release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
 549        iounmap(ei_status.mem);
 550}
 551
 552void __exit
 553cleanup_module(void)
 554{
 555        int this_dev;
 556
 557        for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
 558                struct net_device *dev = dev_wd[this_dev];
 559                if (dev) {
 560                        unregister_netdev(dev);
 561                        cleanup_card(dev);
 562                        free_netdev(dev);
 563                }
 564        }
 565}
 566#endif /* MODULE */
 567