[23] in linux-net channel archive
New modules: wd.c and 3c503.c
daemon@ATHENA.MIT.EDU (Paul Gortmaker)
Thu Jan 19 11:57:50 1995
From: Paul Gortmaker <paul@rasty.anu.edu.au>
To: linux-net@vger.rutgers.edu
Date: Fri, 20 Jan 1995 01:00:43 +1000 (EST)
Cc: bj0rn@blox.se, linux-activists@niksula.hut.fi (linux)
Hello net-folk.
Here are two new modules, for the wd80x3 and the 3c503 ethernet
cards. There is also some fixes to the 3c501 and the 3c509 modules,
as listed below. I have put the module #includes at the top of
the new modules (wd.c and 3c503.c) as Bjorn requested. I did not
move the #includes for the '501 and the '509, as Bjorn said he would
fix all modules present in 83.
This patch is against 83, but should go over 82 as well. It will
NOT go over 81, due to the irq handler changes. (Note that there
are some minor /proc formatting changes that are nice, but not
required. You can cut these out of the patch if you *really* want.)
I have tested these quite extensively both as modules, and as
compiled in drivers, but would like others to test them as well.
Also, the latest Ethernet-HowTo (as of yesterday ;-) now has a short
section on using e'net modules. You can view it from <shameless plug>
http://rsphy1.anu.edu.au/~gpg109
Have fun with it.
Paul.
==================================================================
Here is an example of how to handle two ethercards of the same
brand with the new modules. Nice and simple.
==================================================================
testbox:/tmp/modules/83# ll wd.o
-rw------- 1 root root 4398 Jan 18 00:29 wd.o
testbox:/tmp/modules/83# ln -sf wd.o wd0
testbox:/tmp/modules/83# ln -sf wd.o wd1
testbox:/tmp/modules/83# insmod 8390.o
testbox:/tmp/modules/83# insmod wd0
testbox:/tmp/modules/83# insmod wd1
testbox:/tmp/modules/83# lsmod
Module: #pages: Used by:
wd1 1
wd0 1
8390 2 [wd1, wd0]
testbox:/tmp/modules/83# dmesg
loading device 'eth0'...
eth0: WD80x3 at 0x300, 00 00 C0 4E DC 52 WD8003, IRQ 5, shared memory at 0xca000-0xcbfff.
wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)
loading device 'eth1'...
eth1: WD80x3 at 0x280, 00 00 C0 B4 26 1C WD8003, IRQ 9, shared memory at 0xd0000-0xd1fff.
wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)
testbox:/tmp/modules/83#
==================================================================
Here is an example of two different cards, using the new modules:
==================================================================
testbox:/tmp/modules/83# insmod 8390.o ; insmod wd.o
testbox:/tmp/modules/83# lsmod
Module: #pages: Used by:
wd 1
8390 2 [wd]
testbox:/tmp/modules/83# dmesg -c
loading device 'eth0'...
eth0: WD80x3 at 0x280, 00 00 C0 B4 26 1C WD8003, IRQ 9, shared memory at 0xd0000-0xd1fff.
wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)
testbox:/tmp/modules/83# insmod 3c503.o
testbox:/tmp/modules/83# lsmod
Module: #pages: Used by:
3c503 1
wd 1
8390 2 [3c503, wd]
testbox:/tmp/modules/83# dmesg -c
loading device 'eth1'...
3c503.c:v1.10 9/23/93 Donald Becker (becker@cesdis.gsfc.nasa.gov)
eth1: 3c503 at 0x300, 02 60 8c 3d ea 4e
eth1: 3C503 with shared memory at 0xdc000-0xddfff,
testbox:/tmp/modules/83#
==================================================================
The Fixes:
==========
3c501 and 3c509 modules didn't release_region() when being removed.
This means that you can never re-insmod them in again, and worse,
I think that /proc/ioports will NULL dereference when it goes to look up
the p->name of the removed module. Ugh.
3c501 module didn't give back the memory from dev->priv before
getting nuked. Result - memory leak.
3c501, 3c509, wd, 3c503: Don't bother checking MOD_IN_USE before
closing down. It will never happen, as sys_delete_module() does
this before calling the local cleanup_module() function.
8390.c -- added ei_close() as a default dev->stop. Now used in
3c503 and wd driver. Can also be used in smc-ultra, etc. and
may reduce kernel size in multiple 8390 configurations.
wd.c: Don't grab IRQ at probe, instead wait until wd_open(). Also
we try and inhibit interrupt generation when closed. Also use above
ei_close().
3c501, 3c503, wd: #ifndef the init_etherdev function, as it is not
needed for modules (dev struct is declared static in init_module)
and that saves exporting another ksym.
3c501, 3c503, 3c509, wd: Append "(mod)" to the name passed to
request_region() and request_irq() if it is a module. This is
done with #ifdef's so it doesn't bloat the driver.
kernel/ksyms.c: added autoirq_setup and autoirq_report to the list.
i386/kernel/irq.c: Made the /proc/interrupts a bit more clear.
kernel/module.c: separate multiple modules in the "Used by" list
with a comma (see above).
The Patch:
==========
diff -ur linux-83/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- linux-83/arch/i386/kernel/irq.c Thu Jan 19 20:50:42 1995
+++ linux/arch/i386/kernel/irq.c Thu Jan 19 22:20:41 1995
@@ -164,12 +164,13 @@
int i, len = 0;
struct irqaction * action = irq_action;
+ len=sprintf(buf, "IRQ | Use | Fast | Device\n");
for (i = 0 ; i < 16 ; i++, action++) {
if (!action->handler)
continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ len += sprintf(buf+len, "%2d: %8d %s %s\n",
i, kstat.interrupts[i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ (action->flags & SA_INTERRUPT) ? "yes" : "no ",
action->name);
}
return len;
diff -ur linux-83/drivers/net/3c501.c linux/drivers/net/3c501.c
--- linux-83/drivers/net/3c501.c Thu Jan 19 20:50:47 1995
+++ linux/drivers/net/3c501.c Thu Jan 19 22:20:41 1995
@@ -17,6 +17,9 @@
Fixed (again!) the missing interrupt locking on TX/RX shifting.
Alan Cox <Alan.Cox@linux.org>
+
+ Module cleanups and insmod/rmmod memory leak plugged.
+ Paul Gortmaker <Paul.Gortmaker@anu.edu.au>
Some notes on this thing if you have to hack it. [Alan]
@@ -95,8 +98,10 @@
#include <linux/version.h>
#endif
+#ifndef MODULE
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
unsigned long *mem_startp);
+#endif
/* A zero-terminated list of I/O addresses to be probed.
The 3c501 can be at many locations, but here are the popular ones. */
@@ -230,10 +235,18 @@
return ENODEV;
/* Grab the region so we can find the another board if autoIRQ fails. */
- request_region(ioaddr, EL1_IO_EXTENT,"3c501");
+ request_region(ioaddr, EL1_IO_EXTENT,
+#ifdef MODULE
+ "3c501(mod)"
+#else
+ "3c501"
+#endif
+ );
+#ifndef MODULE /* modules allocate a static dev struct */
if (dev == NULL)
dev = init_etherdev(0, sizeof(struct net_local), 0);
+#endif
/* We auto-IRQ by shutting off the interrupt line and letting it float
high. */
@@ -302,7 +315,13 @@
if (el_debug > 2)
printk("%s: Doing el_open()...", dev->name);
- if (request_irq(dev->irq, &el_interrupt, 0, "3c501")) {
+ if (request_irq(dev->irq, &el_interrupt, 0,
+#ifdef MODULE
+ "3c501(mod)"
+#else
+ "3c501"
+#endif
+ )) {
return -EAGAIN;
}
irq2dev_map[dev->irq] = dev;
@@ -677,12 +696,15 @@
void
cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("3c501: device busy, remove delayed\n");
- else
- {
- unregister_netdev(&dev_3c501);
- }
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ unregister_netdev(&dev_3c501);
+
+ /* Free up the private structure, or leak memory :-) */
+ kfree_s(dev_3c501.priv,sizeof(struct net_local));
+ dev_3c501.priv=NULL; /* gets re-allocated by el1_probe1 */
+
+ /* If we don't do this, we can't re-insmod it later. */
+ release_region(dev_3c501.base_addr, EL1_IO_EXTENT);
}
#endif /* MODULE */
diff -ur linux-83/drivers/net/3c503.c linux/drivers/net/3c503.c
--- linux-83/drivers/net/3c503.c Thu Jan 19 20:50:21 1995
+++ linux/drivers/net/3c503.c Fri Jan 20 00:15:55 1995
@@ -20,11 +20,21 @@
3Com Corporation, 5400 Bayfront Plaza, Santa Clara CA 95052-8145
The Crynwr 3c503 packet driver.
+
+ Change Log:
+ 17/01/95 Module support + use ei_close() from 8390.c.
+ Paul Gortmaker (Paul.Gortmaker@anu.edu.au)
+
*/
static char *version =
"3c503.c:v1.10 9/23/93 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
@@ -38,8 +48,10 @@
#include "8390.h"
#include "3c503.h"
+#ifndef MODULE
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
unsigned long *mem_startp);
+#endif
int el2_probe(struct device *dev);
int el2_pio_probe(struct device *dev);
@@ -172,10 +184,18 @@
return ENODEV;
}
- request_region(ioaddr, EL2_IO_EXTENT,"3c503");
+ request_region(ioaddr, EL2_IO_EXTENT,
+#ifdef MODULE
+ "3c503(mod)"
+#else
+ "3c503"
+#endif
+ );
+#ifndef MODULE /* modules allocate a static dev struct */
if (dev == NULL)
dev = init_etherdev(0, sizeof(struct ei_device), 0);
+#endif
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -291,7 +311,13 @@
outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR);
if (*irqp == autoirq_report(0) /* It's a good IRQ line! */
- && request_irq (dev->irq = *irqp, &ei_interrupt, 0, "3c503") == 0)
+ && request_irq (dev->irq = *irqp, &ei_interrupt, 0,
+#ifdef MODULE
+ "3c503(mod)"
+#else
+ "3c503"
+#endif
+ ) == 0)
break;
}
} while (*++irqp);
@@ -300,23 +326,37 @@
return -EAGAIN;
}
} else {
- if (request_irq(dev->irq, &ei_interrupt, 0, "3c503")) {
+ if (request_irq(dev->irq, &ei_interrupt, 0,
+#ifdef MODULE
+ "3c503(mod)"
+#else
+ "3c503"
+#endif
+ )){
return -EAGAIN;
}
}
+
el2_init_card(dev);
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
return ei_open(dev);
}
static int
el2_close(struct device *dev)
{
- free_irq(dev->irq);
- dev->irq = ei_status.saved_irq;
- irq2dev_map[dev->irq] = NULL;
+ ei_close(dev); /* generic 8390 shutdown */
outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */
- NS8390_init(dev, 0);
+ /* If we could map out anything else, here would be the place... */
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return 0;
}
@@ -458,6 +498,41 @@
outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
return 0;
}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_el2 = {
+ " " /*"3c503"*/, /* name field */
+ 0, 0, 0, 0, /* rmem and mem */
+ 0, 0, /* i/o and irq */
+ 0, 0, 0, /* start, tbusy, irq flags */
+ NULL, /* next device */
+ el2_probe}; /* probe function */
+
+int
+init_module(void)
+{
+ if (register_netdev(&dev_el2) != 0)
+ return -EIO;
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ unregister_netdev(&dev_el2);
+
+ /* Free up the private structure, or leak memory :-) */
+ kfree_s(dev_el2.priv,sizeof(struct ei_device));
+ dev_el2.priv=NULL; /* gets re-allocated by ethdev_init() */
+
+ /* If we don't do this, we can't re-insmod it later. */
+ release_region(dev_el2.base_addr, EL2_IO_EXTENT);
+
+}
+#endif /* MODULE */
+
/*
* Local variables:
diff -ur linux-83/drivers/net/3c509.c linux/drivers/net/3c509.c
--- linux-83/drivers/net/3c509.c Thu Jan 19 20:50:47 1995
+++ linux/drivers/net/3c509.c Thu Jan 19 22:20:41 1995
@@ -63,6 +63,7 @@
#define EL3_CMD 0x0e
#define EL3_STATUS 0x0e
#define ID_PORT 0x100
+#define EL3_IO_EXTENT 0x10
#define EEPROM_READ 0x80
#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
@@ -224,7 +225,13 @@
dev->base_addr = ioaddr;
dev->irq = irq;
dev->if_port = if_port;
- request_region(dev->base_addr, 16,"3c509");
+ request_region(dev->base_addr, EL3_IO_EXTENT,
+#ifdef MODULE
+ "3c509(mod)"
+#else
+ "3c509"
+#endif
+ );
{
char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
@@ -306,7 +313,13 @@
outw(RxReset, ioaddr + EL3_CMD);
outw(SetReadZero | 0x00, ioaddr + EL3_CMD);
- if (request_irq(dev->irq, &el3_interrupt, 0, "3c509")) {
+ if (request_irq(dev->irq, &el3_interrupt, 0,
+#ifdef MODULE
+ "3c509(mod)"
+#else
+ "3c509"
+#endif
+ )) {
return -EAGAIN;
}
@@ -708,14 +721,11 @@
void
cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("3c509: device busy, remove delayed\n");
- else
- {
- unregister_netdev(&dev_3c509);
- kfree_s(dev_3c509.priv,sizeof(struct el3_private));
- dev_3c509.priv=NULL;
- }
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ unregister_netdev(&dev_3c509);
+ kfree_s(dev_3c509.priv,sizeof(struct el3_private));
+ dev_3c509.priv=NULL;
+ release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
}
#endif /* MODULE */
diff -ur linux-83/drivers/net/8390.c linux/drivers/net/8390.c
--- linux-83/drivers/net/8390.c Thu Jan 19 20:50:48 1995
+++ linux/drivers/net/8390.c Thu Jan 19 22:20:41 1995
@@ -27,6 +27,11 @@
Sources:
The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
+ Change Log:
+ 17/01/95 Added ei_close() and made it the default for dev->stop.
+ Paul Gortmaker (Paul.Gortmaker@anu.edu.au)
+
*/
#include <linux/kernel.h>
@@ -119,6 +124,24 @@
return 0;
}
+/* This undoes everything that ei_open does */
+
+int ei_close(struct device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+ ei_local->irqlock = 1;
+ dev->start = 0;
+ free_irq(dev->irq);
+ dev->irq = ei_local->saved_irq;
+ irq2dev_map[dev->irq] = NULL;
+ NS8390_init(dev,0);
+ return 0;
+}
+
static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
int e8390_base = dev->base_addr;
@@ -589,7 +612,8 @@
/* The open call may be overridden by the card-specific code. */
if (dev->open == NULL)
dev->open = &ei_open;
- /* We should have a dev->stop entry also. */
+ if (dev->stop == NULL)
+ dev->stop = &ei_close;
dev->hard_start_xmit = &ei_start_xmit;
dev->get_stats = get_stats;
#ifdef HAVE_MULTICAST
diff -ur linux-83/drivers/net/8390.h linux/drivers/net/8390.h
--- linux-83/drivers/net/8390.h Thu Jan 19 20:50:48 1995
+++ linux/drivers/net/8390.h Thu Jan 19 22:20:41 1995
@@ -24,6 +24,7 @@
extern int ethdev_init(struct device *dev);
extern void NS8390_init(struct device *dev, int startp);
extern int ei_open(struct device *dev);
+extern int ei_close(struct device *dev);
extern void ei_interrupt(int irq, struct pt_regs *regs);
#ifndef HAVE_AUTOIRQ
diff -ur linux-83/drivers/net/MODULES linux/drivers/net/MODULES
--- linux-83/drivers/net/MODULES Thu Jan 19 20:50:10 1995
+++ linux/drivers/net/MODULES Thu Jan 19 22:20:41 1995
@@ -2,6 +2,7 @@
3c509.o \
de600.o \
de620.o \
+ 3c503.o \
3c501.o \
apricot.o \
eexpress.o \
@@ -11,4 +12,5 @@
slhc.o \
dummy.o \
ewrk3.o \
- depca.o
+ depca.o \
+ wd.o
diff -ur linux-83/drivers/net/wd.c linux/drivers/net/wd.c
--- linux-83/drivers/net/wd.c Thu Jan 19 20:50:22 1995
+++ linux/drivers/net/wd.c Fri Jan 20 00:15:30 1995
@@ -15,11 +15,22 @@
This is a driver for WD8003 and WD8013 "compatible" ethercards.
Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
+
+ Change Log:
+ 17/01/95 Module support + use ei_close() from 8390.c,
+ and we don't snarf the IRQ until wd_open().
+ Paul Gortmaker (Paul.Gortmaker@anu.edu.au)
+
*/
static char *version =
"wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
@@ -29,8 +40,11 @@
#include <linux/netdevice.h>
#include "8390.h"
+
+#ifndef MODULE
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
- unsigned long *mem_startp);
+ unsigned long *mem_startp);
+#endif
/* A zero-terminated list of I/O addresses to be probed. */
static unsigned int wd_portlist[] =
@@ -93,7 +107,7 @@
return 0;
}
- return ENODEV;
+ return -ENODEV;
}
#endif
@@ -110,10 +124,12 @@
if (inb(ioaddr + 8) == 0xff /* Extra check to avoid soundcard. */
|| inb(ioaddr + 9) == 0xff
|| (checksum & 0xff) != 0xFF)
- return ENODEV;
+ return -ENODEV;
+#ifndef MODULE /* modules allocate a static dev struct */
if (dev == NULL)
dev = init_etherdev(0, sizeof(struct ei_device), 0);
+#endif
printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
for (i = 0; i < 6; i++)
@@ -227,15 +243,15 @@
} else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */
dev->irq = 9;
- /* Snarf the interrupt now. There's no point in waiting since we cannot
- share and the board will usually be enabled. */
- if (request_irq(dev->irq, ei_interrupt, 0, "wd")) {
- printk (" unable to get IRQ %d.\n", dev->irq);
- return EAGAIN;
- }
-
/* OK, were are certain this is going to work. Setup the device. */
- request_region(ioaddr, WD_IO_EXTENT,"wd");
+ request_region(ioaddr, WD_IO_EXTENT,
+#ifdef MODULE
+ "wd(mod)"
+#else
+ "wd"
+#endif
+ );
+
ethdev_init(dev);
ei_status.name = model_name;
@@ -257,24 +273,36 @@
ei_status.reset_8390 = &wd_reset_8390;
ei_status.block_input = &wd_block_input;
ei_status.block_output = &wd_block_output;
+ ei_status.saved_irq = dev->irq;
dev->open = &wd_open;
dev->stop = &wd_close_card;
NS8390_init(dev, 0);
-#if 1
- /* Enable interrupt generation on softconfig cards -- M.U */
- /* .. but possibly potentially unsafe - Donald */
- if (inb(ioaddr+14) & 0x20)
- outb(inb(ioaddr+4)|0x80, ioaddr+4);
-#endif
-
return 0;
}
static int
wd_open(struct device *dev)
{
- int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+ int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+
+ if (request_irq(dev->irq, ei_interrupt, 0,
+#ifdef MODULE
+ "wd(mod)"
+#else
+ "wd"
+#endif
+ )) {
+ printk ("%s unable to get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+
+#if 1
+ /* Enable interrupt generation on softconfig cards -- M.U */
+ /* .. but possibly potentially unsafe - Donald */
+ if (inb(ioaddr+14) & 0x20)
+ outb(inb(ioaddr+4)|0x80, ioaddr+4);
+#endif
/* Map in the shared memory. Always set register 0 last to remain
compatible with very old boards. */
@@ -285,6 +313,10 @@
outb(ei_status.reg5, ioaddr+WD_CMDREG5);
outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
return ei_open(dev);
}
@@ -365,9 +397,8 @@
{
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
- if (ei_debug > 1)
- printk("%s: Shutting down ethercard.\n", dev->name);
- NS8390_init(dev, 0);
+ /* This handles the work, as it is the same for most 8390 cards. */
+ ei_close(dev);
/* Change from 16-bit to 8-bit shared memory so reboot works. */
outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
@@ -375,10 +406,56 @@
/* And disable the shared memory. */
outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
+#if 1
+ /* Disable interrupt generation on EEPROM cards. */
+ if (inb(wd_cmdreg+14) & 0x20)
+ outb(inb(wd_cmdreg+4)&0x7f, wd_cmdreg+4);
+#endif
+
+ /* If we could map out anything else, here would be the place... */
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
return 0;
}
-
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_wd = {
+ " " /*"WD80x3"*/, /* name field */
+ 0, 0, 0, 0, /* rmem and mem */
+ 0, 0, /* i/o and irq */
+ 0, 0, 0, /* start, tbusy, irq flags */
+ NULL, /* next device */
+ wd_probe}; /* probe function */
+
+int
+init_module(void)
+{
+ if (register_netdev(&dev_wd) != 0)
+ return -EIO;
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ unregister_netdev(&dev_wd);
+
+ /* Free up the private structure, or leak memory :-) */
+ kfree_s(dev_wd.priv,sizeof(struct ei_device));
+ dev_wd.priv=NULL; /* gets re-allocated by ethdev_init() */
+
+ /* Un-register i/o ports in the kernel's table */
+ release_region(dev_wd.base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
+}
+#endif /* MODULE */
+
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c wd.c"
diff -ur linux-83/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-83/kernel/ksyms.c Thu Jan 19 20:50:53 1995
+++ linux/kernel/ksyms.c Thu Jan 19 22:20:42 1995
@@ -261,6 +261,8 @@
X(register_netdev),
X(unregister_netdev),
X(ether_setup),
+ X(autoirq_setup),
+ X(autoirq_report),
X(alloc_skb),
X(kfree_skb),
X(dev_kfree_skb),
diff -ur linux-83/kernel/module.c linux/kernel/module.c
--- linux-83/kernel/module.c Thu Jan 19 20:50:17 1995
+++ linux/kernel/module.c Thu Jan 19 22:20:42 1995
@@ -533,8 +533,10 @@
q = ref->module->name;
while (*q)
*p++ = *q++;
- if (ref->next)
+ if (ref->next) {
+ *p++ = ',';
*p++ = ' ';
+ }
}
*p++ = ']';
}