Commit edf68308 authored by James Bottomley's avatar James Bottomley Committed by Jeff Garzik

3c509 fixes: correct MCA probing, add back ISA probe to Space.c

parent 0145e5c9
......@@ -103,6 +103,10 @@ static int el3_debug = EL3_DEBUG;
static int el3_debug = 2;
#endif
/* Used to do a global count of all the cards in the system. Must be
* a global variable so that the mca/eisa probe routines can increment
* it */
static int el3_cards = 0;
/* To minimize the size of the driver source I only define operating
constants if they are used several times. You'll need the manual
......@@ -167,16 +171,15 @@ struct el3_private {
/* skb send-queue */
int head, size;
struct sk_buff *queue[SKB_QUEUE_SIZE];
char mca_slot;
#ifdef CONFIG_PM
struct pm_dev *pmdev;
#endif
#ifdef __ISAPNP__
struct pnp_dev *pnpdev;
#endif
#ifdef CONFIG_EISA
struct eisa_device *edev;
#endif
enum {
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 struct net_device *el3_root_dev;
......@@ -200,6 +203,8 @@ static int el3_suspend(struct pm_dev *pdev);
static int el3_resume(struct pm_dev *pdev);
static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
#endif
/* generic device remove for all device types */
static int el3_device_remove (struct device *device);
#ifdef CONFIG_EISA
struct eisa_device_id el3_eisa_ids[] = {
......@@ -209,31 +214,46 @@ struct eisa_device_id el3_eisa_ids[] = {
};
static int el3_eisa_probe (struct device *device);
static int el3_eisa_remove (struct device *device);
struct eisa_driver el3_eisa_driver = {
.id_table = el3_eisa_ids,
.driver = {
.name = "3c509",
.probe = el3_eisa_probe,
.remove = __devexit_p (el3_eisa_remove)
.remove = __devexit_p (el3_device_remove)
}
};
#endif
#ifdef CONFIG_MCA
struct el3_mca_adapters_struct {
char* name;
int id;
static int el3_mca_probe(struct device *dev);
static short el3_mca_adapter_ids[] __initdata = {
0x627c,
0x627d,
0x62db,
0x62f6,
0x62f7,
0x0000
};
static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = {
{ "3Com 3c529 EtherLink III (10base2)", 0x627c },
{ "3Com 3c529 EtherLink III (10baseT)", 0x627d },
{ "3Com 3c529 EtherLink III (test mode)", 0x62db },
{ "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
{ "3Com 3c529 EtherLink III (TP)", 0x62f7 },
{ NULL, 0 },
static char *el3_mca_adapter_names[] __initdata = {
"3Com 3c529 EtherLink III (10base2)",
"3Com 3c529 EtherLink III (10baseT)",
"3Com 3c529 EtherLink III (test mode)",
"3Com 3c529 EtherLink III (TP or coax)",
"3Com 3c529 EtherLink III (TP)",
NULL
};
static struct mca_driver el3_mca_driver = {
.id_table = el3_mca_adapter_ids,
.driver = {
.name = "3c529",
.bus = &mca_bus_type,
.probe = el3_mca_probe,
.remove = __devexit_p(el3_device_remove),
},
};
#endif /* CONFIG_MCA */
......@@ -264,12 +284,12 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
};
static u16 el3_isapnp_phys_addr[8][3];
#endif /* __ISAPNP__ */
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_eisa_remove
* - 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. */
......@@ -278,10 +298,9 @@ static int __init el3_common_init (struct net_device *dev)
{
struct el3_private *lp = dev->priv;
short i;
#ifdef CONFIG_EISA
if (!lp->edev) /* EISA devices are not chained */
#endif
el3_cards++;
if (!lp->dev) /* probed devices are not chained */
{
lp->next_dev = el3_root_dev;
el3_root_dev = dev;
......@@ -337,17 +356,13 @@ static void el3_common_remove (struct net_device *dev)
struct el3_private *lp = dev->priv;
(void) lp; /* Keep gcc quiet... */
#ifdef CONFIG_MCA
if(lp->mca_slot!=-1)
mca_mark_as_unused(lp->mca_slot);
#endif
#ifdef CONFIG_PM
if (lp->pmdev)
pm_unregister(lp->pmdev);
#endif
#ifdef __ISAPNP__
if (lp->pnpdev)
pnp_device_detach(lp->pnpdev);
if (lp->type == EL3_PNP)
pnp_device_detach(to_pnp_dev(lp->dev));
#endif
unregister_netdev (dev);
......@@ -363,76 +378,11 @@ static int __init el3_probe(int card_idx)
int ioaddr, irq, if_port;
u16 phys_addr[3];
static int current_tag;
int mca_slot = -1;
#ifdef __ISAPNP__
static int pnp_cards;
struct pnp_dev *idev = NULL;
#endif /* __ISAPNP__ */
#ifdef CONFIG_MCA
/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, heavily
* modified by Chris Beauregard (cpbeaure@csclub.uwaterloo.ca)
* to support standard MCA probing.
*
* redone for multi-card detection by ZP Gu (zpg@castle.net)
* now works as a module
*/
if( MCA_bus ) {
int slot, j;
u_char pos4, pos5;
for( j = 0; el3_mca_adapters[j].name != NULL; j ++ ) {
slot = 0;
while( slot != MCA_NOTFOUND ) {
slot = mca_find_unused_adapter(
el3_mca_adapters[j].id, slot );
if( slot == MCA_NOTFOUND ) break;
/* if we get this far, an adapter has been
* detected and is enabled
*/
pos4 = mca_read_stored_pos( slot, 4 );
pos5 = mca_read_stored_pos( slot, 5 );
ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
irq = pos5 & 0x0f;
/* probing for a card at a particular IO/IRQ */
if(dev && ((dev->irq >= 1 && dev->irq != irq) ||
(dev->base_addr >= 1 && dev->base_addr != ioaddr))) {
slot++; /* probing next slot */
continue;
}
printk("3c509: found %s at slot %d\n",
el3_mca_adapters[j].name, slot + 1 );
/* claim the slot */
mca_set_adapter_name(slot, el3_mca_adapters[j].name);
mca_set_adapter_procfn(slot, NULL, NULL);
mca_mark_as_used(slot);
if_port = pos4 & 0x03;
if (el3_debug > 2) {
printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
}
EL3WINDOW(0);
for (i = 0; i < 3; i++) {
phys_addr[i] = htons(read_eeprom(ioaddr, i));
}
mca_slot = slot;
goto found;
}
}
/* if we get here, we didn't find an MCA adapter */
return -ENODEV;
}
#endif /* CONFIG_MCA */
#ifdef __ISAPNP__
if (nopnp == 1)
goto no_pnp;
......@@ -580,7 +530,7 @@ static int __init el3_probe(int card_idx)
/* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ);
found:
dev = init_etherdev(NULL, sizeof(struct el3_private));
if (dev == NULL) {
release_region(ioaddr, EL3_IO_EXTENT);
......@@ -594,13 +544,80 @@ static int __init el3_probe(int card_idx)
dev->if_port = if_port;
lp = dev->priv;
#ifdef __ISAPNP__
lp->pnpdev = idev;
lp->dev = &idev->dev;
#endif
lp->mca_slot = mca_slot;
return el3_common_init (dev);
}
#ifdef CONFIG_MCA
static int __init el3_mca_probe(struct device *device) {
/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
* heavily modified by Chris Beauregard
* (cpbeaure@csclub.uwaterloo.ca) to support standard MCA
* probing.
*
* 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];
struct net_device *dev = NULL;
u_char pos4, pos5;
struct mca_device *mdev = to_mca_device(device);
int slot = mdev->slot;
pos4 = mca_device_read_stored_pos(mdev, 4);
pos5 = mca_device_read_stored_pos(mdev, 5);
ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
irq = pos5 & 0x0f;
printk("3c529: found %s at slot %d\n",
el3_mca_adapter_names[mdev->index], slot + 1);
/* claim the slot */
strncpy(device->name, el3_mca_adapter_names[mdev->index],
sizeof(device->name));
mca_device_set_claim(mdev, 1);
if_port = pos4 & 0x03;
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);
}
EL3WINDOW(0);
for (i = 0; i < 3; i++) {
phys_addr[i] = htons(read_eeprom(ioaddr, i));
}
dev = init_etherdev(NULL, sizeof(struct el3_private));
if (dev == NULL) {
release_region(ioaddr, EL3_IO_EXTENT);
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
dev->base_addr = ioaddr;
dev->irq = irq;
dev->if_port = if_port;
lp = dev->priv;
lp->dev = device;
lp->type = EL3_MCA;
device->driver_data = dev;
return el3_common_init (dev);
}
#endif /* CONFIG_MCA */
#ifdef CONFIG_EISA
static int __init el3_eisa_probe (struct device *device)
{
......@@ -642,25 +659,26 @@ static int __init el3_eisa_probe (struct device *device)
dev->irq = irq;
dev->if_port = if_port;
lp = dev->priv;
lp->mca_slot = -1;
lp->edev = edev;
lp->dev = device;
lp->type = EL3_EISA;
eisa_set_drvdata (edev, dev);
return el3_common_init (dev);
}
#endif
static int __devexit el3_eisa_remove (struct device *device)
/* This remove works for all device types.
*
* The net dev must be stored in the driver_data field */
static int __devexit el3_device_remove (struct device *device)
{
struct eisa_device *edev;
struct net_device *dev;
edev = to_eisa_device (device);
dev = eisa_get_drvdata (edev);
dev = device->driver_data;
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.
......@@ -1080,7 +1098,7 @@ el3_close(struct net_device *dev)
free_irq(dev->irq, dev);
/* Switching back to window 0 disables the IRQ. */
EL3WINDOW(0);
if (!lp->edev) {
if (lp->type != EL3_EISA) {
/* But we explicitly zero the IRQ line select anyway. Don't do
* it on EISA cards, it prevents the module from getting an
* IRQ after unload+reload... */
......@@ -1530,7 +1548,7 @@ MODULE_LICENSE("GPL");
static int __init el3_init_module(void)
{
int el3_cards = 0;
el3_cards = 0;
if (debug >= 0)
el3_debug = debug;
......@@ -1548,8 +1566,9 @@ static int __init el3_init_module(void)
if (eisa_driver_register (&el3_eisa_driver) < 0) {
eisa_driver_unregister (&el3_eisa_driver);
}
else
el3_cards++; /* Found an eisa card */
#endif
#ifdef CONFIG_MCA
mca_register_driver(&el3_mca_driver);
#endif
return el3_cards ? 0 : -ENODEV;
}
......@@ -1569,6 +1588,9 @@ static void __exit el3_cleanup_module(void)
#ifdef CONFIG_EISA
eisa_driver_unregister (&el3_eisa_driver);
#endif
#ifdef CONFIG_MCA
mca_unregister_driver(&el3_mca_driver);
#endif
}
module_init (el3_init_module);
......
......@@ -224,6 +224,9 @@ static struct devprobe isa_probes[] __initdata = {
#ifdef CONFIG_EL2 /* 3c503 */
{el2_probe, 0},
#endif
#ifdef CONFIG_EL3
{el3_probe, 0},
#endif
#ifdef CONFIG_HPLAN
{hp_probe, 0},
#endif
......
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