[500] in linux-net channel archive

home help back first fref pref prev next nref lref last post

Modularised WD80x3 driver (patch against 1.2.10)

daemon@ATHENA.MIT.EDU (Stefan Kuehnel)
Wed Jun 14 22:56:53 1995

Date: Wed, 14 Jun 1995 13:47:06 +0200 (MET DST)
From: Stefan Kuehnel <stefan@idt.unit.no>
To: linux-net@vger.rutgers.edu
In-Reply-To: <199506140957.FAA17154@vger.rutgers.edu>

Hi,

I just converted the WD80x3 driver so that it can be used as a module.
I don't know if this is the right way to do it, but as I've seen some
patches in this group (and it is a rather short patch), I post it
here.

It's my first try at Linux kernel/driver programming, so any comments
are very welcome.  Most ideas for modularisation are stolen from the
very good drivers of David C. Davies (depca.c, de4x5.c). I haven't
tested it for very long, but I think the new bugs are hidden rather
good :-).

BTW, is the #ifdef HAVE_DEVLIST still sensible?  I would have removed
this stuff, but I wasn't sure.  Also I'd like to move the request_irq
stuff from wd_probe1 to wd_open, but as it was my first try....

Let the flames come in :-).

Stefan

PS: I'll leave this evening for 1 week/10 days, so I can answer any mail 
    only after that.

-----------------------------------------------------------------------
Stefan Kuehnel, Herman Krags vei 1-43, N-7035 Trondheim, Norway
phone:  home: +47/73889754, office: +47/73591446
email: stefan@idt.unit.no, un06@rz.uni-karlsruhe.de, kuehnel@ira.uka.de

--- linux-1.2.10/drivers/net/Makefile	Tue Apr 25 06:27:16 1995
+++ linux/drivers/net/Makefile	Tue Jun 13 21:59:29 1995
@@ -33,6 +33,8 @@
 ifdef CONFIG_WD80x3
 NETDRV_OBJS := $(NETDRV_OBJS) wd.o
 CONFIG_8390 = CONFIG_8390
+else
+MODULES := $(MODULES) wd.o
 endif
 wd.o:	wd.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
--- linux-1.2.10/drivers/net/wd.c	Fri Apr 28 15:56:53 1995
+++ linux/drivers/net/wd.c	Wed Jun 14 02:16:55 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.
+
+	Modularised 06/95 Stefan Kuehnel (stefan@idt.unit.no)
 */
 
 static char *version =
 	"wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif /* MODULE */
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -29,12 +40,6 @@
 
 #include <linux/netdevice.h>
 #include "8390.h"
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int wd_portlist[] =
-{0x300, 0x280, 0x380, 0x240, 0};
 
 int wd_probe(struct device *dev);
 int wd_probe1(struct device *dev, int ioaddr);
@@ -47,6 +52,18 @@
 							const unsigned char *buf, const start_page);
 static int wd_close_card(struct device *dev);
 
+#ifdef MODULE
+int  init_module(void);
+void cleanup_module(void);
+
+#else
+
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int wd_portlist[] =
+{0x300, 0x280, 0x380, 0x240, 0};
+
+#endif /* MODULE */
+
 
 #define WD_START_PG		0x00	/* First page of TX buffer */
 #define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
@@ -77,25 +94,36 @@
 
 int wd_probe(struct device *dev)
 {
-	int i;
 	int base_addr = dev ? dev->base_addr : 0;
+	int status = -ENODEV;
+
+	if (base_addr > 0x1ff) {		/* Check a single specified location. */
+		status = wd_probe1(dev, base_addr);
+	} else if (base_addr != 0) {	/* Don't probe at all. */
+		status = -ENXIO;
+
+    } else { /* base_addr == 0 => auto_probe */
+#ifdef MODULE
+		printk("Autoprobing is not supported when loading a module based driver.\n");
+		status = -EIO;
+#else
+		int i;
 
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return wd_probe1(dev, base_addr);
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return ENXIO;
-
-	for (i = 0; wd_portlist[i]; i++) {
-		int ioaddr = wd_portlist[i];
-		if (check_region(ioaddr, WD_IO_EXTENT))
-			continue;
-		if (wd_probe1(dev, ioaddr) == 0)
-			return 0;
+		for (i = 0; wd_portlist[i]; i++) {
+			int ioaddr = wd_portlist[i];
+			if (check_region(ioaddr, WD_IO_EXTENT))
+			  continue;
+			if (wd_probe1(dev, ioaddr) == 0) {
+				status = 0;
+				break;
+			}
+		}
+#endif /* MODULE */
 	}
 
-	return ENODEV;
+	return status;
 }
-#endif
+#endif /* HAVE_DEVLIST */
 
 int wd_probe1(struct device *dev, int ioaddr)
 {
@@ -110,10 +138,7 @@
 	if (inb(ioaddr + 8) == 0xff 	/* Extra check to avoid soundcard. */
 		|| inb(ioaddr + 9) == 0xff
 		|| (checksum & 0xff) != 0xFF)
-		return ENODEV;
-
-	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct ei_device), 0);
+		return -ENODEV;
 
 	printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
 	for (i = 0; i < 6; i++)
@@ -203,6 +228,7 @@
 		int reg1 = inb(ioaddr+1);
 		int reg4 = inb(ioaddr+4);
 		if (ancient || reg1 == 0xff) {	/* Ack!! No way to read the IRQ! */
+#ifndef MODULE
 			short nic_addr = ioaddr+WD_NIC_OFFSET;
 
 			/* We have an old-style ethercard that doesn't report its IRQ
@@ -220,6 +246,7 @@
 
 			if (ei_debug > 2)
 				printk(" autoirq is %d", dev->irq);
+#endif /* MODULE */
 			if (dev->irq < 2)
 				dev->irq = word16 ? 10 : 5;
 		} else
@@ -227,15 +254,35 @@
 	} else if (dev->irq == 2)		/* Fixup bogosity: IRQ2 is really IRQ9 */
 		dev->irq = 9;
 
+	/* Allocate priv memory here, so that it can safely free'd */
+	/* Otherwise it would be kmalloc'd in ethdev_init() */
+	/* This is only here because 8390.c is broken. If it allocates */
+	/* the memory, it should free it cleanup_module() */
+	/* (I know it's a small structure but still it can't hurt) */
+	dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+    if (dev->priv) {
+		struct ei_device *ei_local;
+
+	    memset(dev->priv, 0, sizeof(struct ei_device));
+		ei_local = (struct ei_device *)dev->priv;
+#ifndef NO_PINGPONG
+		ei_local->pingpong = 1;
+#endif
+	} else {
+        printk(" insufficient memory\n");
+		return -EAGAIN;
+    }
+
 	/* 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")) {
+	if (request_irq(dev->irq, ei_interrupt, 0, dev->name)) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
-		return EAGAIN;
+		kfree_s(dev->priv, sizeof(struct ei_device));
+		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, dev->name);
 	ethdev_init(dev);
 
 	ei_status.name = model_name;
@@ -275,6 +322,7 @@
 wd_open(struct device *dev)
 {
   int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+  int status;
 
   /* Map in the shared memory. Always set register 0 last to remain
 	 compatible with very old boards. */
@@ -285,7 +333,12 @@
 	  outb(ei_status.reg5, ioaddr+WD_CMDREG5);
   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 
-  return ei_open(dev);
+  if ((status = ei_open(dev)))
+	return status;
+
+  MOD_INC_USE_COUNT;
+
+  return 0;
 }
 
 static void
@@ -376,8 +429,52 @@
 	/* And disable the shared memory. */
 	outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 
+	MOD_DEC_USE_COUNT;
+
 	return 0;
 }
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device thisCard = {
+  "        ",  /* device name inserted by /linux/drivers/net/net_init.c */
+  0, 0, 0, 0,
+  0x280, 5,   /* I/O address, IRQ */
+  0, 0, 0, NULL, wd_probe };
+
+/*
+ *	This is a tweak to keep the insmod program happy. It can only
+ *	set int values with var=value so we split these out.
+ */
+ 
+int irq=5;	    /* EDIT THESE LINE FOR YOUR CONFIGURATION */
+int io=0x280;   /* Or use the irq= io= options to insmod */
+
+int
+init_module(void)
+{
+  thisCard.irq=irq;
+  thisCard.base_addr=io;
+  if (register_netdev(&thisCard) != 0)
+    return -EIO;
+  return 0;
+}
+
+void
+cleanup_module(void)
+{
+    int ioaddr = thisCard.base_addr - WD_NIC_OFFSET;
+
+    free_irq(thisCard.irq);
+    release_region(ioaddr, WD_IO_EXTENT);
+
+    kfree_s(thisCard.priv, sizeof(struct ei_device));
+    thisCard.priv = NULL;
+
+    unregister_netdev(&thisCard);
+}
+#endif /* MODULE */
+
 
 
 /*

home help back first fref pref prev next nref lref last post