~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/net/wd.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.