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