root/drivers/net/e2100.c

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

DEFINITIONS

This source file includes following definitions.
  1. mem_on
  2. mem_off
  3. e2100_probe
  4. e21_probe1
  5. e21_open
  6. e21_reset_8390
  7. e21_block_input
  8. e21_block_output
  9. e21_close
  10. init_module
  11. cleanup_module

   1 /* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
   2 /*
   3         Written 1993-1994 by Donald Becker.
   4 
   5         Copyright 1994 by Donald Becker.
   6         Copyright 1993 United States Government as represented by the
   7         Director, National Security Agency.  This software may be used and
   8         distributed according to the terms of the GNU Public License,
   9         incorporated herein by reference.
  10 
  11         This is a driver for the Cabletron E2100 series ethercards.
  12 
  13         The Author may be reached as becker@cesdis.gsfc.nasa.gov, or
  14         C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  15 
  16         The E2100 series ethercard is a fairly generic shared memory 8390
  17         implementation.  The only unusual aspect is the way the shared memory
  18         registers are set: first you do an inb() in what is normally the
  19         station address region, and the low three bits of next outb() *address*
  20         is used as the write value for that register.  Either someone wasn't
  21         too used to dem bit en bites, or they were trying to obfuscate the
  22         programming     interface.
  23 
  24         There is an additional complication when setting the window on the packet
  25         buffer.  You must first do a read into the packet buffer region with the
  26         low 8 address bits the address setting the page for the start of the packet
  27         buffer window, and then do the above operation.  See mem_on() for details.
  28 
  29         One bug on the chip is that even a hard reset won't disable the memory
  30         window, usually resulting in a hung machine if mem_off() isn't called.
  31         If this happens, you must power down the machine for about 30 seconds.
  32 */
  33 
  34 static const char *version =
  35         "e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
  36 
  37 #ifdef MODULE
  38 #include <linux/module.h>
  39 #include <linux/version.h>
  40 #endif
  41 
  42 #include <linux/kernel.h>
  43 #include <linux/sched.h>
  44 #include <linux/errno.h>
  45 #include <linux/string.h>
  46 #include <asm/io.h>
  47 #include <asm/system.h>
  48 #include <linux/ioport.h>
  49 
  50 #include <linux/netdevice.h>
  51 #include "8390.h"
  52 
  53 static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
  54 
  55 /* Offsets from the base_addr.
  56    Read from the ASIC register, and the low three bits of the next outb()
  57    address is used to set the corresponding register. */
  58 #define E21_NIC_OFFSET  0               /* Offset to the 8390 NIC. */
  59 #define E21_ASIC                0x10
  60 #define E21_MEM_ENABLE  0x10
  61 #define  E21_MEM_ON             0x05    /* Enable memory in 16 bit mode. */
  62 #define  E21_MEM_ON_8   0x07    /* Enable memory in  8 bit mode. */
  63 #define E21_MEM_BASE    0x11    
  64 #define E21_IRQ_LOW             0x12    /* The low three bits of the IRQ number. */
  65 #define E21_IRQ_HIGH    0x14    /* The high IRQ bit and media select ...  */
  66 #define E21_MEDIA               0x14    /* (alias). */
  67 #define  E21_ALT_IFPORT 0x02    /* Set to use the other (BNC,AUI) port. */
  68 #define  E21_BIG_MEM    0x04    /* Use a bigger (64K) buffer (we don't) */
  69 #define E21_SAPROM              0x10    /* Offset to station address data. */
  70 #define E21_IO_EXTENT    0x20
  71 
  72 extern inline void mem_on(short port, volatile char *mem_base,
     /* [previous][next][first][last][top][bottom][index][help] */
  73                                                   unsigned char start_page )
  74 {
  75         /* This is a little weird: set the shared memory window by doing a
  76            read.  The low address bits specify the starting page. */
  77         mem_base[start_page];
  78         inb(port + E21_MEM_ENABLE);
  79         outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
  80 }
  81 
  82 extern inline void mem_off(short port)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84         inb(port + E21_MEM_ENABLE);
  85         outb(0x00, port + E21_MEM_ENABLE);
  86 }
  87 
  88 /* In other drivers I put the TX pages first, but the E2100 window circuitry
  89    is designed to have a 4K Tx region last. The windowing circuitry wraps the
  90    window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
  91    appear contiguously in the window. */
  92 #define E21_RX_START_PG         0x00    /* First page of RX buffer */
  93 #define E21_RX_STOP_PG          0x30    /* Last page +1 of RX ring */
  94 #define E21_BIG_RX_STOP_PG      0xF0    /* Last page +1 of RX ring */
  95 #define E21_TX_START_PG         E21_RX_STOP_PG  /* First page of TX buffer */
  96 
  97 int e2100_probe(struct device *dev);
  98 int e21_probe1(struct device *dev, int ioaddr);
  99 
 100 static int e21_open(struct device *dev);
 101 static void e21_reset_8390(struct device *dev);
 102 static int e21_block_input(struct device *dev, int count,
 103                                                    char *buf, int ring_offset);
 104 static void e21_block_output(struct device *dev, int count,
 105                                                          const unsigned char *buf, const start_page);
 106 static int e21_close(struct device *dev);
 107 
 108 
 109 /*  Probe for the E2100 series ethercards.  These cards have an 8390 at the
 110         base address and the station address at both offset 0x10 and 0x18.  I read
 111         the station address from offset 0x18 to avoid the dataport of NE2000
 112         ethercards, and look for Ctron's unique ID (first three octets of the
 113         station address).
 114  */
 115 
 116 int e2100_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118         int *port;
 119         int base_addr = dev->base_addr;
 120 
 121         if (base_addr > 0x1ff)          /* Check a single specified location. */
 122                 return e21_probe1(dev, base_addr);
 123         else if (base_addr != 0)        /* Don't probe at all. */
 124                 return ENXIO;
 125 
 126         for (port = e21_probe_list; *port; port++) {
 127                 if (check_region(*port, E21_IO_EXTENT))
 128                         continue;
 129                 if (e21_probe1(dev, *port) == 0)
 130                         return 0;
 131         }
 132 
 133         return ENODEV;
 134 }
 135 
 136 int e21_probe1(struct device *dev, int ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138         int i, status;
 139         unsigned char *station_addr = dev->dev_addr;
 140 
 141         /* First check the station address for the Ctron prefix. */
 142         if (inb(ioaddr + E21_SAPROM + 0) != 0x00
 143                 || inb(ioaddr + E21_SAPROM + 1) != 0x00
 144                 || inb(ioaddr + E21_SAPROM + 2) != 0x1d)
 145                 return ENODEV;
 146 
 147         /* Verify by making certain that there is a 8390 at there. */
 148         outb(E8390_NODMA + E8390_STOP, ioaddr);
 149         SLOW_DOWN_IO;
 150         status = inb(ioaddr);
 151         if (status != 0x21 && status != 0x23)
 152                 return ENODEV;
 153 
 154         /* Read the station address PROM.  */
 155         for (i = 0; i < 6; i++)
 156                 station_addr[i] = inb(ioaddr + E21_SAPROM + i);
 157 
 158         inb(ioaddr + E21_MEDIA);                /* Point to media selection. */
 159         outb(0, ioaddr + E21_ASIC);     /* and disable the secondary interface. */
 160 
 161         printk("%s: E21** at %#3x,", dev->name, ioaddr);
 162         for (i = 0; i < 6; i++)
 163                 printk(" %02X", station_addr[i]);
 164 
 165         if (dev->irq < 2) {
 166                 int irqlist[] = {15,11,10,12,5,9,3,4}, i;
 167                 for (i = 0; i < 8; i++)
 168                         if (request_irq (irqlist[i], NULL, 0, "bogus") != -EBUSY) {
 169                                 dev->irq = irqlist[i];
 170                                 break;
 171                         }
 172                 if (i >= 8) {
 173                         printk(" unable to get IRQ %d.\n", dev->irq);
 174                         return EAGAIN;
 175                 }
 176         } else if (dev->irq == 2)       /* Fixup luser bogosity: IRQ2 is really IRQ9 */
 177                 dev->irq = 9;
 178 
 179         /* Grab the region so we can find a different board if IRQ select fails. */
 180         request_region(ioaddr, E21_IO_EXTENT, "e2100");
 181 
 182         /* The 8390 is at the base address. */
 183         dev->base_addr = ioaddr;
 184 
 185         ethdev_init(dev);
 186 
 187         ei_status.name = "E2100";
 188         ei_status.word16 = 1;
 189         ei_status.tx_start_page = E21_TX_START_PG;
 190         ei_status.rx_start_page = E21_RX_START_PG;
 191         ei_status.stop_page = E21_RX_STOP_PG;
 192     ei_status.saved_irq = dev->irq;
 193 
 194         /* Check the media port used.  The port can be passed in on the
 195            low mem_end bits. */
 196         if (dev->mem_end & 15)
 197                 dev->if_port = dev->mem_end & 7;
 198         else {
 199                 dev->if_port = 0;
 200                 inb(ioaddr + E21_MEDIA);        /* Turn automatic media detection on. */
 201                 for(i = 0; i < 6; i++)
 202                         if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) {
 203                                 dev->if_port = 1;
 204                                 break;
 205                         }
 206         }
 207 
 208         /* Never map in the E21 shared memory unless you are actively using it.
 209            Also, the shared memory has effective only one setting -- spread all
 210            over the 128K region! */
 211         if (dev->mem_start == 0)
 212                 dev->mem_start = 0xd0000;
 213         
 214 #ifdef notdef
 215         /* These values are unused.  The E2100 has a 2K window into the packet
 216            buffer.  The window can be set to start on any page boundary. */
 217         dev->rmem_start = dev->mem_start + TX_PAGES*256;
 218         dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
 219 #endif
 220 
 221         printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
 222                    dev->if_port ? "secondary" : "primary", dev->mem_start);
 223 
 224         if (ei_debug > 0)
 225                 printk(version);
 226 
 227         ei_status.reset_8390 = &e21_reset_8390;
 228         ei_status.block_input = &e21_block_input;
 229         ei_status.block_output = &e21_block_output;
 230         dev->open = &e21_open;
 231         dev->stop = &e21_close;
 232         NS8390_init(dev, 0);
 233 
 234         return 0;
 235 }
 236 
 237 static int
 238 e21_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 239 {
 240         short ioaddr = dev->base_addr;
 241         int rc;
 242 
 243         if (request_irq(dev->irq, ei_interrupt, 0, "e2100")) {
 244                 return EBUSY;
 245         }
 246         irq2dev_map[dev->irq] = dev;
 247 
 248         /* Set the interrupt line and memory base on the hardware. */
 249         inb(ioaddr + E21_IRQ_LOW);
 250         outb(0, ioaddr + E21_ASIC + (dev->irq & 7));
 251         inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
 252         outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
 253                    + (dev->if_port ? E21_ALT_IFPORT : 0));
 254         inb(ioaddr + E21_MEM_BASE);
 255         outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
 256 
 257         rc = ei_open(dev);
 258         if (rc != 0) return rc;
 259 #ifdef MODULE
 260         MOD_INC_USE_COUNT;
 261 #endif
 262         return 0;
 263 }
 264 
 265 static void
 266 e21_reset_8390(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 267 {
 268         short ioaddr = dev->base_addr;
 269 
 270         outb(0x01, ioaddr);
 271         if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies);
 272         ei_status.txing = 0;
 273 
 274         /* Set up the ASIC registers, just in case something changed them. */
 275 
 276         if (ei_debug > 1) printk("reset done\n");
 277         return;
 278 }
 279 
 280 /*  Block input and output are easy on shared memory ethercards.
 281         The E21xx makes block_input() especially easy by wrapping the top
 282         ring buffer to the bottom automatically. */
 283 static int
 284 e21_block_input(struct device *dev, int count, char *buf, int ring_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286         short ioaddr = dev->base_addr;
 287         char *shared_mem = (char *)dev->mem_start;
 288         int start_page = (ring_offset>>8);
 289 
 290         mem_on(ioaddr, shared_mem, start_page);
 291 
 292         /* We'll always get a 4 byte header read first. */
 293         if (count == 4)
 294                 ((int*)buf)[0] = ((int*)shared_mem)[0];
 295         else
 296                 memcpy(buf, shared_mem + (ring_offset & 0xff), count);
 297 
 298         /* Turn off memory access: we would need to reprogram the window anyway. */
 299         mem_off(ioaddr);
 300 
 301         return 0;
 302 }
 303 
 304 static void
 305 e21_block_output(struct device *dev, int count, const unsigned char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 306                                  int start_page)
 307 {
 308         short ioaddr = dev->base_addr;
 309         volatile char *shared_mem = (char *)dev->mem_start;
 310 
 311         /* Set the shared memory window start by doing a read, with the low address
 312            bits specifying the starting page. */
 313         *(shared_mem + start_page);
 314         mem_on(ioaddr, shared_mem, start_page);
 315 
 316         memcpy((char*)shared_mem, buf, count);
 317         mem_off(ioaddr);
 318 }
 319 
 320 static int
 321 e21_close(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 322 {
 323         short ioaddr = dev->base_addr;
 324 
 325         if (ei_debug > 1)
 326                 printk("%s: Shutting down ethercard.\n", dev->name);
 327 
 328     free_irq(dev->irq);
 329     dev->irq = ei_status.saved_irq;
 330 
 331         /* Shut off the interrupt line and secondary interface. */
 332         inb(ioaddr + E21_IRQ_LOW);
 333         outb(0, ioaddr + E21_ASIC);
 334         inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
 335         outb(0, ioaddr + E21_ASIC);
 336 
 337     irq2dev_map[dev->irq] = NULL;
 338 
 339         NS8390_init(dev, 0);
 340 
 341         /* Double-check that the memory has been turned off, because really
 342            really bad things happen if it isn't. */
 343         mem_off(ioaddr);
 344 
 345 #ifdef MODULE
 346         MOD_DEC_USE_COUNT;
 347 #endif
 348 
 349         return 0;
 350 }
 351 
 352 #ifdef HAVE_DEVLIST
 353 struct netdev_entry e21_drv =
 354 {"e21", e21_probe1, E21_IO_EXTENT, e21_probe_list};
 355 #endif
 356 
 357 #ifdef MODULE
 358 char kernel_version[] = UTS_RELEASE;
 359 static char devicename[9] = { 0, };
 360 static struct device dev_e2100 = {
 361         devicename, /* device name is inserted by linux/drivers/net/net_init.c */
 362         0, 0, 0, 0,
 363         0, 0,
 364         0, 0, 0, NULL, e2100_probe };
 365 
 366 int io = 0x300;
 367 int irq = 0;
 368 
 369 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 370 {
 371         if (io == 0)
 372                 printk("e2100: You should not use auto-probing with insmod!\n");
 373         dev_e2100.base_addr = io;
 374         dev_e2100.irq       = irq;
 375         if (register_netdev(&dev_e2100) != 0) {
 376                 printk("e2100: register_netdev() returned non-zero.\n");
 377                 return -EIO;
 378         }
 379         return 0;
 380 }
 381 
 382 void
 383 cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385         if (MOD_IN_USE)
 386                 printk("e2100: device busy, remove delayed\n");
 387         else
 388         {
 389                 unregister_netdev(&dev_e2100);
 390 
 391                 /* If we don't do this, we can't re-insmod it later. */
 392                 release_region(dev_e2100.base_addr, E21_IO_EXTENT);
 393         }
 394 }
 395 #endif /* MODULE */
 396 
 397 /*
 398  * Local variables:
 399  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c"
 400  *  version-control: t
 401  *  tab-width: 4
 402  *  kept-new-versions: 5
 403  * End:
 404  */

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