patch-2.2.15 linux/drivers/net/smc-mca.c
Next file: linux/drivers/net/smc-mca.h
Previous file: linux/drivers/net/sktr.h
Back to the patch index
Back to the overall index
- Lines: 535
- Date:
Fri Apr 21 12:46:20 2000
- Orig file:
v2.2.14/drivers/net/smc-mca.c
- Orig date:
Wed Dec 16 21:35:49 1998
diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
@@ -1,4 +1,4 @@
-/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
+/* smc-mca.c: A SMC Ultra ethernet driver for linux. */
/*
Most of this driver, except for ultramca_probe is nearly
verbatim from smc-ultra.c by Donald Becker. The rest is
@@ -8,7 +8,7 @@
This driver uses the cards in the 8390-compatible, shared memory mode.
Most of the run-time complexity is handled by the generic code in
- 8390.c. The code in this file is responsible for
+ 8390.c.
This driver enables the shared memory only when doing the actual data
transfers to avoid a bug in early version of the card that corrupted
@@ -20,9 +20,21 @@
Changelog:
- Paul Gortmaker : multiple card support for module users.
- David Weis : Micro Channel-ized it.
-
+ Paul Gortmaker : multiple card support for module users.
+ David Weis : Micro Channel-ized it.
+ Tom Sightler : Added support for IBM PS/2 Ethernet Adapter/A
+ Christopher Turcksin : Changed MCA-probe so that multiple adapters are
+ found correctly (Jul 16, 1997)
+ Chris Beauregard : Tried to merge the two changes above (Dec 15, 1997)
+ Tom Sightler : Fixed minor detection bug caused by above merge
+ Tom Sightler : Added support for three more Western Digital
+ MCA-adapters
+ Tom Sightler : Added support for 2.2.x mca_find_unused_adapter
+ Hartmut Schmidt : - Modified parameter detection to handle each
+ card differently depending on a switch-list
+ - 'card_ver' removed from the adapter list
+ - Some minor bug fixes
+ David Monro : Backport from 2.3 to 2.2, other minor fixes.
*/
@@ -66,53 +78,183 @@
#define ULTRA_IO_EXTENT 32
#define EN0_ERWCNT 0x08 /* Early receive warning count. */
+#define _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A 0
+#define _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A 1
+#define _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A 2
+#define _6fc1_WD_Starcard_PLUS_A_WD8003ST_A 3
+#define _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A 4
+#define _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A 5
+#define _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A 6
+#define _efe5_IBM_PS2_Adapter_A_for_Ethernet 7
+
+struct smc_mca_adapters_t {
+ unsigned int id;
+ char *name;
+};
+
+const struct smc_mca_adapters_t smc_mca_adapters[] = {
+ { 0x61c8, "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)" },
+ { 0x61c9, "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)" },
+ { 0x6fc0, "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)" },
+ { 0x6fc1, "WD Starcard PLUS/A (WD8003ST/A)" },
+ { 0x6fc2, "WD Ethercard PLUS 10T/A (WD8003W/A)" },
+ { 0xefd4, "IBM PS/2 Adapter/A for Ethernet UTP/AUI (WD8013WP/A)" },
+ { 0xefd5, "IBM PS/2 Adapter/A for Ethernet BNC/AUI (WD8013EP/A)" },
+ { 0xefe5, "IBM PS/2 Adapter/A for Ethernet" },
+ { 0x0000, NULL }
+};
-__initfunc(int ultramca_probe(struct device *dev))
+int __init ultramca_probe(struct device *dev)
{
unsigned short ioaddr;
unsigned char reg4, num_pages;
- char slot;
- unsigned char pos2, pos3, pos4, pos5;
- int i;
-
- /* Look for two flavors of SMC Elite/A (3013EP/A) -jeh- */
- if(( (slot=mca_find_adapter(0x61c8,0)) != MCA_NOTFOUND) ||
- ((slot=mca_find_adapter(0xefd5,0)) != MCA_NOTFOUND) )
+ char slot = -1;
+ unsigned char pos2 = 0xff, pos3 = 0xff, pos4 = 0xff, pos5 = 0xff;
+ int i, j;
+ int adapter_found = 0;
+ int adapter = 0;
+ int tbase = 0;
+ int tirq = 0;
+ int base_addr = dev ? dev->base_addr : 0;
+ int irq = dev ? dev->irq : 0;
- {
-#ifndef MODULE
- mca_set_adapter_name( slot, "SMC Elite/A (8013EP/A)" );
-#endif
+ if (!MCA_bus) {
+ return ENODEV;
}
- else if( (slot=mca_find_adapter(0x61c9,0)) != MCA_NOTFOUND)
- {
-#ifndef MODULE
- mca_set_adapter_name( slot, "SMC Elite10T/A (8013WP/A)" );
-#endif
+
+ /* This is a hack, snd should go away when the "0xffe0 means
+ * don't do ISA probe" code goes away. We aren't ISA, and 0xffe0
+ * is not a possible port for us.
+ */
+ if (base_addr == 0xffe0) {
+ base_addr = 0;
+ }
+ if (base_addr || irq) {
+ printk(KERN_INFO "Probing for SMC MCA adapter");
+ if (base_addr) {
+ printk(" at I/O address 0x%04x%c",
+ base_addr, irq ? ' ' : '\n');
+ }
+ if (irq) {
+ printk("using irq %d\n", irq);
+ }
}
- else
- return -ENODEV;
- pos2 = mca_read_stored_pos(slot, 2); /* IO range */
- pos3 = mca_read_stored_pos(slot, 3); /* shared mem */
- pos4 = mca_read_stored_pos(slot, 4); /* bios base */
- pos5 = mca_read_stored_pos(slot, 5); /* irq and media */
+ /* proper multicard detection by ZP Gu (zpg@castle.net) */
- dev->base_addr = ioaddr = addr_table[pos2 >> 4].base_addr;
- dev->irq = irq_table[(pos5 & ~IRQ_MASK) >> 2].irq;
+ for (j = 0; (smc_mca_adapters[j].name != NULL) && !adapter_found; j++) {
+ slot = mca_find_unused_adapter(smc_mca_adapters[j].id, 0);
+ while((slot != MCA_NOTFOUND) && !adapter_found) {
+ tirq = 0;
+ tbase = 0;
+
+ /* If we're trying to match a specificied irq or
+ * io address, we'll reject the adapter
+ * found unless it's the one we're looking for
+ */
+
+ pos2 = mca_read_stored_pos(slot, 2); /* io_addr */
+ pos3 = mca_read_stored_pos(slot, 3); /* shared mem */
+ pos4 = mca_read_stored_pos(slot, 4); /* ROM bios addr
+ * range */
+ pos5 = mca_read_stored_pos(slot, 5); /* irq, media
+ * and RIPL */
+
+ /* Test the following conditions:
+ * - If an irq parameter is supplied, compare it
+ * with the irq of the adapter we found
+ * - If a base_addr paramater is given, compare it
+ * with the base_addr of the adapter we found
+ * - Check that the irq and the base_addr of the
+ * adapter we found is not already in use by
+ * this driver
+ */
+ switch (j) { /* j = card-idx (card array above) [hs] */
+ case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
+ case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
+ case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
+ case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
+ {
+ tbase = addr_table[(pos2 & 0xf0) >> 4].base_addr;
+ tirq = irq_table[(pos5 & 0xc) >> 2].new_irq;
+ break;
+ }
+ case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
+ case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
+ case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
+ case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
+ {
+ tbase = ((pos2 & 0x0fe) * 0x10);
+ tirq = irq_table[(pos5 & 3)].old_irq;
+ break;
+ }
+ }
+
+ if(!tirq || !tbase || (irq && irq != tirq) || (base_addr && tbase != base_addr)) {
+ slot = mca_find_unused_adapter(smc_mca_adapters[j].id, slot + 1);
+ } else {
+ adapter_found = 1;
+ adapter = j;
+ }
+ }
+ }
+ /* Correct j now, before we forget */
+ j--;
+
+ if(!adapter_found) {
+ return ((base_addr || irq) ? ENXIO : ENODEV);
+ }
+
+ /* Adapter found. */
+
+ printk(KERN_INFO "%s: %s found in slot %d\n",
+ dev->name, smc_mca_adapters[adapter].name, slot + 1);
+
+ mca_set_adapter_name(slot, smc_mca_adapters[adapter].name);
+
+
+ dev->base_addr = ioaddr = tbase;
+ dev->irq = tirq;
dev->mem_start = 0;
- num_pages = 40;
- for (i = 0; i < 15; i++)
- {
- if (mem_table[i].mem_index == (pos3 & ~MEM_MASK))
+ num_pages = 40;
+
+ switch (j) { /* 'j' = card-# in const array above [hs] */
+ case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
+ case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
+ {
+ for (i = 0; i < 16; i++) { /* taking 16 counts
+ * up to 15 [hs] */
+ if (mem_table[i].mem_index == (pos3 & ~MEM_MASK)) {
+ dev->mem_start = mem_table[i].mem_start;
+ num_pages = mem_table[i].num_pages;
+ }
+ }
+ break;
+ }
+ case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
+ case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
+ case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
+ case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
{
- dev->mem_start = mem_table[i].mem_start;
- num_pages = mem_table[i].num_pages;
+ dev->mem_start = ((pos3 & 0xfc) * 0x1000);
+ num_pages = 0x40;
+ break;
+ }
+ case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
+ case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
+ {
+ /* courtesy of gamera@quartz.ocn.ne.jp, pos3 indicates
+ * the index of the 0x2000 step.
+ * beware different number of pages [hs]
+ */
+ dev->mem_start = 0xc0000 + (0x2000 * (pos3 & 0xf));
+ num_pages = 0x20 + (2 * (pos3 & 0x10));
+ break;
}
}
- if (dev->mem_start == 0) /* sanity check, shouldn't happen */
+ if (dev->mem_start == 0) /* sanity check, shouldn't happen */
return -ENODEV;
reg4 = inb(ioaddr + 4) & 0x7f;
@@ -121,52 +263,46 @@
if (load_8390_module("wd.c"))
return -ENOSYS;
- printk("%s: SMC Ultra MCA at %#3x,", dev->name, ioaddr);
+ printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
- /*
- * Switch from the station address to the alternate register set and
- * read the useful registers there.
+ /* Switch from the station address to the alternate register set
+ * and read the useful registers there.
*/
outb(0x80 | reg4, ioaddr + 4);
- /*
- * Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot.
+ /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot.
*/
outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
- /*
- * Switch back to the station address register set so that the MS-DOS driver
- * can find the card after a warm boot.
+ /* Switch back to the station address register set so that
+ * the MS-DOS driver can find the card after a warm boot.
*/
outb(reg4, ioaddr + 4);
- /*
- * Allocate dev->priv and fill in 8390 specific dev fields.
+ /* Allocate dev->priv and fill in 8390 specific dev fields.
*/
- if (ethdev_init(dev))
- {
+ if (ethdev_init(dev)) {
printk (", no memory for dev->priv.\n");
return -ENOMEM;
}
- /*
- * OK, we are certain this is going to work. Setup the device.
+ /* OK, we are certain this is going to work. Setup the device.
*/
+ mca_mark_as_used(slot);
request_region(ioaddr, ULTRA_IO_EXTENT, "smc-mca");
- /*
- * The 8390 isn't at the base address, so fake the offset
+ /* The 8390 isn't at the base address, so fake the offset
*/
- dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
+ dev->base_addr = ioaddr + ULTRA_NIC_OFFSET;
ei_status.name = "SMC Ultra MCA";
ei_status.word16 = 1;
@@ -174,16 +310,20 @@
ei_status.rx_start_page = START_PG + TX_PAGES;
ei_status.stop_page = num_pages;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->rmem_start = dev->mem_start + TX_PAGES * 256;
dev->mem_end = dev->rmem_end =
- dev->mem_start + (ei_status.stop_page - START_PG)*256;
+ dev->mem_start + (ei_status.stop_page - START_PG) * 256;
- printk(", IRQ %d memory %#lx-%#lx.\n", dev->irq, dev->mem_start, dev->mem_end-1);
+ printk(", IRQ %d memory %#lx-%#lx.\n",
+ dev->irq, dev->mem_start, dev->mem_end - 1);
ei_status.reset_8390 = &ultramca_reset_8390;
ei_status.block_input = &ultramca_block_input;
ei_status.block_output = &ultramca_block_output;
ei_status.get_8390_hdr = &ultramca_get_8390_hdr;
+
+ ei_status.priv = slot;
+
dev->open = &ultramca_open;
dev->stop = &ultramca_close_card;
NS8390_init(dev, 0);
@@ -196,21 +336,19 @@
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev))
- return -EAGAIN;
+ return -EAGAIN;
outb(ULTRA_MEMENB, ioaddr); /* Enable memory */
outb(0x80, ioaddr + 5); /* ??? */
outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */
outb(0x04, ioaddr + 5); /* ??? */
- /*
- * Set the early receive warning level in window 0 high enough not
- * to receive ERW interrupts.
+ /* Set the early receive warning level in window 0 high enough not
+ * to receive ERW interrupts.
*/
- /*
- * outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
- * outb(0xff, dev->base_addr + EN0_ERWCNT);
+ /* outb_p(E8390_NODMA + E8390_PAGE0, dev->base_addr);
+ * outb(0xff, dev->base_addr + EN0_ERWCNT);
*/
ei_open(dev);
@@ -223,7 +361,8 @@
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
outb(ULTRA_RESET, ioaddr);
- if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies);
+ if (ei_debug > 1)
+ printk("resetting Ultra, t=%ld...", jiffies);
ei_status.txing = 0;
outb(0x80, ioaddr + 5); /* ??? */
@@ -235,12 +374,13 @@
}
/* Grab the 8390 specific header. Similar to the block_input routine, but
- we don't need to be concerned with ring wrap as the header will be at
- the start of a page, so we optimize accordingly. */
+ * we don't need to be concerned with ring wrap as the header will be at
+ * the start of a page, so we optimize accordingly.
+ */
static void ultramca_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
- unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8);
+ unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG) << 8);
#ifdef notdef
/* Officially this is what we are doing, but the readl() is faster */
@@ -251,22 +391,20 @@
}
/* Block input and output are easy on shared memory ethercards, the only
- complication is when the ring buffer wraps. */
+ * complication is when the ring buffer wraps.
+ */
static void ultramca_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
{
- unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG<<8);
+ unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
- if (xfer_start + count > dev->rmem_end)
- {
- /* We must wrap the input move. */
+ if (xfer_start + count > dev->rmem_end) {
+ /* We must wrap the input move. */
int semi_count = dev->rmem_end - xfer_start;
memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
- }
- else
- {
+ } else {
/* Packet is in one chunk -- we can copy + cksum. */
eth_io_copy_and_sum(skb, xfer_start, count, 0);
}
@@ -276,7 +414,7 @@
static void ultramca_block_output(struct device *dev, int count, const unsigned char *buf,
int start_page)
{
- unsigned long shmem = dev->mem_start + ((start_page - START_PG)<<8);
+ unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8);
memcpy_toio(shmem, buf, count);
}
@@ -296,7 +434,8 @@
NS8390_init(dev, 0);
/* We should someday disable shared memory and change to 8-bit mode
- "just in case"... */
+ * "just in case"...
+ */
MOD_DEC_USE_COUNT;
@@ -307,8 +446,9 @@
#ifdef MODULE
#undef MODULE /* don't want to bother now! */
-#define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */
-#define NAMELEN 8 /* # of chars for storing dev->name */
+#define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */
+#define NAMELEN 8 /* # of chars for storing dev->name */
+
static char namelist[NAMELEN * MAX_ULTRAMCA_CARDS] = { 0, };
static struct device dev_ultra[MAX_ULTRAMCA_CARDS] =
@@ -327,53 +467,41 @@
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-
int init_module(void)
{
int this_dev, found = 0;
- for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++)
- {
+ for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
struct device *dev = &dev_ultra[this_dev];
- dev->name = namelist+(NAMELEN*this_dev);
+ dev->name = namelist + (NAMELEN * this_dev);
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->init = ultramca_probe;
- if (io[this_dev] == 0)
- {
- if (this_dev != 0)
- break; /* only autoprobe 1st one */
- printk(KERN_NOTICE "smc-mca.c: Presently autoprobing (not recommended) for a single card.\n");
- }
- if (register_netdev(dev) != 0)
- {
- printk(KERN_WARNING "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) { /* Got at least one. */
- lock_8390_module();
- return 0;
- }
- return -ENXIO;
+
+ if (register_netdev(dev) != 0) {
+ break;
}
found++;
}
- lock_8390_module();
- return 0;
+ if (found != 0) { /* Got at least one. */
+ lock_8390_module();
+ return 0;
+ }
+ printk(KERN_NOTICE "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
+ return -ENXIO;
}
void cleanup_module(void)
{
int this_dev;
- for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++)
- {
+ for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
struct device *dev = &dev_ultra[this_dev];
- if (dev->priv != NULL)
- {
+ if (dev->priv != NULL) {
void *priv = dev->priv;
/* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
+ mca_mark_as_unused(ei_status.priv);
release_region(ioaddr, ULTRA_IO_EXTENT);
unregister_netdev(dev);
kfree(priv);
@@ -382,7 +510,6 @@
unlock_8390_module();
}
#endif /* MODULE */
-
/*
* Local variables:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)