3c509: convert to isa_driver and pnp_driver
Convert 3c509 driver to isa_driver and pnp_driver. The result is that autoloading using udev and hibernation works with ISA PnP cards. It also adds hibernation support for non-PnP ISA cards. xcvr module parameter was removed as its value was not used. Tested using 3 ISA cards in various combinations of PnP and non-PnP modes. EISA and MCA only compile-tested. Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
@@ -55,24 +55,23 @@
|
|||||||
- Increase *read_eeprom udelay to workaround oops with 2 cards.
|
- Increase *read_eeprom udelay to workaround oops with 2 cards.
|
||||||
v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
|
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_NAME "3c509"
|
||||||
#define DRV_VERSION "1.19b"
|
#define DRV_VERSION "1.20"
|
||||||
#define DRV_RELDATE "08Nov2002"
|
#define DRV_RELDATE "04Feb2008"
|
||||||
|
|
||||||
/* A few values that may be tweaked. */
|
/* A few values that may be tweaked. */
|
||||||
|
|
||||||
/* Time in jiffies before concluding the transmitter is hung. */
|
/* Time in jiffies before concluding the transmitter is hung. */
|
||||||
#define TX_TIMEOUT (400*HZ/1000)
|
#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>
|
#include <linux/module.h>
|
||||||
#ifdef CONFIG_MCA
|
|
||||||
#include <linux/mca.h>
|
#include <linux/mca.h>
|
||||||
#endif
|
#include <linux/isa.h>
|
||||||
#include <linux/isapnp.h>
|
#include <linux/pnp.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/errno.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";
|
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
|
#ifdef EL3_DEBUG
|
||||||
static int el3_debug = EL3_DEBUG;
|
static int el3_debug = EL3_DEBUG;
|
||||||
#else
|
#else
|
||||||
@@ -111,6 +106,7 @@ static int el3_debug = 2;
|
|||||||
* a global variable so that the mca/eisa probe routines can increment
|
* a global variable so that the mca/eisa probe routines can increment
|
||||||
* it */
|
* it */
|
||||||
static int el3_cards = 0;
|
static int el3_cards = 0;
|
||||||
|
#define EL3_MAX_CARDS 8
|
||||||
|
|
||||||
/* To minimize the size of the driver source I only define operating
|
/* To minimize the size of the driver source I only define operating
|
||||||
constants if they are used several times. You'll need the manual
|
constants if they are used several times. You'll need the manual
|
||||||
@@ -168,23 +164,31 @@ enum RxFilter {
|
|||||||
*/
|
*/
|
||||||
#define SKB_QUEUE_SIZE 64
|
#define SKB_QUEUE_SIZE 64
|
||||||
|
|
||||||
|
enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
|
||||||
|
|
||||||
struct el3_private {
|
struct el3_private {
|
||||||
struct net_device_stats stats;
|
struct net_device_stats stats;
|
||||||
struct net_device *next_dev;
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
/* skb send-queue */
|
/* skb send-queue */
|
||||||
int head, size;
|
int head, size;
|
||||||
struct sk_buff *queue[SKB_QUEUE_SIZE];
|
struct sk_buff *queue[SKB_QUEUE_SIZE];
|
||||||
enum {
|
enum el3_cardtype type;
|
||||||
EL3_MCA,
|
|
||||||
EL3_PNP,
|
|
||||||
EL3_EISA,
|
|
||||||
} type; /* type of device */
|
|
||||||
struct device *dev;
|
|
||||||
};
|
};
|
||||||
static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/
|
static int id_port;
|
||||||
static struct net_device *el3_root_dev;
|
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 id_read_eeprom(int index);
|
||||||
static ushort read_eeprom(int ioaddr, int index);
|
static ushort read_eeprom(int ioaddr, int index);
|
||||||
static int el3_open(struct net_device *dev);
|
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_down(struct net_device *dev);
|
||||||
static void el3_up(struct net_device *dev);
|
static void el3_up(struct net_device *dev);
|
||||||
static const struct ethtool_ops ethtool_ops;
|
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_suspend(struct device *, pm_message_t);
|
||||||
static int el3_resume(struct device *);
|
static int el3_resume(struct device *);
|
||||||
#else
|
#else
|
||||||
@@ -209,13 +213,272 @@ static int el3_resume(struct device *);
|
|||||||
|
|
||||||
|
|
||||||
/* generic device remove for all device types */
|
/* generic device remove for all device types */
|
||||||
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
|
|
||||||
static int el3_device_remove (struct device *device);
|
static int el3_device_remove (struct device *device);
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
static void el3_poll_controller(struct net_device *dev);
|
static void el3_poll_controller(struct net_device *dev);
|
||||||
#endif
|
#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
|
#ifdef CONFIG_EISA
|
||||||
static struct eisa_device_id el3_eisa_ids[] = {
|
static struct eisa_device_id el3_eisa_ids[] = {
|
||||||
{ "TCM5092" },
|
{ "TCM5092" },
|
||||||
@@ -230,13 +493,14 @@ static int el3_eisa_probe (struct device *device);
|
|||||||
static struct eisa_driver el3_eisa_driver = {
|
static struct eisa_driver el3_eisa_driver = {
|
||||||
.id_table = el3_eisa_ids,
|
.id_table = el3_eisa_ids,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "3c509",
|
.name = "3c579",
|
||||||
.probe = el3_eisa_probe,
|
.probe = el3_eisa_probe,
|
||||||
.remove = __devexit_p (el3_device_remove),
|
.remove = __devexit_p (el3_device_remove),
|
||||||
.suspend = el3_suspend,
|
.suspend = el3_suspend,
|
||||||
.resume = el3_resume,
|
.resume = el3_resume,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
static int eisa_registered;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MCA
|
#ifdef CONFIG_MCA
|
||||||
@@ -271,45 +535,9 @@ static struct mca_driver el3_mca_driver = {
|
|||||||
.resume = el3_resume,
|
.resume = el3_resume,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
static int mca_registered;
|
||||||
#endif /* CONFIG_MCA */
|
#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)
|
static int __init el3_common_init(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct el3_private *lp = netdev_priv(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)
|
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);
|
unregister_netdev (dev);
|
||||||
release_region(dev->base_addr, EL3_IO_EXTENT);
|
release_region(dev->base_addr, EL3_IO_EXTENT);
|
||||||
free_netdev (dev);
|
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
|
#ifdef CONFIG_MCA
|
||||||
static int __init el3_mca_probe(struct device *device)
|
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)
|
* redone for multi-card detection by ZP Gu (zpg@castle.net)
|
||||||
* now works as a module */
|
* now works as a module */
|
||||||
|
|
||||||
struct el3_private *lp;
|
|
||||||
short i;
|
short i;
|
||||||
int ioaddr, irq, if_port;
|
int ioaddr, irq, if_port;
|
||||||
u16 phys_addr[3];
|
u16 phys_addr[3];
|
||||||
@@ -613,7 +620,7 @@ static int __init el3_mca_probe(struct device *device)
|
|||||||
irq = pos5 & 0x0f;
|
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);
|
el3_mca_adapter_names[mdev->index], slot + 1);
|
||||||
|
|
||||||
/* claim the slot */
|
/* claim the slot */
|
||||||
@@ -626,7 +633,7 @@ static int __init el3_mca_probe(struct device *device)
|
|||||||
irq = mca_device_transform_irq(mdev, irq);
|
irq = mca_device_transform_irq(mdev, irq);
|
||||||
ioaddr = mca_device_transform_ioport(mdev, ioaddr);
|
ioaddr = mca_device_transform_ioport(mdev, ioaddr);
|
||||||
if (el3_debug > 2) {
|
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);
|
EL3WINDOW(0);
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
@@ -641,13 +648,7 @@ static int __init el3_mca_probe(struct device *device)
|
|||||||
|
|
||||||
netdev_boot_setup_check(dev);
|
netdev_boot_setup_check(dev);
|
||||||
|
|
||||||
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
|
el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA);
|
||||||
dev->base_addr = ioaddr;
|
|
||||||
dev->irq = irq;
|
|
||||||
dev->if_port = if_port;
|
|
||||||
lp = netdev_priv(dev);
|
|
||||||
lp->dev = device;
|
|
||||||
lp->type = EL3_MCA;
|
|
||||||
device->driver_data = dev;
|
device->driver_data = dev;
|
||||||
err = el3_common_init(dev);
|
err = el3_common_init(dev);
|
||||||
|
|
||||||
@@ -657,7 +658,7 @@ static int __init el3_mca_probe(struct device *device)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
el3_cards++;
|
el3_devs[el3_cards++] = dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,7 +667,6 @@ static int __init el3_mca_probe(struct device *device)
|
|||||||
#ifdef CONFIG_EISA
|
#ifdef CONFIG_EISA
|
||||||
static int __init el3_eisa_probe (struct device *device)
|
static int __init el3_eisa_probe (struct device *device)
|
||||||
{
|
{
|
||||||
struct el3_private *lp;
|
|
||||||
short i;
|
short i;
|
||||||
int ioaddr, irq, if_port;
|
int ioaddr, irq, if_port;
|
||||||
u16 phys_addr[3];
|
u16 phys_addr[3];
|
||||||
@@ -678,7 +678,7 @@ static int __init el3_eisa_probe (struct device *device)
|
|||||||
edev = to_eisa_device (device);
|
edev = to_eisa_device (device);
|
||||||
ioaddr = edev->base_addr;
|
ioaddr = edev->base_addr;
|
||||||
|
|
||||||
if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509"))
|
if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa"))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
/* Change the register set to the configuration window 0. */
|
/* 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);
|
netdev_boot_setup_check(dev);
|
||||||
|
|
||||||
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
|
el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA);
|
||||||
dev->base_addr = ioaddr;
|
|
||||||
dev->irq = irq;
|
|
||||||
dev->if_port = if_port;
|
|
||||||
lp = netdev_priv(dev);
|
|
||||||
lp->dev = device;
|
|
||||||
lp->type = EL3_EISA;
|
|
||||||
eisa_set_drvdata (edev, dev);
|
eisa_set_drvdata (edev, dev);
|
||||||
err = el3_common_init(dev);
|
err = el3_common_init(dev);
|
||||||
|
|
||||||
@@ -716,12 +710,11 @@ static int __init el3_eisa_probe (struct device *device)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
el3_cards++;
|
el3_devs[el3_cards++] = dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
|
|
||||||
/* This remove works for all device types.
|
/* This remove works for all device types.
|
||||||
*
|
*
|
||||||
* The net dev must be stored in the driver_data field */
|
* 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);
|
el3_common_remove (dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Read a word from the EEPROM using the regular EEPROM access register.
|
/* Read a word from the EEPROM using the regular EEPROM access register.
|
||||||
Assume that we are in register window zero.
|
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. */
|
/* 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;
|
int bit, word = 0;
|
||||||
|
|
||||||
@@ -765,7 +757,7 @@ static ushort __init id_read_eeprom(int index)
|
|||||||
word = (word << 1) + (inb(id_port) & 0x01);
|
word = (word << 1) + (inb(id_port) & 0x01);
|
||||||
|
|
||||||
if (el3_debug > 3)
|
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;
|
return word;
|
||||||
}
|
}
|
||||||
@@ -787,13 +779,13 @@ el3_open(struct net_device *dev)
|
|||||||
|
|
||||||
EL3WINDOW(0);
|
EL3WINDOW(0);
|
||||||
if (el3_debug > 3)
|
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));
|
dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
|
||||||
|
|
||||||
el3_up(dev);
|
el3_up(dev);
|
||||||
|
|
||||||
if (el3_debug > 3)
|
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));
|
dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -806,7 +798,7 @@ el3_tx_timeout (struct net_device *dev)
|
|||||||
int ioaddr = dev->base_addr;
|
int ioaddr = dev->base_addr;
|
||||||
|
|
||||||
/* Transmitter timeout, serious problems. */
|
/* 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",
|
"Tx FIFO room %d.\n",
|
||||||
dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
|
dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
|
||||||
inw(ioaddr + TX_FREE));
|
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;
|
lp->stats.tx_bytes += skb->len;
|
||||||
|
|
||||||
if (el3_debug > 4) {
|
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));
|
dev->name, skb->len, inw(ioaddr + EL3_STATUS));
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
@@ -840,7 +832,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||||||
ushort status = inw(ioaddr + EL3_STATUS);
|
ushort status = inw(ioaddr + EL3_STATUS);
|
||||||
if (status & 0x0001 /* IRQ line active, missed one. */
|
if (status & 0x0001 /* IRQ line active, missed one. */
|
||||||
&& inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */
|
&& 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,
|
" Tx %2.2x Rx %4.4x.\n", dev->name, status,
|
||||||
inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
|
inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
|
||||||
inw(ioaddr + RX_STATUS));
|
inw(ioaddr + RX_STATUS));
|
||||||
@@ -914,7 +906,7 @@ el3_interrupt(int irq, void *dev_id)
|
|||||||
|
|
||||||
if (el3_debug > 4) {
|
if (el3_debug > 4) {
|
||||||
status = inw(ioaddr + EL3_STATUS);
|
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)) &
|
while ((status = inw(ioaddr + EL3_STATUS)) &
|
||||||
@@ -925,7 +917,7 @@ el3_interrupt(int irq, void *dev_id)
|
|||||||
|
|
||||||
if (status & TxAvailable) {
|
if (status & TxAvailable) {
|
||||||
if (el3_debug > 5)
|
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. */
|
/* There's room in the FIFO for a full-sized packet. */
|
||||||
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
|
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
|
||||||
netif_wake_queue (dev);
|
netif_wake_queue (dev);
|
||||||
@@ -964,7 +956,7 @@ el3_interrupt(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (--i < 0) {
|
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);
|
dev->name, status);
|
||||||
/* Clear all interrupts. */
|
/* Clear all interrupts. */
|
||||||
outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
|
outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
|
||||||
@@ -975,7 +967,7 @@ el3_interrupt(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (el3_debug > 4) {
|
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));
|
inw(ioaddr + EL3_STATUS));
|
||||||
}
|
}
|
||||||
spin_unlock(&lp->lock);
|
spin_unlock(&lp->lock);
|
||||||
@@ -1450,7 +1442,7 @@ el3_up(struct net_device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Power Management support functions */
|
/* Power Management support functions */
|
||||||
#ifdef EL3_SUSPEND
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
static int
|
static int
|
||||||
el3_suspend(struct device *pdev, pm_message_t state)
|
el3_suspend(struct device *pdev, pm_message_t state)
|
||||||
@@ -1500,79 +1492,102 @@ el3_resume(struct device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* EL3_SUSPEND */
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
/* 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};
|
|
||||||
|
|
||||||
module_param(debug,int, 0);
|
module_param(debug,int, 0);
|
||||||
module_param_array(irq, int, NULL, 0);
|
module_param_array(irq, int, NULL, 0);
|
||||||
module_param_array(xcvr, int, NULL, 0);
|
|
||||||
module_param(max_interrupt_work, int, 0);
|
module_param(max_interrupt_work, int, 0);
|
||||||
MODULE_PARM_DESC(debug, "debug level (0-6)");
|
MODULE_PARM_DESC(debug, "debug level (0-6)");
|
||||||
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
|
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");
|
MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
|
||||||
#if defined(__ISAPNP__)
|
#ifdef CONFIG_PNP
|
||||||
module_param(nopnp, int, 0);
|
module_param(nopnp, int, 0);
|
||||||
MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
|
MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
|
||||||
MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
|
#endif /* CONFIG_PNP */
|
||||||
#endif /* __ISAPNP__ */
|
MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver");
|
||||||
MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
static int __init el3_init_module(void)
|
static int __init el3_init_module(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
el3_cards = 0;
|
|
||||||
|
|
||||||
if (debug >= 0)
|
if (debug >= 0)
|
||||||
el3_debug = debug;
|
el3_debug = debug;
|
||||||
|
|
||||||
el3_root_dev = NULL;
|
#ifdef CONFIG_PNP
|
||||||
while (el3_probe(el3_cards) == 0) {
|
if (!nopnp) {
|
||||||
if (irq[el3_cards] > 1)
|
ret = pnp_register_driver(&el3_pnp_driver);
|
||||||
el3_root_dev->irq = irq[el3_cards];
|
if (!ret)
|
||||||
if (xcvr[el3_cards] >= 0)
|
pnp_registered = 1;
|
||||||
el3_root_dev->if_port = xcvr[el3_cards];
|
}
|
||||||
el3_cards++;
|
#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
|
#ifdef CONFIG_EISA
|
||||||
ret = eisa_driver_register(&el3_eisa_driver);
|
ret = eisa_driver_register(&el3_eisa_driver);
|
||||||
|
if (!ret)
|
||||||
|
eisa_registered = 1;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_MCA
|
#ifdef CONFIG_MCA
|
||||||
{
|
ret = mca_register_driver(&el3_mca_driver);
|
||||||
int err = mca_register_driver(&el3_mca_driver);
|
if (!ret)
|
||||||
if (ret == 0)
|
mca_registered = 1;
|
||||||
ret = err;
|
#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
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit el3_cleanup_module(void)
|
static void __exit el3_cleanup_module(void)
|
||||||
{
|
{
|
||||||
struct net_device *next_dev;
|
#ifdef CONFIG_PNP
|
||||||
|
if (pnp_registered)
|
||||||
while (el3_root_dev) {
|
pnp_unregister_driver(&el3_pnp_driver);
|
||||||
struct el3_private *lp = netdev_priv(el3_root_dev);
|
#endif
|
||||||
|
if (isa_registered)
|
||||||
next_dev = lp->next_dev;
|
isa_unregister_driver(&el3_isa_driver);
|
||||||
el3_common_remove (el3_root_dev);
|
if (id_port)
|
||||||
el3_root_dev = next_dev;
|
release_region(id_port, 1);
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_EISA
|
#ifdef CONFIG_EISA
|
||||||
eisa_driver_unregister (&el3_eisa_driver);
|
if (eisa_registered)
|
||||||
|
eisa_driver_unregister(&el3_eisa_driver);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_MCA
|
#ifdef CONFIG_MCA
|
||||||
|
if (mca_registered)
|
||||||
mca_unregister_driver(&el3_mca_driver);
|
mca_unregister_driver(&el3_mca_driver);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init (el3_init_module);
|
module_init (el3_init_module);
|
||||||
module_exit (el3_cleanup_module);
|
module_exit (el3_cleanup_module);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user