Commit 39def843 authored by Stephen Hemminger's avatar Stephen Hemminger

[PATCH] (5/42) fmv18

Based on viro, NE29-fmv18
	* switched fmv18x to dynamic allocation
	* fmv18x: embedded ->priv
	* fmv18x: fixed resource leaks on failure exits
	* fmv18x: fixed clobbering on autoprobe
	* fmv18x: compile fix - comment is _not_ an empty statement.  The thing
	  had been b0rken since 2.4.3-pre2, BTW...
parent 84e78fd3
...@@ -53,7 +53,7 @@ extern struct net_device *express_probe(int unit); ...@@ -53,7 +53,7 @@ extern struct net_device *express_probe(int unit);
extern struct net_device *eepro_probe(int unit); extern struct net_device *eepro_probe(int unit);
extern int at1500_probe(struct net_device *); extern int at1500_probe(struct net_device *);
extern int at1700_probe(struct net_device *); extern int at1700_probe(struct net_device *);
extern int fmv18x_probe(struct net_device *); extern struct net_device *fmv18x_probe(int unit);
extern struct net_device *eth16i_probe(int unit); extern struct net_device *eth16i_probe(int unit);
extern struct net_device *i82596_probe(int unit); extern struct net_device *i82596_probe(int unit);
extern struct net_device *ewrk3_probe(int unit); extern struct net_device *ewrk3_probe(int unit);
...@@ -243,14 +243,14 @@ static struct devprobe isa_probes[] __initdata = { ...@@ -243,14 +243,14 @@ static struct devprobe isa_probes[] __initdata = {
#endif #endif
#ifdef CONFIG_AT1700 #ifdef CONFIG_AT1700
{at1700_probe, 0}, {at1700_probe, 0},
#endif
#ifdef CONFIG_FMV18X /* Fujitsu FMV-181/182 */
{fmv18x_probe, 0},
#endif #endif
{NULL, 0}, {NULL, 0},
}; };
static struct devprobe2 isa_probes2[] __initdata = { static struct devprobe2 isa_probes2[] __initdata = {
#ifdef CONFIG_FMV18X /* Fujitsu FMV-181/182 */
{fmv18x_probe, 0},
#endif
#ifdef CONFIG_ETH16I #ifdef CONFIG_ETH16I
{eth16i_probe, 0}, /* ICL EtherTeam 16i/32 */ {eth16i_probe, 0}, /* ICL EtherTeam 16i/32 */
#endif #endif
......
...@@ -57,7 +57,7 @@ static const char version[] = ...@@ -57,7 +57,7 @@ static const char version[] =
#include <asm/io.h> #include <asm/io.h>
#include <asm/dma.h> #include <asm/dma.h>
static int fmv18x_probe_list[] __initdata = { static unsigned fmv18x_probe_list[] __initdata = {
0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
}; };
...@@ -109,8 +109,6 @@ struct net_local { ...@@ -109,8 +109,6 @@ struct net_local {
/* Index to functions, as function prototypes. */ /* Index to functions, as function prototypes. */
extern int fmv18x_probe(struct net_device *dev);
static int fmv18x_probe1(struct net_device *dev, short ioaddr); static int fmv18x_probe1(struct net_device *dev, short ioaddr);
static int net_open(struct net_device *dev); static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
...@@ -129,23 +127,50 @@ static void set_multicast_list(struct net_device *dev); ...@@ -129,23 +127,50 @@ static void set_multicast_list(struct net_device *dev);
(detachable devices only). (detachable devices only).
*/ */
int __init fmv18x_probe(struct net_device *dev) static int io = 0x220;
static int irq;
struct net_device * __init fmv18x_probe(int unit)
{ {
int i; struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
int base_addr = dev->base_addr; unsigned *port;
int err = 0;
SET_MODULE_OWNER(dev); if (!dev)
return ERR_PTR(-ENODEV);
if (base_addr > 0x1ff) /* Check a single specified location. */ if (unit >= 0) {
return fmv18x_probe1(dev, base_addr); sprintf(dev->name, "eth%d", unit);
else if (base_addr != 0) /* Don't probe at all. */ netdev_boot_setup_check(dev);
return -ENXIO; io = dev->base_addr;
irq = dev->irq;
}
for (i = 0; fmv18x_probe_list[i]; i++) SET_MODULE_OWNER(dev);
if (fmv18x_probe1(dev, fmv18x_probe_list[i]) == 0)
return 0;
return -ENODEV; if (io > 0x1ff) { /* Check a single specified location. */
err = fmv18x_probe1(dev, io);
} else if (io != 0) { /* Don't probe at all. */
err = -ENXIO;
} else {
for (port = fmv18x_probe_list; *port; port++)
if (fmv18x_probe1(dev, *port) == 0)
break;
if (!*port)
err = -ENODEV;
}
if (err)
goto out;
err = register_netdev(dev);
if (err)
goto out1;
return dev;
out1:
free_irq(dev->irq, dev);
release_region(dev->base_addr, FMV18X_IO_EXTENT);
out:
free_netdev(dev);
return ERR_PTR(err);
} }
/* The Fujitsu datasheet suggests that the NIC be probed for by checking its /* The Fujitsu datasheet suggests that the NIC be probed for by checking its
...@@ -160,7 +185,7 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) ...@@ -160,7 +185,7 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
{ {
char irqmap[4] = {3, 7, 10, 15}; char irqmap[4] = {3, 7, 10, 15};
char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
unsigned int i, irq, retval; unsigned int i, retval;
struct net_local *lp; struct net_local *lp;
/* Resetting the chip doesn't reset the ISA interface, so don't bother. /* Resetting the chip doesn't reset the ISA interface, so don't bother.
...@@ -170,6 +195,9 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) ...@@ -170,6 +195,9 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name)) if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name))
return -EBUSY; return -EBUSY;
dev->irq = irq;
dev->base_addr = ioaddr;
/* Check I/O address configuration and Fujitsu vendor code */ /* Check I/O address configuration and Fujitsu vendor code */
if (inb(ioaddr+FJ_MACADDR ) != 0x00 if (inb(ioaddr+FJ_MACADDR ) != 0x00
|| inb(ioaddr+FJ_MACADDR+1) != 0x00 || inb(ioaddr+FJ_MACADDR+1) != 0x00
...@@ -181,9 +209,8 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) ...@@ -181,9 +209,8 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
/* Check PnP mode for FMV-183/184/183A/184A. */ /* Check PnP mode for FMV-183/184/183A/184A. */
/* This PnP routine is very poor. IO and IRQ should be known. */ /* This PnP routine is very poor. IO and IRQ should be known. */
if (inb(ioaddr + FJ_STATUS1) & 0x20) { if (inb(ioaddr + FJ_STATUS1) & 0x20) {
irq = dev->irq;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (irq == irqmap_pnp[i]) if (dev->irq == irqmap_pnp[i])
break; break;
} }
if (i == 8) { if (i == 8) {
...@@ -193,22 +220,19 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) ...@@ -193,22 +220,19 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
} else { } else {
if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr) if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr)
return -ENODEV; return -ENODEV;
irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; dev->irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03];
} }
/* Snarf the interrupt vector now. */ /* Snarf the interrupt vector now. */
retval = request_irq(irq, &net_interrupt, 0, dev->name, dev); retval = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);
if (retval) { if (retval) {
printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on" printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on"
"IRQ %d.\n", ioaddr, irq); "IRQ %d.\n", ioaddr, dev->irq);
goto out; goto out;
} }
printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name, printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name,
ioaddr, irq); ioaddr, dev->irq);
dev->base_addr = ioaddr;
dev->irq = irq;
for(i = 0; i < 6; i++) { for(i = 0; i < 6; i++) {
unsigned char val = inb(ioaddr + FJ_MACADDR + i); unsigned char val = inb(ioaddr + FJ_MACADDR + i);
...@@ -279,14 +303,10 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr) ...@@ -279,14 +303,10 @@ static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
dev->watchdog_timeo = HZ/10; dev->watchdog_timeo = HZ/10;
dev->get_stats = net_get_stats; dev->get_stats = net_get_stats;
dev->set_multicast_list = set_multicast_list; dev->set_multicast_list = set_multicast_list;
/* Fill in the fields of 'dev' with ethernet-generic values. */
ether_setup(dev);
return 0; return 0;
out_irq: out_irq:
free_irq(irq, dev); free_irq(dev->irq, dev);
out: out:
release_region(ioaddr, FMV18X_IO_EXTENT); release_region(ioaddr, FMV18X_IO_EXTENT);
return retval; return retval;
...@@ -413,9 +433,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -413,9 +433,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
lp->tx_queue_len = 0; lp->tx_queue_len = 0;
dev->trans_start = jiffies; dev->trans_start = jiffies;
lp->tx_started = 1; lp->tx_started = 1;
} else if (lp->tx_queue_len < 4096 - 1502) } else if (lp->tx_queue_len >= 4096 - 1502) /* No room for a packet */
/* Yes, there is room for one more packet. */
else
netif_stop_queue(dev); netif_stop_queue(dev);
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -628,9 +646,7 @@ static void set_multicast_list(struct net_device *dev) ...@@ -628,9 +646,7 @@ static void set_multicast_list(struct net_device *dev)
} }
#ifdef MODULE #ifdef MODULE
static struct net_device dev_fmv18x; static struct net_device *dev_fmv18x;
static int io = 0x220;
static int irq;
MODULE_PARM(io, "i"); MODULE_PARM(io, "i");
MODULE_PARM(irq, "i"); MODULE_PARM(irq, "i");
...@@ -644,26 +660,19 @@ int init_module(void) ...@@ -644,26 +660,19 @@ int init_module(void)
{ {
if (io == 0) if (io == 0)
printk("fmv18x: You should not use auto-probing with insmod!\n"); printk("fmv18x: You should not use auto-probing with insmod!\n");
dev_fmv18x.base_addr = io; dev_fmv18x = fmv18x_probe(-1);
dev_fmv18x.irq = irq; if (IS_ERR(dev_fmv18x))
dev_fmv18x.init = fmv18x_probe; return PTR_ERR(dev_fmv18x);
if (register_netdev(&dev_fmv18x) != 0) {
printk("fmv18x: register_netdev() returned non-zero.\n");
return -EIO;
}
return 0; return 0;
} }
void void
cleanup_module(void) cleanup_module(void)
{ {
unregister_netdev(&dev_fmv18x); unregister_netdev(dev_fmv18x);
kfree(dev_fmv18x.priv); free_irq(dev_fmv18x->irq, dev_fmv18x);
dev_fmv18x.priv = NULL; release_region(dev_fmv18x->base_addr, FMV18X_IO_EXTENT);
free_netdev(dev_fmv18x);
/* If we don't do this, we can't re-insmod it later. */
free_irq(dev_fmv18x.irq, &dev_fmv18x);
release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT);
} }
#endif /* MODULE */ #endif /* MODULE */
......
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