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

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