DORMANTno replies

[PATCH] (10/12) Probe2 -- wavelan

From: Stephen Hemminger <hidden>
Date: 2003-10-14 22:34:10

Original by Al Viro (NE21-wavelan)
	* switched wavelan to dynamic allocation
	* wavelan: embedded ->priv
	* wavelan: fixed clobbering on autoprobe
	* wavelan: fixed IO before request_region()
	* wavelan: fixed resource leaks on failure exits
	* wavelan: fixed order of freeing bugs
Updated to apply agains jgarzik/net-drivers-2.5-exp


diff -urN 08-arlan/drivers/net/Space.c 09-wavelan/drivers/net/Space.c
--- 08-arlan/drivers/net/Space.c	2003-09-29 16:23:44.000000000 -0700
+++ 09-wavelan/drivers/net/Space.c	2003-09-29 16:30:02.000000000 -0700
@@ -58,7 +58,7 @@
 extern int i82596_probe(struct net_device *);
 extern int ewrk3_probe(struct net_device *);
 extern int el1_probe(struct net_device *);
-extern int wavelan_probe(struct net_device *);
+extern struct net_device *wavelan_probe(int unit);
 extern struct net_device *arlan_probe(int unit);
 extern struct net_device *el16_probe(int unit);
 extern int elmc_probe(struct net_device *);
@@ -269,13 +269,13 @@
 #ifdef CONFIG_EL1		/* 3c501 */
 	{el1_probe, 0},
 #endif
-#ifdef CONFIG_WAVELAN		/* WaveLAN */
-	{wavelan_probe, 0},
-#endif
 	{NULL, 0},
 };
 
 static struct devprobe2 isa_probes2[] __initdata = {
+#ifdef CONFIG_WAVELAN		/* WaveLAN */
+	{wavelan_probe, 0},
+#endif
 #ifdef CONFIG_ARLAN		/* Aironet */
 	{arlan_probe, 0},
 #endif
diff -urN 08-arlan/drivers/net/wireless/wavelan.c 09-wavelan/drivers/net/wireless/wavelan.c
--- 08-arlan/drivers/net/wireless/wavelan.c	2003-09-27 17:50:59.000000000 -0700
+++ 09-wavelan/drivers/net/wireless/wavelan.c	2003-09-29 16:30:09.000000000 -0700
@@ -4091,12 +4091,24 @@
  * device structure
  * (called by wavelan_probe() and via init_module()).
  */
-static int __init wavelan_config(device * dev)
+static int __init wavelan_config(device *dev, unsigned short ioaddr)
 {
-	unsigned long ioaddr = dev->base_addr;
 	u8 irq_mask;
 	int irq;
 	net_local *lp;
+	mac_addr mac;
+	int err;
+
+	if (!request_region(ioaddr, sizeof(ha_t), "wavelan"))
+		return -EADDRINUSE;
+
+	err = wv_check_ioaddr(ioaddr, mac);
+	if (err)
+		goto out;
+
+	memcpy(dev->dev_addr, mac, 6);
+
+	dev->base_addr = ioaddr;
 
 #ifdef DEBUG_CALLBACK_TRACE
 	printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n",
@@ -4136,25 +4148,18 @@
 		       "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
 		       dev->name, irq_mask);
 #endif
-		return -EAGAIN;
+		err = -EAGAIN;
+		goto out;
 	}
 
 	dev->irq = irq;
 
-	if (!request_region(ioaddr, sizeof(ha_t), "wavelan"))
-		return -EBUSY;
-
 	dev->mem_start = 0x0000;
 	dev->mem_end = 0x0000;
 	dev->if_port = 0;
 
 	/* Initialize device structures */
-	dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
-	if (dev->priv == NULL) {
-		release_region(ioaddr, sizeof(ha_t));
-		return -ENOMEM;
-	}
-	memset(dev->priv, 0x00, sizeof(net_local));
+	memset(dev->priv, 0, sizeof(net_local));
 	lp = (net_local *) dev->priv;
 
 	/* Back link to the device structure. */
@@ -4172,12 +4177,6 @@
 	/* Init spinlock */
 	spin_lock_init(&lp->spinlock);
 
-	/*
-	 * Fill in the fields of the device structure
-	 * with generic Ethernet values.
-	 */
-	ether_setup(dev);
-
 	SET_MODULE_OWNER(dev);
 	dev->open = wavelan_open;
 	dev->stop = wavelan_close;
@@ -4204,6 +4203,9 @@
 	printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
 #endif
 	return 0;
+out:
+	release_region(ioaddr, sizeof(ha_t));
+	return err;
 }
 
 /*------------------------------------------------------------------*/
@@ -4214,19 +4216,13 @@
  * We follow the example in drivers/net/ne.c.
  * (called in "Space.c")
  */
-int __init wavelan_probe(device * dev)
+struct net_device * __init wavelan_probe(int unit)
 {
+	struct net_device *dev;
 	short base_addr;
-	mac_addr mac;		/* MAC address (check existence of WaveLAN) */
+	int def_irq;
 	int i;
-	int r;
-
-#ifdef DEBUG_CALLBACK_TRACE
-	printk(KERN_DEBUG
-	       "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
-	       dev->name, (unsigned int) dev,
-	       (unsigned int) dev->base_addr);
-#endif
+	int r = 0;
 
 #ifdef	STRUCT_CHECK
 	if (wv_struct_check() != (char *) NULL) {
@@ -4237,8 +4233,20 @@
 	}
 #endif				/* STRUCT_CHECK */
 
-	/* Check the value of the command line parameter for base address. */
+	dev = alloc_etherdev(sizeof(net_local));
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	sprintf(dev->name, "eth%d", unit);
+	netdev_boot_setup_check(dev);
 	base_addr = dev->base_addr;
+	def_irq = dev->irq;
+
+#ifdef DEBUG_CALLBACK_TRACE
+	printk(KERN_DEBUG
+	       "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n",
+	       dev->name, dev, (unsigned int) dev->base_addr);
+#endif
 
 	/* Don't probe at all. */
 	if (base_addr < 0) {
@@ -4247,16 +4255,9 @@
 		       "%s: wavelan_probe(): invalid base address\n",
 		       dev->name);
 #endif
-		return -ENXIO;
-	}
-
-	/* Check a single specified location. */
-	if (base_addr > 0x100) {
-		/* Check if there is something at this base address */
-		if ((r = wv_check_ioaddr(base_addr, mac)) == 0) {
-			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-			r = wavelan_config(dev);
-		}
+		r = -ENXIO;
+	} else if (base_addr > 0x100) { /* Check a single specified location. */
+		r = wavelan_config(dev, base_addr);
 #ifdef DEBUG_CONFIG_INFO
 		if (r != 0)
 			printk(KERN_DEBUG
@@ -4267,35 +4268,33 @@
 #ifdef DEBUG_CALLBACK_TRACE
 		printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
 #endif
-		return r;
-	}
-
-	/* Scan all possible addresses of the WaveLAN hardware. */
-	for (i = 0; i < NELS(iobase); i++) {
-		/* Check whether there is something at this base address. */
-		if (wv_check_ioaddr(iobase[i], mac) == 0) {
-			dev->base_addr = iobase[i];	/* Copy base address. */
-			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-			if (wavelan_config(dev) == 0) {
+	} else { /* Scan all possible addresses of the WaveLAN hardware. */
+		for (i = 0; i < NELS(iobase); i++) {
+			dev->irq = def_irq;
+			if (wavelan_config(dev, iobase[i]) == 0) {
 #ifdef DEBUG_CALLBACK_TRACE
 				printk(KERN_DEBUG
 				       "%s: <-wavelan_probe()\n",
 				       dev->name);
 #endif
-				return 0;
+				break;
 			}
 		}
+		if (i == NELS(iobase))
+			r = -ENODEV;
 	}
-
-	/* We may have touched base_addr.  Another driver may not like it. */
-	dev->base_addr = base_addr;
-
-#ifdef DEBUG_CONFIG_INFO
-	printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
-	       dev->name);
-#endif
-
-	return -ENODEV;
+	if (r) 
+		goto out;
+	r = register_netdev(dev);
+	if (r)
+		goto out1;
+	return dev;
+out1:
+	release_region(dev->base_addr, sizeof(ha_t));
+	wavelan_list = wavelan_list->next;
+out:
+	kfree(dev);
+	return ERR_PTR(r);
 }
 
 /****************************** MODULE ******************************/
@@ -4311,7 +4310,6 @@
  */
 int init_module(void)
 {
-	mac_addr mac;		/* MAC address (check WaveLAN existence) */
 	int ret = -EIO;		/* Return error if no cards found */
 	int i;
 
@@ -4337,38 +4335,28 @@
 	/* Loop on all possible base addresses. */
 	i = -1;
 	while ((io[++i] != 0) && (i < NELS(io))) {
-		/* Check if there is something at this base address. */
-		if (wv_check_ioaddr(io[i], mac) == 0) {
-			device *dev;
+		struct net_device *dev = alloc_etherdev(sizeof(net_local));
+		if (!dev)
+			break;
+		memcpy(dev->name, name[i], IFNAMSIZ);	/* Copy name */
+		dev->base_addr = io[i];
+		dev->irq = irq[i];
 
-			/* Create device and set basic arguments. */
-			dev =
-			    kmalloc(sizeof(struct net_device), GFP_KERNEL);
-			if (dev == NULL) {
-				ret = -ENOMEM;
-				break;
-			}
-			memset(dev, 0x00, sizeof(struct net_device));
-			memcpy(dev->name, name[i], IFNAMSIZ);	/* Copy name */
-			dev->base_addr = io[i];
-			dev->irq = irq[i];
-			dev->init = &wavelan_config;
-			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-
-			/* Try to create the device. */
+		/* Check if there is something at this base address. */
+		if (wavelan_config(dev, io[i]) == 0) {
 			if (register_netdev(dev) != 0) {
-				/* Deallocate everything. */
-				/* Note: if dev->priv is mallocated, there is no way to fail. */
-				kfree(dev);
+				release_region(dev->base_addr, sizeof(ha_t));
+				wavelan_list = wavelan_list->next;
 			} else {
-				/* If at least one device OK, we do not fail */
 				ret = 0;
+				continue;
 			}
-		}		/* if there is something at the address */
-	}			/* Loop on all addresses. */
+		}
+		kfree(dev);
+	}
 
 #ifdef DEBUG_CONFIG_ERROR
-	if (wavelan_list == (net_local *) NULL)
+	if (!wavelan_list)
 		printk(KERN_WARNING
 		       "WaveLAN init_module(): no device found\n");
 #endif
@@ -4390,7 +4378,7 @@
 #endif
 
 	/* Loop on all devices and release them. */
-	while (wavelan_list != (net_local *) NULL) {
+	while (wavelan_list) {
 		device *dev = wavelan_list->dev;
 
 #ifdef DEBUG_CONFIG_INFO
@@ -4398,18 +4386,11 @@
 		       "%s: cleanup_module(): removing device at 0x%x\n",
 		       dev->name, (unsigned int) dev);
 #endif
-
-		/* Release the ioport region. */
-		release_region(dev->base_addr, sizeof(ha_t));
-
-		/* Definitely remove the device. */
 		unregister_netdev(dev);
 
-		/* Unlink the device. */
+		release_region(dev->base_addr, sizeof(ha_t));
 		wavelan_list = wavelan_list->next;
 
-		/* Free pieces. */
-		kfree(dev->priv);
 		free_netdev(dev);
 	}
 
diff -urN 08-arlan/drivers/net/wireless/wavelan.p.h 09-wavelan/drivers/net/wireless/wavelan.p.h
--- 08-arlan/drivers/net/wireless/wavelan.p.h	2003-09-27 17:50:38.000000000 -0700
+++ 09-wavelan/drivers/net/wireless/wavelan.p.h	2003-09-29 16:30:09.000000000 -0700
@@ -656,9 +656,8 @@
 static int
 	wavelan_open(device *),		/* Open the device. */
 	wavelan_close(device *),	/* Close the device. */
-	wavelan_config(device *);	/* Configure one device. */
-extern int
-	wavelan_probe(device *);	/* See Space.c. */
+	wavelan_config(device *, unsigned short);/* Configure one device. */
+extern struct net_device *wavelan_probe(int unit);	/* See Space.c. */
 
 /**************************** VARIABLES ****************************/
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help