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; ...@@ -103,6 +103,10 @@ static int el3_debug = EL3_DEBUG;
static int el3_debug = 2; static int el3_debug = 2;
#endif #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 /* 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
...@@ -167,16 +171,15 @@ struct el3_private { ...@@ -167,16 +171,15 @@ struct el3_private {
/* 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];
char mca_slot;
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct pm_dev *pmdev; struct pm_dev *pmdev;
#endif #endif
#ifdef __ISAPNP__ enum {
struct pnp_dev *pnpdev; EL3_MCA,
#endif EL3_PNP,
#ifdef CONFIG_EISA EL3_EISA,
struct eisa_device *edev; } type; /* type of device */
#endif struct device *dev;
}; };
static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/ static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/
static struct net_device *el3_root_dev; static struct net_device *el3_root_dev;
...@@ -200,6 +203,8 @@ static int el3_suspend(struct pm_dev *pdev); ...@@ -200,6 +203,8 @@ static int el3_suspend(struct pm_dev *pdev);
static int el3_resume(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); static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
#endif #endif
/* generic device remove for all device types */
static int el3_device_remove (struct device *device);
#ifdef CONFIG_EISA #ifdef CONFIG_EISA
struct eisa_device_id el3_eisa_ids[] = { struct eisa_device_id el3_eisa_ids[] = {
...@@ -209,31 +214,46 @@ 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_probe (struct device *device);
static int el3_eisa_remove (struct device *device);
struct eisa_driver el3_eisa_driver = { struct eisa_driver el3_eisa_driver = {
.id_table = el3_eisa_ids, .id_table = el3_eisa_ids,
.driver = { .driver = {
.name = "3c509", .name = "3c509",
.probe = el3_eisa_probe, .probe = el3_eisa_probe,
.remove = __devexit_p (el3_eisa_remove) .remove = __devexit_p (el3_device_remove)
} }
}; };
#endif #endif
#ifdef CONFIG_MCA #ifdef CONFIG_MCA
struct el3_mca_adapters_struct { static int el3_mca_probe(struct device *dev);
char* name;
int id; static short el3_mca_adapter_ids[] __initdata = {
0x627c,
0x627d,
0x62db,
0x62f6,
0x62f7,
0x0000
}; };
static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = { static char *el3_mca_adapter_names[] __initdata = {
{ "3Com 3c529 EtherLink III (10base2)", 0x627c }, "3Com 3c529 EtherLink III (10base2)",
{ "3Com 3c529 EtherLink III (10baseT)", 0x627d }, "3Com 3c529 EtherLink III (10baseT)",
{ "3Com 3c529 EtherLink III (test mode)", 0x62db }, "3Com 3c529 EtherLink III (test mode)",
{ "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 }, "3Com 3c529 EtherLink III (TP or coax)",
{ "3Com 3c529 EtherLink III (TP)", 0x62f7 }, "3Com 3c529 EtherLink III (TP)",
{ NULL, 0 }, 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 */ #endif /* CONFIG_MCA */
...@@ -264,12 +284,12 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { ...@@ -264,12 +284,12 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
}; };
static u16 el3_isapnp_phys_addr[8][3]; static u16 el3_isapnp_phys_addr[8][3];
#endif /* __ISAPNP__ */
static int nopnp; static int nopnp;
#endif /* __ISAPNP__ */
/* With the driver model introduction for EISA devices, both init /* With the driver model introduction for EISA devices, both init
* and cleanup have been split : * 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 * - MCA/ISA still use el3_probe
* *
* Both call el3_common_init/el3_common_remove. */ * Both call el3_common_init/el3_common_remove. */
...@@ -278,10 +298,9 @@ static int __init el3_common_init (struct net_device *dev) ...@@ -278,10 +298,9 @@ static int __init el3_common_init (struct net_device *dev)
{ {
struct el3_private *lp = dev->priv; struct el3_private *lp = dev->priv;
short i; short i;
#ifdef CONFIG_EISA el3_cards++;
if (!lp->edev) /* EISA devices are not chained */ if (!lp->dev) /* probed devices are not chained */
#endif
{ {
lp->next_dev = el3_root_dev; lp->next_dev = el3_root_dev;
el3_root_dev = dev; el3_root_dev = dev;
...@@ -337,17 +356,13 @@ static void el3_common_remove (struct net_device *dev) ...@@ -337,17 +356,13 @@ static void el3_common_remove (struct net_device *dev)
struct el3_private *lp = dev->priv; struct el3_private *lp = dev->priv;
(void) lp; /* Keep gcc quiet... */ (void) lp; /* Keep gcc quiet... */
#ifdef CONFIG_MCA
if(lp->mca_slot!=-1)
mca_mark_as_unused(lp->mca_slot);
#endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
if (lp->pmdev) if (lp->pmdev)
pm_unregister(lp->pmdev); pm_unregister(lp->pmdev);
#endif #endif
#ifdef __ISAPNP__ #ifdef __ISAPNP__
if (lp->pnpdev) if (lp->type == EL3_PNP)
pnp_device_detach(lp->pnpdev); pnp_device_detach(to_pnp_dev(lp->dev));
#endif #endif
unregister_netdev (dev); unregister_netdev (dev);
...@@ -363,76 +378,11 @@ static int __init el3_probe(int card_idx) ...@@ -363,76 +378,11 @@ static int __init el3_probe(int card_idx)
int ioaddr, irq, if_port; int ioaddr, irq, if_port;
u16 phys_addr[3]; u16 phys_addr[3];
static int current_tag; static int current_tag;
int mca_slot = -1;
#ifdef __ISAPNP__ #ifdef __ISAPNP__
static int pnp_cards; static int pnp_cards;
struct pnp_dev *idev = NULL; struct pnp_dev *idev = NULL;
#endif /* __ISAPNP__ */ #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__ #ifdef __ISAPNP__
if (nopnp == 1) if (nopnp == 1)
goto no_pnp; goto no_pnp;
...@@ -580,7 +530,7 @@ static int __init el3_probe(int card_idx) ...@@ -580,7 +530,7 @@ static int __init el3_probe(int card_idx)
/* Free the interrupt so that some other card can use it. */ /* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ); outw(0x0f00, ioaddr + WN0_IRQ);
found:
dev = init_etherdev(NULL, sizeof(struct el3_private)); dev = init_etherdev(NULL, sizeof(struct el3_private));
if (dev == NULL) { if (dev == NULL) {
release_region(ioaddr, EL3_IO_EXTENT); release_region(ioaddr, EL3_IO_EXTENT);
...@@ -594,13 +544,80 @@ static int __init el3_probe(int card_idx) ...@@ -594,13 +544,80 @@ static int __init el3_probe(int card_idx)
dev->if_port = if_port; dev->if_port = if_port;
lp = dev->priv; lp = dev->priv;
#ifdef __ISAPNP__ #ifdef __ISAPNP__
lp->pnpdev = idev; lp->dev = &idev->dev;
#endif #endif
lp->mca_slot = mca_slot;
return el3_common_init (dev); 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 #ifdef CONFIG_EISA
static int __init el3_eisa_probe (struct device *device) static int __init el3_eisa_probe (struct device *device)
{ {
...@@ -642,25 +659,26 @@ 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->irq = irq;
dev->if_port = if_port; dev->if_port = if_port;
lp = dev->priv; lp = dev->priv;
lp->mca_slot = -1; lp->dev = device;
lp->edev = edev; lp->type = EL3_EISA;
eisa_set_drvdata (edev, dev); eisa_set_drvdata (edev, dev);
return el3_common_init (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; struct net_device *dev;
edev = to_eisa_device (device); dev = device->driver_data;
dev = eisa_get_drvdata (edev);
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.
...@@ -1080,7 +1098,7 @@ el3_close(struct net_device *dev) ...@@ -1080,7 +1098,7 @@ el3_close(struct net_device *dev)
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
/* Switching back to window 0 disables the IRQ. */ /* Switching back to window 0 disables the IRQ. */
EL3WINDOW(0); EL3WINDOW(0);
if (!lp->edev) { if (lp->type != EL3_EISA) {
/* But we explicitly zero the IRQ line select anyway. Don't do /* But we explicitly zero the IRQ line select anyway. Don't do
* it on EISA cards, it prevents the module from getting an * it on EISA cards, it prevents the module from getting an
* IRQ after unload+reload... */ * IRQ after unload+reload... */
...@@ -1530,7 +1548,7 @@ MODULE_LICENSE("GPL"); ...@@ -1530,7 +1548,7 @@ MODULE_LICENSE("GPL");
static int __init el3_init_module(void) static int __init el3_init_module(void)
{ {
int el3_cards = 0; el3_cards = 0;
if (debug >= 0) if (debug >= 0)
el3_debug = debug; el3_debug = debug;
...@@ -1548,8 +1566,9 @@ static int __init el3_init_module(void) ...@@ -1548,8 +1566,9 @@ static int __init el3_init_module(void)
if (eisa_driver_register (&el3_eisa_driver) < 0) { if (eisa_driver_register (&el3_eisa_driver) < 0) {
eisa_driver_unregister (&el3_eisa_driver); eisa_driver_unregister (&el3_eisa_driver);
} }
else #endif
el3_cards++; /* Found an eisa card */ #ifdef CONFIG_MCA
mca_register_driver(&el3_mca_driver);
#endif #endif
return el3_cards ? 0 : -ENODEV; return el3_cards ? 0 : -ENODEV;
} }
...@@ -1569,6 +1588,9 @@ static void __exit el3_cleanup_module(void) ...@@ -1569,6 +1588,9 @@ static void __exit el3_cleanup_module(void)
#ifdef CONFIG_EISA #ifdef CONFIG_EISA
eisa_driver_unregister (&el3_eisa_driver); eisa_driver_unregister (&el3_eisa_driver);
#endif #endif
#ifdef CONFIG_MCA
mca_unregister_driver(&el3_mca_driver);
#endif
} }
module_init (el3_init_module); module_init (el3_init_module);
......
...@@ -224,6 +224,9 @@ static struct devprobe isa_probes[] __initdata = { ...@@ -224,6 +224,9 @@ static struct devprobe isa_probes[] __initdata = {
#ifdef CONFIG_EL2 /* 3c503 */ #ifdef CONFIG_EL2 /* 3c503 */
{el2_probe, 0}, {el2_probe, 0},
#endif #endif
#ifdef CONFIG_EL3
{el3_probe, 0},
#endif
#ifdef CONFIG_HPLAN #ifdef CONFIG_HPLAN
{hp_probe, 0}, {hp_probe, 0},
#endif #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