diff options
Diffstat (limited to 'drivers/net/ne.c')
-rw-r--r-- | drivers/net/ne.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/drivers/net/ne.c b/drivers/net/ne.c index ae8a4fbdc..58573948c 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -28,7 +28,8 @@ rjohnson@analogic.com : Changed init order so an interrupt will only occur after memory is allocated for dev->priv. Deallocated memory last in cleanup_modue() - + Richard Guenther : Added support for ISAPnP cards + */ /* Routines for the NatSemi-based designs (NE[12]000). */ @@ -43,6 +44,7 @@ static const char *version = #include <linux/sched.h> #include <linux/errno.h> #include <linux/pci.h> +#include <linux/isapnp.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/system.h> @@ -90,6 +92,13 @@ pci_clone_list[] __initdata = { static int probe_pci = 1; #endif +static struct { unsigned short vendor, function; char *name; } +isapnp_clone_list[] __initdata = { + {ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), "NN NE2000" }, + {ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), "Generic PNP" }, + {0,} +}; + #ifdef SUPPORT_NE_BAD_CLONES /* A list of bad clones that we none-the-less recognize. */ static struct { const char *name8, *name16; unsigned char SAprefix[4];} @@ -128,6 +137,7 @@ static unsigned int pci_irq_line = 0; int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); +static int ne_probe_isapnp(struct net_device *dev); #ifdef CONFIG_PCI static int ne_probe_pci(struct net_device *dev); #endif @@ -193,6 +203,10 @@ int __init ne_probe(struct net_device *dev) return 0; #endif + /* Then look for any installed ISAPnP clones */ + if (isapnp_present() && (ne_probe_isapnp(dev) == 0)) + return 0; + #ifndef MODULE /* Last resort. The semi-risky ISA auto-probe. */ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { @@ -243,6 +257,46 @@ static int __init ne_probe_pci(struct net_device *dev) } #endif /* CONFIG_PCI */ +static int __init ne_probe_isapnp(struct net_device *dev) +{ + int i; + + for (i = 0; isapnp_clone_list[i].vendor != 0; i++) { + struct pci_dev *idev = NULL; + + while ((idev = isapnp_find_dev(NULL, + isapnp_clone_list[i].vendor, + isapnp_clone_list[i].function, + idev))) { + /* Avoid already found cards from previous calls */ + if (idev->prepare(idev)) + continue; + if (idev->activate(idev)) + continue; + pci_irq_line = idev->irq_resource[0].start; + /* if no irq, search for next */ + if (!pci_irq_line) + continue; + /* found it */ + if (ne_probe1(dev, idev->resource[0].start) != 0) { /* Shouldn't happen. */ + printk(KERN_ERR "ne.c: Probe of ISAPnP card at %#lx failed.\n", + idev->resource[0].start); + return -ENXIO; + } + ei_status.priv = (unsigned long)idev; + break; + } + if (!idev) + continue; + printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", + isapnp_clone_list[i].name, + dev->base_addr, dev->irq); + return 0; + } + + return -ENODEV; +} + static int __init ne_probe1(struct net_device *dev, int ioaddr) { int i; @@ -491,6 +545,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &ne_block_input; ei_status.block_output = &ne_block_output; ei_status.get_8390_hdr = &ne_get_8390_hdr; + ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; NS8390_init(dev, 0); @@ -819,6 +874,9 @@ void cleanup_module(void) struct net_device *dev = &dev_ne[this_dev]; if (dev->priv != NULL) { void *priv = dev->priv; + struct pci_dev *idev = (struct pci_dev *)ei_status.priv; + if (idev) + idev->deactivate(idev); free_irq(dev->irq, dev); release_region(dev->base_addr, NE_IO_EXTENT); unregister_netdev(dev); |