diff options
Diffstat (limited to 'drivers/net/3c509.c')
| -rw-r--r-- | drivers/net/3c509.c | 729 | 
1 files changed, 372 insertions, 357 deletions
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 8fafac987e0..54dac0696d9 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -54,25 +54,24 @@  		v1.19a 28Oct2002 Davud Ruggiero <jdr@farfalle.com>  			- Increase *read_eeprom udelay to workaround oops with 2 cards.  		v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org> -		    - Introduce driver model for EISA cards. +			- Introduce driver model for EISA cards. +		v1.20  04Feb2008 Ondrej Zary <linux@rainbow-software.org> +			- convert to isa_driver and pnp_driver and some cleanups  */  #define DRV_NAME	"3c509" -#define DRV_VERSION	"1.19b" -#define DRV_RELDATE	"08Nov2002" +#define DRV_VERSION	"1.20" +#define DRV_RELDATE	"04Feb2008"  /* A few values that may be tweaked. */  /* Time in jiffies before concluding the transmitter is hung. */  #define TX_TIMEOUT  (400*HZ/1000) -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 10;  #include <linux/module.h> -#ifdef CONFIG_MCA  #include <linux/mca.h> -#endif -#include <linux/isapnp.h> +#include <linux/isa.h> +#include <linux/pnp.h>  #include <linux/string.h>  #include <linux/interrupt.h>  #include <linux/errno.h> @@ -97,10 +96,6 @@ static int max_interrupt_work = 10;  static char version[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n"; -#if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA)) -#define EL3_SUSPEND -#endif -  #ifdef EL3_DEBUG  static int el3_debug = EL3_DEBUG;  #else @@ -111,6 +106,7 @@ static int el3_debug = 2;   * a global variable so that the mca/eisa probe routines can increment   * it */  static int el3_cards = 0; +#define EL3_MAX_CARDS 8  /* To minimize the size of the driver source I only define operating     constants if they are used several times.  You'll need the manual @@ -119,7 +115,7 @@ static int el3_cards = 0;  #define EL3_DATA 0x00  #define EL3_CMD 0x0e  #define EL3_STATUS 0x0e -#define	 EEPROM_READ 0x80 +#define	EEPROM_READ 0x80  #define EL3_IO_EXTENT	16 @@ -168,23 +164,31 @@ enum RxFilter {   */  #define SKB_QUEUE_SIZE	64 +enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA }; +  struct el3_private {  	struct net_device_stats stats; -	struct net_device *next_dev;  	spinlock_t lock;  	/* skb send-queue */  	int head, size;  	struct sk_buff *queue[SKB_QUEUE_SIZE]; -	enum { -		EL3_MCA, -		EL3_PNP, -		EL3_EISA, -	} type;						/* type of device */ -	struct device *dev; +	enum el3_cardtype type;  }; -static int id_port __initdata = 0x110;	/* Start with 0x110 to avoid new sound cards.*/ -static struct net_device *el3_root_dev; +static int id_port; +static int current_tag; +static struct net_device *el3_devs[EL3_MAX_CARDS]; + +/* Parameters that may be passed into the module. */ +static int debug = -1; +static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 10; +#ifdef CONFIG_PNP +static int nopnp; +#endif +static int __init el3_common_init(struct net_device *dev); +static void el3_common_remove(struct net_device *dev);  static ushort id_read_eeprom(int index);  static ushort read_eeprom(int ioaddr, int index);  static int el3_open(struct net_device *dev); @@ -199,7 +203,7 @@ static void el3_tx_timeout (struct net_device *dev);  static void el3_down(struct net_device *dev);  static void el3_up(struct net_device *dev);  static const struct ethtool_ops ethtool_ops; -#ifdef EL3_SUSPEND +#ifdef CONFIG_PM  static int el3_suspend(struct device *, pm_message_t);  static int el3_resume(struct device *);  #else @@ -209,13 +213,272 @@ static int el3_resume(struct device *);  /* generic device remove for all device types */ -#if defined(CONFIG_EISA) || defined(CONFIG_MCA)  static int el3_device_remove (struct device *device); -#endif  #ifdef CONFIG_NET_POLL_CONTROLLER  static void el3_poll_controller(struct net_device *dev);  #endif +/* Return 0 on success, 1 on error, 2 when found already detected PnP card */ +static int el3_isa_id_sequence(__be16 *phys_addr) +{ +	short lrs_state = 0xff; +	int i; + +	/* ISA boards are detected by sending the ID sequence to the +	   ID_PORT.  We find cards past the first by setting the 'current_tag' +	   on cards as they are found.  Cards with their tag set will not +	   respond to subsequent ID sequences. */ + +	outb(0x00, id_port); +	outb(0x00, id_port); +	for (i = 0; i < 255; i++) { +		outb(lrs_state, id_port); +		lrs_state <<= 1; +		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; +	} +	/* For the first probe, clear all board's tag registers. */ +	if (current_tag == 0) +		outb(0xd0, id_port); +	else			/* Otherwise kill off already-found boards. */ +		outb(0xd8, id_port); +	if (id_read_eeprom(7) != 0x6d50) +		return 1; +	/* Read in EEPROM data, which does contention-select. +	   Only the lowest address board will stay "on-line". +	   3Com got the byte order backwards. */ +	for (i = 0; i < 3; i++) +		phys_addr[i] = htons(id_read_eeprom(i)); +#ifdef CONFIG_PNP +	if (!nopnp) { +		/* The ISA PnP 3c509 cards respond to the ID sequence too. +		   This check is needed in order not to register them twice. */ +		for (i = 0; i < el3_cards; i++) { +			struct el3_private *lp = netdev_priv(el3_devs[i]); +			if (lp->type == EL3_PNP +			    && !memcmp(phys_addr, el3_devs[i]->dev_addr, +				       ETH_ALEN)) { +				if (el3_debug > 3) +					printk(KERN_DEBUG "3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", +						phys_addr[0] & 0xff, phys_addr[0] >> 8, +						phys_addr[1] & 0xff, phys_addr[1] >> 8, +						phys_addr[2] & 0xff, phys_addr[2] >> 8); +				/* Set the adaptor tag so that the next card can be found. */ +				outb(0xd0 + ++current_tag, id_port); +				return 2; +			} +		} +	} +#endif /* CONFIG_PNP */ +	return 0; + +} + +static void __devinit el3_dev_fill(struct net_device *dev, __be16 *phys_addr, +				   int ioaddr, int irq, int if_port, +				   enum el3_cardtype type) +{ +	struct el3_private *lp = netdev_priv(dev); + +	memcpy(dev->dev_addr, phys_addr, ETH_ALEN); +	dev->base_addr = ioaddr; +	dev->irq = irq; +	dev->if_port = if_port; +	lp->type = type; +} + +static int __devinit el3_isa_match(struct device *pdev, +				   unsigned int ndev) +{ +	struct net_device *dev; +	int ioaddr, isa_irq, if_port, err; +	unsigned int iobase; +	__be16 phys_addr[3]; + +	while ((err = el3_isa_id_sequence(phys_addr)) == 2) +		;	/* Skip to next card when PnP card found */ +	if (err == 1) +		return 0; + +	iobase = id_read_eeprom(8); +	if_port = iobase >> 14; +	ioaddr = 0x200 + ((iobase & 0x1f) << 4); +	if (irq[el3_cards] > 1 && irq[el3_cards] < 16) +		isa_irq = irq[el3_cards]; +	else +		isa_irq = id_read_eeprom(9) >> 12; + +	dev = alloc_etherdev(sizeof(struct el3_private)); +	if (!dev) +		return -ENOMEM; + +	netdev_boot_setup_check(dev); + +	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) { +		free_netdev(dev); +		return 0; +	} + +	/* Set the adaptor tag so that the next card can be found. */ +	outb(0xd0 + ++current_tag, id_port); + +	/* Activate the adaptor at the EEPROM location. */ +	outb((ioaddr >> 4) | 0xe0, id_port); + +	EL3WINDOW(0); +	if (inw(ioaddr) != 0x6d50) { +		free_netdev(dev); +		return 0; +	} + +	/* Free the interrupt so that some other card can use it. */ +	outw(0x0f00, ioaddr + WN0_IRQ); + +	el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA); +	dev_set_drvdata(pdev, dev); +	if (el3_common_init(dev)) { +		free_netdev(dev); +		return 0; +	} + +	el3_devs[el3_cards++] = dev; +	return 1; +} + +static int __devexit el3_isa_remove(struct device *pdev, +				    unsigned int ndev) +{ +	el3_device_remove(pdev); +	dev_set_drvdata(pdev, NULL); +	return 0; +} + +#ifdef CONFIG_PM +static int el3_isa_suspend(struct device *dev, unsigned int n, +			   pm_message_t state) +{ +	current_tag = 0; +	return el3_suspend(dev, state); +} + +static int el3_isa_resume(struct device *dev, unsigned int n) +{ +	struct net_device *ndev = dev_get_drvdata(dev); +	int ioaddr = ndev->base_addr, err; +	__be16 phys_addr[3]; + +	while ((err = el3_isa_id_sequence(phys_addr)) == 2) +		;	/* Skip to next card when PnP card found */ +	if (err == 1) +		return 0; +	/* Set the adaptor tag so that the next card can be found. */ +	outb(0xd0 + ++current_tag, id_port); +	/* Enable the card */ +	outb((ioaddr >> 4) | 0xe0, id_port); +	EL3WINDOW(0); +	if (inw(ioaddr) != 0x6d50) +		return 1; +	/* Free the interrupt so that some other card can use it. */ +	outw(0x0f00, ioaddr + WN0_IRQ); +	return el3_resume(dev); +} +#endif + +static struct isa_driver el3_isa_driver = { +	.match		= el3_isa_match, +	.remove		= __devexit_p(el3_isa_remove), +#ifdef CONFIG_PM +	.suspend	= el3_isa_suspend, +	.resume		= el3_isa_resume, +#endif +	.driver		= { +		.name	= "3c509" +	}, +}; +static int isa_registered; + +#ifdef CONFIG_PNP +static struct pnp_device_id el3_pnp_ids[] = { +	{ .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ +	{ .id = "TCM5091" }, /* 3Com Etherlink III */ +	{ .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ +	{ .id = "TCM5095" }, /* 3Com Etherlink III (TPO) */ +	{ .id = "TCM5098" }, /* 3Com Etherlink III (TPC) */ +	{ .id = "PNP80f7" }, /* 3Com Etherlink III compatible */ +	{ .id = "PNP80f8" }, /* 3Com Etherlink III compatible */ +	{ .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, el3_pnp_ids); + +static int __devinit el3_pnp_probe(struct pnp_dev *pdev, +				    const struct pnp_device_id *id) +{ +	short i; +	int ioaddr, irq, if_port; +	u16 phys_addr[3]; +	struct net_device *dev = NULL; +	int err; + +	ioaddr = pnp_port_start(pdev, 0); +	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp")) +		return -EBUSY; +	irq = pnp_irq(pdev, 0); +	EL3WINDOW(0); +	for (i = 0; i < 3; i++) +		phys_addr[i] = htons(read_eeprom(ioaddr, i)); +	if_port = read_eeprom(ioaddr, 8) >> 14; +	dev = alloc_etherdev(sizeof(struct el3_private)); +	if (!dev) { +		release_region(ioaddr, EL3_IO_EXTENT); +		return -ENOMEM; +	} +	SET_NETDEV_DEV(dev, &pdev->dev); +	netdev_boot_setup_check(dev); + +	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP); +	pnp_set_drvdata(pdev, dev); +	err = el3_common_init(dev); + +	if (err) { +		pnp_set_drvdata(pdev, NULL); +		free_netdev(dev); +		return err; +	} + +	el3_devs[el3_cards++] = dev; +	return 0; +} + +static void __devexit el3_pnp_remove(struct pnp_dev *pdev) +{ +	el3_common_remove(pnp_get_drvdata(pdev)); +	pnp_set_drvdata(pdev, NULL); +} + +#ifdef CONFIG_PM +static int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) +{ +	return el3_suspend(&pdev->dev, state); +} + +static int el3_pnp_resume(struct pnp_dev *pdev) +{ +	return el3_resume(&pdev->dev); +} +#endif + +static struct pnp_driver el3_pnp_driver = { +	.name		= "3c509", +	.id_table	= el3_pnp_ids, +	.probe		= el3_pnp_probe, +	.remove		= __devexit_p(el3_pnp_remove), +#ifdef CONFIG_PM +	.suspend	= el3_pnp_suspend, +	.resume		= el3_pnp_resume, +#endif +}; +static int pnp_registered; +#endif /* CONFIG_PNP */ +  #ifdef CONFIG_EISA  static struct eisa_device_id el3_eisa_ids[] = {  		{ "TCM5092" }, @@ -230,13 +493,14 @@ static int el3_eisa_probe (struct device *device);  static struct eisa_driver el3_eisa_driver = {  		.id_table = el3_eisa_ids,  		.driver   = { -				.name    = "3c509", +				.name    = "3c579",  				.probe   = el3_eisa_probe,  				.remove  = __devexit_p (el3_device_remove),  				.suspend = el3_suspend,  				.resume  = el3_resume,  		}  }; +static int eisa_registered;  #endif  #ifdef CONFIG_MCA @@ -271,45 +535,9 @@ static struct mca_driver el3_mca_driver = {  				.resume  = el3_resume,  		},  }; +static int mca_registered;  #endif /* CONFIG_MCA */ -#if defined(__ISAPNP__) -static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), -		(long) "3Com Etherlink III (TP)" }, -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), -		(long) "3Com Etherlink III" }, -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), -		(long) "3Com Etherlink III (combo)" }, -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), -		(long) "3Com Etherlink III (TPO)" }, -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), -		(long) "3Com Etherlink III (TPC)" }, -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f7), -		(long) "3Com Etherlink III compatible" }, -	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID, -		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), -		(long) "3Com Etherlink III compatible" }, -	{ }	/* terminate list */ -}; - -static __be16 el3_isapnp_phys_addr[8][3]; -static int nopnp; -#endif /* __ISAPNP__ */ - -/* With the driver model introduction for EISA devices, both init - * and cleanup have been split : - * - EISA devices probe/remove starts in el3_eisa_probe/el3_device_remove - * - MCA/ISA still use el3_probe - * - * Both call el3_common_init/el3_common_remove. */ -  static int __init el3_common_init(struct net_device *dev)  {  	struct el3_private *lp = netdev_priv(dev); @@ -360,231 +588,11 @@ static int __init el3_common_init(struct net_device *dev)  static void el3_common_remove (struct net_device *dev)  { -	struct el3_private *lp = netdev_priv(dev); - -	(void) lp;				/* Keep gcc quiet... */ -#if defined(__ISAPNP__) -	if (lp->type == EL3_PNP) -		pnp_device_detach(to_pnp_dev(lp->dev)); -#endif -  	unregister_netdev (dev);  	release_region(dev->base_addr, EL3_IO_EXTENT);  	free_netdev (dev);  } -static int __init el3_probe(int card_idx) -{ -	struct net_device *dev; -	struct el3_private *lp; -	short lrs_state = 0xff, i; -	int ioaddr, irq, if_port; -	__be16 phys_addr[3]; -	static int current_tag; -	int err = -ENODEV; -#if defined(__ISAPNP__) -	static int pnp_cards; -	struct pnp_dev *idev = NULL; -	int pnp_found = 0; - -	if (nopnp == 1) -		goto no_pnp; - -	for (i=0; el3_isapnp_adapters[i].vendor != 0; i++) { -		int j; -		while ((idev = pnp_find_dev(NULL, -					    el3_isapnp_adapters[i].vendor, -					    el3_isapnp_adapters[i].function, -					    idev))) { -			if (pnp_device_attach(idev) < 0) -				continue; -			if (pnp_activate_dev(idev) < 0) { -__again: -				pnp_device_detach(idev); -				continue; -			} -			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) -				goto __again; -			ioaddr = pnp_port_start(idev, 0); -			if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509 PnP")) { -				pnp_device_detach(idev); -				return -EBUSY; -			} -			irq = pnp_irq(idev, 0); -			if (el3_debug > 3) -				printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n", -					(char*) el3_isapnp_adapters[i].driver_data, ioaddr, irq); -			EL3WINDOW(0); -			for (j = 0; j < 3; j++) -				el3_isapnp_phys_addr[pnp_cards][j] = -					phys_addr[j] = -						htons(read_eeprom(ioaddr, j)); -			if_port = read_eeprom(ioaddr, 8) >> 14; -			dev = alloc_etherdev(sizeof (struct el3_private)); -			if (!dev) { -					release_region(ioaddr, EL3_IO_EXTENT); -					pnp_device_detach(idev); -					return -ENOMEM; -			} - -			SET_NETDEV_DEV(dev, &idev->dev); -			pnp_cards++; - -			netdev_boot_setup_check(dev); -			pnp_found = 1; -			goto found; -		} -	} -no_pnp: -#endif /* __ISAPNP__ */ - -	/* Select an open I/O location at 0x1*0 to do contention select. */ -	for ( ; id_port < 0x200; id_port += 0x10) { -		if (!request_region(id_port, 1, "3c509")) -			continue; -		outb(0x00, id_port); -		outb(0xff, id_port); -		if (inb(id_port) & 0x01){ -			release_region(id_port, 1); -			break; -		} else -			release_region(id_port, 1); -	} -	if (id_port >= 0x200) { -		/* Rare -- do we really need a warning? */ -		printk(" WARNING: No I/O port available for 3c509 activation.\n"); -		return -ENODEV; -	} - -	/* Next check for all ISA bus boards by sending the ID sequence to the -	   ID_PORT.  We find cards past the first by setting the 'current_tag' -	   on cards as they are found.  Cards with their tag set will not -	   respond to subsequent ID sequences. */ - -	outb(0x00, id_port); -	outb(0x00, id_port); -	for(i = 0; i < 255; i++) { -		outb(lrs_state, id_port); -		lrs_state <<= 1; -		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; -	} - -	/* For the first probe, clear all board's tag registers. */ -	if (current_tag == 0) -		outb(0xd0, id_port); -	else				/* Otherwise kill off already-found boards. */ -		outb(0xd8, id_port); - -	if (id_read_eeprom(7) != 0x6d50) { -		return -ENODEV; -	} - -	/* Read in EEPROM data, which does contention-select. -	   Only the lowest address board will stay "on-line". -	   3Com got the byte order backwards. */ -	for (i = 0; i < 3; i++) { -		phys_addr[i] = htons(id_read_eeprom(i)); -	} - -#if defined(__ISAPNP__) -	if (nopnp == 0) { -		/* The ISA PnP 3c509 cards respond to the ID sequence. -		   This check is needed in order not to register them twice. */ -		for (i = 0; i < pnp_cards; i++) { -			if (phys_addr[0] == el3_isapnp_phys_addr[i][0] && -			    phys_addr[1] == el3_isapnp_phys_addr[i][1] && -			    phys_addr[2] == el3_isapnp_phys_addr[i][2]) -			{ -				if (el3_debug > 3) -					printk("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", -						phys_addr[0] & 0xff, phys_addr[0] >> 8, -						phys_addr[1] & 0xff, phys_addr[1] >> 8, -						phys_addr[2] & 0xff, phys_addr[2] >> 8); -				/* Set the adaptor tag so that the next card can be found. */ -				outb(0xd0 + ++current_tag, id_port); -				goto no_pnp; -			} -		} -	} -#endif /* __ISAPNP__ */ - -	{ -		unsigned int iobase = id_read_eeprom(8); -		if_port = iobase >> 14; -		ioaddr = 0x200 + ((iobase & 0x1f) << 4); -	} -	irq = id_read_eeprom(9) >> 12; - -	dev = alloc_etherdev(sizeof (struct el3_private)); -	if (!dev) -		return -ENOMEM; - -	netdev_boot_setup_check(dev); - -	/* Set passed-in IRQ or I/O Addr. */ -	if (dev->irq > 1  &&  dev->irq < 16) -			irq = dev->irq; - -	if (dev->base_addr) { -		if (dev->mem_end == 0x3c509 	/* Magic key */ -		    && dev->base_addr >= 0x200  &&  dev->base_addr <= 0x3e0) -			ioaddr = dev->base_addr & 0x3f0; -		else if (dev->base_addr != ioaddr) -			goto out; -	} - -	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509")) { -		err = -EBUSY; -		goto out; -	} - -	/* Set the adaptor tag so that the next card can be found. */ -	outb(0xd0 + ++current_tag, id_port); - -	/* Activate the adaptor at the EEPROM location. */ -	outb((ioaddr >> 4) | 0xe0, id_port); - -	EL3WINDOW(0); -	if (inw(ioaddr) != 0x6d50) -		goto out1; - -	/* Free the interrupt so that some other card can use it. */ -	outw(0x0f00, ioaddr + WN0_IRQ); - -#if defined(__ISAPNP__) - found:							/* PNP jumps here... */ -#endif /* __ISAPNP__ */ - -	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); -	dev->base_addr = ioaddr; -	dev->irq = irq; -	dev->if_port = if_port; -	lp = netdev_priv(dev); -#if defined(__ISAPNP__) -	lp->dev = &idev->dev; -	if (pnp_found) -		lp->type = EL3_PNP; -#endif -	err = el3_common_init(dev); - -	if (err) -		goto out1; - -	el3_cards++; -	lp->next_dev = el3_root_dev; -	el3_root_dev = dev; -	return 0; - -out1: -#if defined(__ISAPNP__) -	if (idev) -		pnp_device_detach(idev); -#endif -out: -	free_netdev(dev); -	return err; -} -  #ifdef CONFIG_MCA  static int __init el3_mca_probe(struct device *device)  { @@ -596,7 +604,6 @@ static int __init el3_mca_probe(struct device *device)  	 * redone for multi-card detection by ZP Gu (zpg@castle.net)  	 * now works as a module */ -	struct el3_private *lp;  	short i;  	int ioaddr, irq, if_port;  	u16 phys_addr[3]; @@ -613,7 +620,7 @@ static int __init el3_mca_probe(struct device *device)  	irq = pos5 & 0x0f; -	printk("3c529: found %s at slot %d\n", +	printk(KERN_INFO "3c529: found %s at slot %d\n",  		   el3_mca_adapter_names[mdev->index], slot + 1);  	/* claim the slot */ @@ -626,7 +633,7 @@ static int __init el3_mca_probe(struct device *device)  	irq = mca_device_transform_irq(mdev, irq);  	ioaddr = mca_device_transform_ioport(mdev, ioaddr);  	if (el3_debug > 2) { -			printk("3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port); +			printk(KERN_DEBUG "3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);  	}  	EL3WINDOW(0);  	for (i = 0; i < 3; i++) { @@ -641,13 +648,7 @@ static int __init el3_mca_probe(struct device *device)  	netdev_boot_setup_check(dev); -	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); -	dev->base_addr = ioaddr; -	dev->irq = irq; -	dev->if_port = if_port; -	lp = netdev_priv(dev); -	lp->dev = device; -	lp->type = EL3_MCA; +	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA);  	device->driver_data = dev;  	err = el3_common_init(dev); @@ -657,7 +658,7 @@ static int __init el3_mca_probe(struct device *device)  		return -ENOMEM;  	} -	el3_cards++; +	el3_devs[el3_cards++] = dev;  	return 0;  } @@ -666,7 +667,6 @@ static int __init el3_mca_probe(struct device *device)  #ifdef CONFIG_EISA  static int __init el3_eisa_probe (struct device *device)  { -	struct el3_private *lp;  	short i;  	int ioaddr, irq, if_port;  	u16 phys_addr[3]; @@ -678,7 +678,7 @@ static int __init el3_eisa_probe (struct device *device)  	edev = to_eisa_device (device);  	ioaddr = edev->base_addr; -	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509")) +	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa"))  		return -EBUSY;  	/* Change the register set to the configuration window 0. */ @@ -700,13 +700,7 @@ static int __init el3_eisa_probe (struct device *device)  	netdev_boot_setup_check(dev); -	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); -	dev->base_addr = ioaddr; -	dev->irq = irq; -	dev->if_port = if_port; -	lp = netdev_priv(dev); -	lp->dev = device; -	lp->type = EL3_EISA; +	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA);  	eisa_set_drvdata (edev, dev);  	err = el3_common_init(dev); @@ -716,12 +710,11 @@ static int __init el3_eisa_probe (struct device *device)  		return err;  	} -	el3_cards++; +	el3_devs[el3_cards++] = dev;  	return 0;  }  #endif -#if defined(CONFIG_EISA) || defined(CONFIG_MCA)  /* This remove works for all device types.   *   * The net dev must be stored in the driver_data field */ @@ -734,7 +727,6 @@ static int __devexit el3_device_remove (struct device *device)  	el3_common_remove (dev);  	return 0;  } -#endif  /* Read a word from the EEPROM using the regular EEPROM access register.     Assume that we are in register window zero. @@ -749,7 +741,7 @@ static ushort read_eeprom(int ioaddr, int index)  }  /* Read a word from the EEPROM when in the ISA ID probe state. */ -static ushort __init id_read_eeprom(int index) +static ushort id_read_eeprom(int index)  {  	int bit, word = 0; @@ -765,7 +757,7 @@ static ushort __init id_read_eeprom(int index)  		word = (word << 1) + (inb(id_port) & 0x01);  	if (el3_debug > 3) -		printk("  3c509 EEPROM word %d %#4.4x.\n", index, word); +		printk(KERN_DEBUG "  3c509 EEPROM word %d %#4.4x.\n", index, word);  	return word;  } @@ -787,13 +779,13 @@ el3_open(struct net_device *dev)  	EL3WINDOW(0);  	if (el3_debug > 3) -		printk("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name, +		printk(KERN_DEBUG "%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,  			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));  	el3_up(dev);  	if (el3_debug > 3) -		printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n", +		printk(KERN_DEBUG "%s: Opened 3c509  IRQ %d  status %4.4x.\n",  			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));  	return 0; @@ -806,7 +798,7 @@ el3_tx_timeout (struct net_device *dev)  	int ioaddr = dev->base_addr;  	/* Transmitter timeout, serious problems. */ -	printk("%s: transmit timed out, Tx_status %2.2x status %4.4x " +	printk(KERN_WARNING "%s: transmit timed out, Tx_status %2.2x status %4.4x "  		   "Tx FIFO room %d.\n",  		   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),  		   inw(ioaddr + TX_FREE)); @@ -831,7 +823,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)  	lp->stats.tx_bytes += skb->len;  	if (el3_debug > 4) { -		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", +		printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",  			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));  	}  #if 0 @@ -840,7 +832,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)  		ushort status = inw(ioaddr + EL3_STATUS);  		if (status & 0x0001 		/* IRQ line active, missed one. */  			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */ -			printk("%s: Missed interrupt, status then %04x now %04x" +			printk(KERN_DEBUG "%s: Missed interrupt, status then %04x now %04x"  				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,  				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),  				   inw(ioaddr + RX_STATUS)); @@ -914,7 +906,7 @@ el3_interrupt(int irq, void *dev_id)  	if (el3_debug > 4) {  		status = inw(ioaddr + EL3_STATUS); -		printk("%s: interrupt, status %4.4x.\n", dev->name, status); +		printk(KERN_DEBUG "%s: interrupt, status %4.4x.\n", dev->name, status);  	}  	while ((status = inw(ioaddr + EL3_STATUS)) & @@ -925,7 +917,7 @@ el3_interrupt(int irq, void *dev_id)  		if (status & TxAvailable) {  			if (el3_debug > 5) -				printk("	TX room bit was handled.\n"); +				printk(KERN_DEBUG "	TX room bit was handled.\n");  			/* There's room in the FIFO for a full-sized packet. */  			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);  			netif_wake_queue (dev); @@ -964,7 +956,7 @@ el3_interrupt(int irq, void *dev_id)  		}  		if (--i < 0) { -			printk("%s: Infinite loop in interrupt, status %4.4x.\n", +			printk(KERN_ERR "%s: Infinite loop in interrupt, status %4.4x.\n",  				   dev->name, status);  			/* Clear all interrupts. */  			outw(AckIntr | 0xFF, ioaddr + EL3_CMD); @@ -975,7 +967,7 @@ el3_interrupt(int irq, void *dev_id)  	}  	if (el3_debug > 4) { -		printk("%s: exiting interrupt, status %4.4x.\n", dev->name, +		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name,  			   inw(ioaddr + EL3_STATUS));  	}  	spin_unlock(&lp->lock); @@ -1450,7 +1442,7 @@ el3_up(struct net_device *dev)  }  /* Power Management support functions */ -#ifdef EL3_SUSPEND +#ifdef CONFIG_PM  static int  el3_suspend(struct device *pdev, pm_message_t state) @@ -1500,79 +1492,102 @@ el3_resume(struct device *pdev)  	return 0;  } -#endif /* EL3_SUSPEND */ - -/* Parameters that may be passed into the module. */ -static int debug = -1; -static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +#endif /* CONFIG_PM */  module_param(debug,int, 0);  module_param_array(irq, int, NULL, 0); -module_param_array(xcvr, int, NULL, 0);  module_param(max_interrupt_work, int, 0);  MODULE_PARM_DESC(debug, "debug level (0-6)");  MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); -MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");  MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); -#if defined(__ISAPNP__) +#ifdef CONFIG_PNP  module_param(nopnp, int, 0);  MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)"); -MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters); -#endif	/* __ISAPNP__ */ -MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver"); +#endif	/* CONFIG_PNP */ +MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver");  MODULE_LICENSE("GPL");  static int __init el3_init_module(void)  {  	int ret = 0; -	el3_cards = 0;  	if (debug >= 0)  		el3_debug = debug; -	el3_root_dev = NULL; -	while (el3_probe(el3_cards) == 0) { -		if (irq[el3_cards] > 1) -			el3_root_dev->irq = irq[el3_cards]; -		if (xcvr[el3_cards] >= 0) -			el3_root_dev->if_port = xcvr[el3_cards]; -		el3_cards++; +#ifdef CONFIG_PNP +	if (!nopnp) { +		ret = pnp_register_driver(&el3_pnp_driver); +		if (!ret) +			pnp_registered = 1; +	} +#endif +	/* Select an open I/O location at 0x1*0 to do ISA contention select. */ +	/* Start with 0x110 to avoid some sound cards.*/ +	for (id_port = 0x110 ; id_port < 0x200; id_port += 0x10) { +		if (!request_region(id_port, 1, "3c509-control")) +			continue; +		outb(0x00, id_port); +		outb(0xff, id_port); +		if (inb(id_port) & 0x01) +			break; +		else +			release_region(id_port, 1); +	} +	if (id_port >= 0x200) { +		id_port = 0; +		printk(KERN_ERR "No I/O port available for 3c509 activation.\n"); +	} else { +		ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS); +		if (!ret) +			isa_registered = 1;  	} -  #ifdef CONFIG_EISA  	ret = eisa_driver_register(&el3_eisa_driver); +	if (!ret) +		eisa_registered = 1;  #endif  #ifdef CONFIG_MCA -	{ -		int err = mca_register_driver(&el3_mca_driver); -		if (ret == 0) -			ret = err; -	} +	ret = mca_register_driver(&el3_mca_driver); +	if (!ret) +		mca_registered = 1; +#endif + +#ifdef CONFIG_PNP +	if (pnp_registered) +		ret = 0; +#endif +	if (isa_registered) +		ret = 0; +#ifdef CONFIG_EISA +	if (eisa_registered) +		ret = 0; +#endif +#ifdef CONFIG_MCA +	if (mca_registered) +		ret = 0;  #endif  	return ret;  }  static void __exit el3_cleanup_module(void)  { -	struct net_device *next_dev; - -	while (el3_root_dev) { -		struct el3_private *lp = netdev_priv(el3_root_dev); - -		next_dev = lp->next_dev; -		el3_common_remove (el3_root_dev); -		el3_root_dev = next_dev; -	} - +#ifdef CONFIG_PNP +	if (pnp_registered) +		pnp_unregister_driver(&el3_pnp_driver); +#endif +	if (isa_registered) +		isa_unregister_driver(&el3_isa_driver); +	if (id_port) +		release_region(id_port, 1);  #ifdef CONFIG_EISA -	eisa_driver_unregister (&el3_eisa_driver); +	if (eisa_registered) +		eisa_driver_unregister(&el3_eisa_driver);  #endif  #ifdef CONFIG_MCA -	mca_unregister_driver(&el3_mca_driver); +	if (mca_registered) +		mca_unregister_driver(&el3_mca_driver);  #endif  }  module_init (el3_init_module);  module_exit (el3_cleanup_module); -  |