Commit 80c883a4 authored by Stephen Hemminger's avatar Stephen Hemminger

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

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
parent 3bcaef6a
...@@ -58,7 +58,7 @@ extern int eth16i_probe(struct net_device *); ...@@ -58,7 +58,7 @@ extern int eth16i_probe(struct net_device *);
extern int i82596_probe(struct net_device *); extern int i82596_probe(struct net_device *);
extern int ewrk3_probe(struct net_device *); extern int ewrk3_probe(struct net_device *);
extern int el1_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 *arlan_probe(int unit);
extern struct net_device *el16_probe(int unit); extern struct net_device *el16_probe(int unit);
extern int elmc_probe(struct net_device *); extern int elmc_probe(struct net_device *);
...@@ -264,14 +264,14 @@ static struct devprobe isa_probes[] __initdata = { ...@@ -264,14 +264,14 @@ static struct devprobe isa_probes[] __initdata = {
#endif #endif
#ifdef CONFIG_EL1 /* 3c501 */ #ifdef CONFIG_EL1 /* 3c501 */
{el1_probe, 0}, {el1_probe, 0},
#endif
#ifdef CONFIG_WAVELAN /* WaveLAN */
{wavelan_probe, 0},
#endif #endif
{NULL, 0}, {NULL, 0},
}; };
static struct devprobe2 isa_probes2[] __initdata = { static struct devprobe2 isa_probes2[] __initdata = {
#ifdef CONFIG_WAVELAN /* WaveLAN */
{wavelan_probe, 0},
#endif
#ifdef CONFIG_ARLAN /* Aironet */ #ifdef CONFIG_ARLAN /* Aironet */
{arlan_probe, 0}, {arlan_probe, 0},
#endif #endif
......
...@@ -4091,12 +4091,24 @@ static int wavelan_close(device * dev) ...@@ -4091,12 +4091,24 @@ static int wavelan_close(device * dev)
* device structure * device structure
* (called by wavelan_probe() and via init_module()). * (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; u8 irq_mask;
int irq; int irq;
net_local *lp; 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 #ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n",
...@@ -4136,25 +4148,18 @@ static int __init wavelan_config(device * dev) ...@@ -4136,25 +4148,18 @@ static int __init wavelan_config(device * dev)
"%s: wavelan_config(): could not wavelan_map_irq(%d).\n", "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
dev->name, irq_mask); dev->name, irq_mask);
#endif #endif
return -EAGAIN; err = -EAGAIN;
goto out;
} }
dev->irq = irq; dev->irq = irq;
if (!request_region(ioaddr, sizeof(ha_t), "wavelan"))
return -EBUSY;
dev->mem_start = 0x0000; dev->mem_start = 0x0000;
dev->mem_end = 0x0000; dev->mem_end = 0x0000;
dev->if_port = 0; dev->if_port = 0;
/* Initialize device structures */ /* Initialize device structures */
dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); memset(dev->priv, 0, sizeof(net_local));
if (dev->priv == NULL) {
release_region(ioaddr, sizeof(ha_t));
return -ENOMEM;
}
memset(dev->priv, 0x00, sizeof(net_local));
lp = (net_local *) dev->priv; lp = (net_local *) dev->priv;
/* Back link to the device structure. */ /* Back link to the device structure. */
...@@ -4172,12 +4177,6 @@ static int __init wavelan_config(device * dev) ...@@ -4172,12 +4177,6 @@ static int __init wavelan_config(device * dev)
/* Init spinlock */ /* Init spinlock */
spin_lock_init(&lp->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); SET_MODULE_OWNER(dev);
dev->open = wavelan_open; dev->open = wavelan_open;
dev->stop = wavelan_close; dev->stop = wavelan_close;
...@@ -4204,6 +4203,9 @@ static int __init wavelan_config(device * dev) ...@@ -4204,6 +4203,9 @@ static int __init wavelan_config(device * dev)
printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
#endif #endif
return 0; return 0;
out:
release_region(ioaddr, sizeof(ha_t));
return err;
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -4214,19 +4216,13 @@ static int __init wavelan_config(device * dev) ...@@ -4214,19 +4216,13 @@ static int __init wavelan_config(device * dev)
* We follow the example in drivers/net/ne.c. * We follow the example in drivers/net/ne.c.
* (called in "Space.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; short base_addr;
mac_addr mac; /* MAC address (check existence of WaveLAN) */ int def_irq;
int i; int i;
int r; int r = 0;
#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
#ifdef STRUCT_CHECK #ifdef STRUCT_CHECK
if (wv_struct_check() != (char *) NULL) { if (wv_struct_check() != (char *) NULL) {
...@@ -4237,8 +4233,20 @@ int __init wavelan_probe(device * dev) ...@@ -4237,8 +4233,20 @@ int __init wavelan_probe(device * dev)
} }
#endif /* STRUCT_CHECK */ #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; 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. */ /* Don't probe at all. */
if (base_addr < 0) { if (base_addr < 0) {
...@@ -4247,16 +4255,9 @@ int __init wavelan_probe(device * dev) ...@@ -4247,16 +4255,9 @@ int __init wavelan_probe(device * dev)
"%s: wavelan_probe(): invalid base address\n", "%s: wavelan_probe(): invalid base address\n",
dev->name); dev->name);
#endif #endif
return -ENXIO; r = -ENXIO;
} } else if (base_addr > 0x100) { /* Check a single specified location. */
r = wavelan_config(dev, base_addr);
/* 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);
}
#ifdef DEBUG_CONFIG_INFO #ifdef DEBUG_CONFIG_INFO
if (r != 0) if (r != 0)
printk(KERN_DEBUG printk(KERN_DEBUG
...@@ -4267,35 +4268,33 @@ int __init wavelan_probe(device * dev) ...@@ -4267,35 +4268,33 @@ int __init wavelan_probe(device * dev)
#ifdef DEBUG_CALLBACK_TRACE #ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
#endif #endif
return r; } else { /* Scan all possible addresses of the WaveLAN hardware. */
} for (i = 0; i < NELS(iobase); i++) {
dev->irq = def_irq;
/* Scan all possible addresses of the WaveLAN hardware. */ if (wavelan_config(dev, iobase[i]) == 0) {
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) {
#ifdef DEBUG_CALLBACK_TRACE #ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: <-wavelan_probe()\n", "%s: <-wavelan_probe()\n",
dev->name); dev->name);
#endif #endif
return 0; break;
} }
} }
if (i == NELS(iobase))
r = -ENODEV;
} }
if (r)
/* We may have touched base_addr. Another driver may not like it. */ goto out;
dev->base_addr = base_addr; r = register_netdev(dev);
if (r)
#ifdef DEBUG_CONFIG_INFO goto out1;
printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", return dev;
dev->name); out1:
#endif release_region(dev->base_addr, sizeof(ha_t));
wavelan_list = wavelan_list->next;
return -ENODEV; out:
kfree(dev);
return ERR_PTR(r);
} }
/****************************** MODULE ******************************/ /****************************** MODULE ******************************/
...@@ -4311,7 +4310,6 @@ int __init wavelan_probe(device * dev) ...@@ -4311,7 +4310,6 @@ int __init wavelan_probe(device * dev)
*/ */
int init_module(void) int init_module(void)
{ {
mac_addr mac; /* MAC address (check WaveLAN existence) */
int ret = -EIO; /* Return error if no cards found */ int ret = -EIO; /* Return error if no cards found */
int i; int i;
...@@ -4337,38 +4335,28 @@ int init_module(void) ...@@ -4337,38 +4335,28 @@ int init_module(void)
/* Loop on all possible base addresses. */ /* Loop on all possible base addresses. */
i = -1; i = -1;
while ((io[++i] != 0) && (i < NELS(io))) { while ((io[++i] != 0) && (i < NELS(io))) {
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];
/* Check if there is something at this base address. */ /* Check if there is something at this base address. */
if (wv_check_ioaddr(io[i], mac) == 0) { if (wavelan_config(dev, io[i]) == 0) {
device *dev;
/* 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. */
if (register_netdev(dev) != 0) { if (register_netdev(dev) != 0) {
/* Deallocate everything. */ release_region(dev->base_addr, sizeof(ha_t));
/* Note: if dev->priv is mallocated, there is no way to fail. */ wavelan_list = wavelan_list->next;
kfree(dev);
} else { } else {
/* If at least one device OK, we do not fail */
ret = 0; ret = 0;
continue;
} }
} /* if there is something at the address */ }
} /* Loop on all addresses. */ kfree(dev);
}
#ifdef DEBUG_CONFIG_ERROR #ifdef DEBUG_CONFIG_ERROR
if (wavelan_list == (net_local *) NULL) if (!wavelan_list)
printk(KERN_WARNING printk(KERN_WARNING
"WaveLAN init_module(): no device found\n"); "WaveLAN init_module(): no device found\n");
#endif #endif
...@@ -4390,7 +4378,7 @@ void cleanup_module(void) ...@@ -4390,7 +4378,7 @@ void cleanup_module(void)
#endif #endif
/* Loop on all devices and release them. */ /* Loop on all devices and release them. */
while (wavelan_list != (net_local *) NULL) { while (wavelan_list) {
device *dev = wavelan_list->dev; device *dev = wavelan_list->dev;
#ifdef DEBUG_CONFIG_INFO #ifdef DEBUG_CONFIG_INFO
...@@ -4398,18 +4386,11 @@ void cleanup_module(void) ...@@ -4398,18 +4386,11 @@ void cleanup_module(void)
"%s: cleanup_module(): removing device at 0x%x\n", "%s: cleanup_module(): removing device at 0x%x\n",
dev->name, (unsigned int) dev); dev->name, (unsigned int) dev);
#endif #endif
/* Release the ioport region. */
release_region(dev->base_addr, sizeof(ha_t));
/* Definitely remove the device. */
unregister_netdev(dev); unregister_netdev(dev);
/* Unlink the device. */ release_region(dev->base_addr, sizeof(ha_t));
wavelan_list = wavelan_list->next; wavelan_list = wavelan_list->next;
/* Free pieces. */
kfree(dev->priv);
free_netdev(dev); free_netdev(dev);
} }
......
...@@ -656,9 +656,8 @@ static void ...@@ -656,9 +656,8 @@ static void
static int static int
wavelan_open(device *), /* Open the device. */ wavelan_open(device *), /* Open the device. */
wavelan_close(device *), /* Close the device. */ wavelan_close(device *), /* Close the device. */
wavelan_config(device *); /* Configure one device. */ wavelan_config(device *, unsigned short);/* Configure one device. */
extern int extern struct net_device *wavelan_probe(int unit); /* See Space.c. */
wavelan_probe(device *); /* See Space.c. */
/**************************** VARIABLES ****************************/ /**************************** VARIABLES ****************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment