patch-2.0.37 linux/drivers/net/depca.c
Next file: linux/drivers/net/dgrs.c
Previous file: linux/drivers/net/de4x5.h
Back to the patch index
Back to the overall index
- Lines: 632
- Date:
Sun Jun 13 10:21:01 1999
- Orig file:
v2.0.36/linux/drivers/net/depca.c
- Orig date:
Tue Apr 8 08:47:45 1997
diff -u --recursive --new-file v2.0.36/linux/drivers/net/depca.c linux/drivers/net/depca.c
@@ -154,7 +154,20 @@
the 'memory autoprobe' picking the wrong shared memory (for the case of
2 depca's in a PC).
+ ************************************************************************
+ Support for MCA EtherWORKS cards added 11-3-98.
+ Verified to work with up to 2 DE212 cards in a system (although not
+ fully stress-tested).
+
+ Currently known bugs/limitations:
+
+ Note: with the MCA stuff as a module, it trusts the MCA configuration,
+ not the command line for IRQ and memory address. You can
+ specify them if you want, but it will throw your values out.
+ You still have to pass the IO address it was configured as
+ though.
+ ************************************************************************
TO DO:
------
@@ -202,11 +215,16 @@
0.422 29-Apr-96 Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
0.423 7-Jun-96 Fix module load bug <kmg@barco.be>
0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
+ 0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
+ reported by <mmogilvi@elbert.uccs.edu>
+ 0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
+ by <tymm@computer.org>
+ 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
=========================================================================
*/
-static const char *version = "depca.c:v0.43 96/8/16 davies@maniac.ultranet.com\n";
+static const char *version = "depca.c:v0.451 1998/11/14 davies@maniac.ultranet.com\n";
#include <linux/module.h>
@@ -233,6 +251,10 @@
#include <linux/unistd.h>
#include <linux/ctype.h>
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
+
#include "depca.h"
#ifdef DEPCA_DEBUG
@@ -280,15 +302,20 @@
static short mem_chkd = 0;
/*
+** Adapter ID for the MCA EtherWORKS DE210/212 adapter
+*/
+#define DE212_ID 0x6def
+
+/*
** Name <-> Adapter mapping
*/
#define DEPCA_SIGNATURE {"DEPCA",\
"DE100","DE101",\
"DE200","DE201","DE202",\
- "DE210",\
+ "DE210","DE212",\
"DE422",\
""}
-static enum {DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown} adapter;
+static enum {DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown} adapter;
/*
** Miscellaneous info...
@@ -342,7 +369,7 @@
char devname[DEPCA_STRLEN]; /* Device Product String */
char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */
char adapter; /* Adapter type */
- struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
+ char mca_slot; /* MCA slot, if MCA else -1 */ struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
struct depca_init init_block;/* Shadow Initialization block */
char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
@@ -393,7 +420,7 @@
/*
** Private functions
*/
-static int depca_hw_init(struct device *dev, u_long ioaddr);
+static int depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot);
static void depca_init_ring(struct device *dev);
static int depca_rx(struct device *dev);
static int depca_tx(struct device *dev);
@@ -407,6 +434,9 @@
static void SetMulticastFilter(struct device *dev);
static void isa_probe(struct device *dev, u_long iobase);
static void eisa_probe(struct device *dev, u_long iobase);
+#ifdef CONFIG_MCA
+static void mca_probe(struct device *dev, u_long iobase);
+#endif
static struct device *alloc_device(struct device *dev, u_long iobase);
static int depca_dev_index(char *s);
static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *));
@@ -441,7 +471,8 @@
-int depca_probe(struct device *dev)
+int
+depca_probe(struct device *dev)
{
int tmp = num_depcas, status = -ENODEV;
u_long iobase = dev->base_addr;
@@ -450,6 +481,9 @@
printk("Autoprobing is not supported when loading a module based driver.\n");
status = -EIO;
} else {
+#ifdef CONFIG_MCA
+ mca_probe(dev, iobase);
+#endif
isa_probe(dev, iobase);
eisa_probe(dev, iobase);
@@ -472,7 +506,7 @@
}
static int
-depca_hw_init(struct device *dev, u_long ioaddr)
+depca_hw_init(struct device *dev, u_long ioaddr, int mca_slot)
{
struct depca_private *lp;
int i, j, offset, netRAM, mem_len, status=0;
@@ -495,7 +529,10 @@
if ((adapter != unknown) && mem_start) { /* found a DEPCA device */
dev->base_addr = ioaddr;
- if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
+ if (mca_slot != -1) {
+ printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name,
+ ioaddr, mca_slot);
+ } else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */
printk("%s: %s at 0x%04lx (EISA slot %d)",
dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
} else { /* ISA port address */
@@ -541,7 +578,8 @@
lp = (struct depca_private *)dev->priv;
memset((char *)dev->priv, 0, sizeof(struct depca_private));
lp->adapter = adapter;
- sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+ lp->mca_slot = mca_slot;
+ sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
/* Initialisation Block */
@@ -603,6 +641,7 @@
case de201:
case de202:
case de210:
+ case de212:
depca_irq = de2xx_irq;
break;
case de422:
@@ -1205,10 +1244,161 @@
return;
}
+#ifdef CONFIG_MCA
+/*
+** Microchannel bus I/O device probe
+*/
+static void
+mca_probe(struct device *dev, u_long ioaddr)
+{
+ unsigned char pos[2];
+ unsigned char where;
+ unsigned long iobase;
+ int irq;
+ int slot = 0;
+
+ /*
+ ** See if we've been here before.
+ */
+ if ((!ioaddr && autoprobed) || (ioaddr && !loading_module)) return;
+
+ if (MCA_bus) {
+ /*
+ ** Search for the adapter. If an address has been given, search
+ ** specifically for the card at that address. Otherwise find the
+ ** first card in the system.
+ */
+ while ((dev!=NULL) &&
+ ((slot=mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
+ pos[0] = mca_read_stored_pos(slot, 2);
+ pos[1] = mca_read_stored_pos(slot, 3);
+
+ /*
+ ** IO of card is handled by bits 1 and 2 of pos0.
+ **
+ ** bit2 bit1 IO
+ ** 0 0 0x2c00
+ ** 0 1 0x2c10
+ ** 1 0 0x2c20
+ ** 1 1 0x2c30
+ */
+ where = (pos[0] & 6) >> 1;
+ iobase = 0x2c00 + (0x10 * where);
+
+ if ((ioaddr) && (ioaddr != iobase)) {
+ /*
+ ** Card was found, but not at the right IO location. Continue
+ ** scanning from the next MCA slot up for another card.
+ */
+ slot++;
+ continue;
+ }
+
+ /*
+ ** Found the adapter we were looking for. Now start setting it up.
+ **
+ ** First work on decoding the IRQ. It's stored in the lower 4 bits
+ ** of pos1. Bits are as follows (from the ADF file):
+ **
+ ** Bits
+ ** 3 2 1 0 IRQ
+ ** --------------------
+ ** 0 0 1 0 5
+ ** 0 0 0 1 9
+ ** 0 1 0 0 10
+ ** 1 0 0 0 11
+ **/
+ where = pos[1] & 0x0f;
+ switch(where) {
+ case 1:
+ irq = 9;
+ break;
+ case 2:
+ irq = 5;
+ break;
+ case 4:
+ irq = 10;
+ break;
+ case 8:
+ irq = 11;
+ break;
+ default:
+ printk("%s: mca_probe IRQ error. You should never get here (%d).\n", dev->name, where);
+ return;
+ }
+
+ /*
+ ** Shared memory address of adapter is stored in bits 3-5 of pos0.
+ ** They are mapped as follows:
+ **
+ ** Bit
+ ** 5 4 3 Memory Addresses
+ ** 0 0 0 C0000-CFFFF (64K)
+ ** 1 0 0 C8000-CFFFF (32K)
+ ** 0 0 1 D0000-DFFFF (64K)
+ ** 1 0 1 D8000-DFFFF (32K)
+ ** 0 1 0 E0000-EFFFF (64K)
+ ** 1 1 0 E8000-EFFFF (32K)
+ */
+ where = (pos[0] & 0x18) >> 3;
+ mem = 0xc0000 + (where * 0x10000);
+ if (pos[0] & 0x20) {
+ mem += 0x8000;
+ }
+
+ /*
+ ** Get everything allocated and initialized... (almost just
+ ** like the ISA and EISA probes)
+ */
+ if (DevicePresent(iobase) != 0) {
+ /*
+ ** If the MCA configuration says the card should be here,
+ ** it really should be here.
+ */
+ printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not
+responding.\n", dev->name, iobase);
+ }
+
+ if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, iobase)) != NULL) {
+ dev->irq = irq;
+ if (depca_hw_init(dev, iobase, slot) == 0) {
+ /*
+ ** Adapter initialized correctly: Name it in
+ ** /proc/mca.
+ */
+ mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
+ mca_mark_as_used(slot);
+ num_depcas++;
+ }
+ num_eth++;
+ }
+ } else if (autoprobed) {
+ printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+ }
+
+ /*
+ ** If this is a probe by a module, return after setting up the
+ ** given card.
+ */
+ if (ioaddr) return;
+
+ /*
+ ** Set up to check the next slot and loop.
+ */
+ slot++;
+ }
+ }
+
+ return;
+}
+#endif
+
/*
** ISA bus I/O device probe
*/
-static void isa_probe(struct device *dev, u_long ioaddr)
+static void
+isa_probe(struct device *dev, u_long ioaddr)
{
int i = num_depcas, maxSlots;
s32 ports[] = DEPCA_IO_PORTS;
@@ -1225,17 +1415,17 @@
}
for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
- if (DevicePresent(ports[i]) == 0) {
- if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+ if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+ if (DevicePresent(ports[i]) == 0) {
if ((dev = alloc_device(dev, ports[i])) != NULL) {
- if (depca_hw_init(dev, ports[i]) == 0) {
+ if (depca_hw_init(dev, ports[i], -1) == 0) {
num_depcas++;
}
num_eth++;
}
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
}
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
}
}
@@ -1246,7 +1436,8 @@
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
** the motherboard. Upto 15 EISA devices are supported.
*/
-static void eisa_probe(struct device *dev, u_long ioaddr)
+static void
+eisa_probe(struct device *dev, u_long ioaddr)
{
int i, maxSlots;
u_long iobase;
@@ -1267,19 +1458,19 @@
if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
- if (EISA_signature(name, EISA_ID)) {
- if (DevicePresent(iobase) == 0) {
- if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if (EISA_signature(name, EISA_ID)) {
+ if (DevicePresent(iobase) == 0) {
if ((dev = alloc_device(dev, iobase)) != NULL) {
- if (depca_hw_init(dev, iobase) == 0) {
+ if (depca_hw_init(dev, iobase, -1) == 0) {
num_depcas++;
}
num_eth++;
}
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
}
}
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
}
}
@@ -1683,7 +1874,7 @@
/*
** Perform IOCTL call functions here. Some are privileged operations and the
** effective uid is checked in those cases.
-** All MCA IOCTLs will not work here and are for testing purposes only.
+** All multicast IOCTLs will not work here and are for testing purposes only.
*/
static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
@@ -1703,126 +1894,103 @@
tmp.addr[i] = dev->dev_addr[i];
}
ioc->len = ETH_ALEN;
- if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, tmp.addr, ioc->len);
- }
-
+ if (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT;
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
break;
+
case DEPCA_SET_HWADDR: /* Set the hardware address */
- if (suser()) {
- if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
- memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
- for (i=0; i<ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- }
- while(dev->tbusy); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
- while(lp->tx_old != lp->tx_new);/* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
- }
- } else {
- status = -EPERM;
+ if (!suser()) return -EPERM;
+ if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT;
+ memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+ for (i=0; i<ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp.addr[i];
}
+ while(dev->tbusy) barrier(); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
break;
+
case DEPCA_SET_PROM: /* Set Promiscuous Mode */
- if (suser()) {
- while(dev->tbusy); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode |= PROM; /* Set promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
- } else {
- status = -EPERM;
- }
+ if (!suser()) return -EPERM;
+ while(dev->tbusy) barrier(); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode |= PROM; /* Set promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
break;
+
case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
- if (suser()) {
- while(dev->tbusy); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
- } else {
- status = -EPERM;
- }
+ if (!suser()) return -EPERM;
+ while(dev->tbusy) barrier(); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
break;
+
case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
printk("%s: Boo!\n", dev->name);
-
break;
+
case DEPCA_GET_MCA: /* Get the multicast address table */
ioc->len = (HASH_TABLE_LEN >> 3);
- if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len);
- }
-
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+ memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len);
break;
- case DEPCA_SET_MCA: /* Set a multicast address */
- if (suser()) {
- if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) {
- memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
- set_multicast_list(dev);
- }
- } else {
- status = -EPERM;
- }
+ case DEPCA_SET_MCA: /* Set a multicast address */
+ if (!suser()) return -EPERM;
+ if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT;
+ memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+ set_multicast_list(dev);
break;
- case DEPCA_CLR_MCA: /* Clear all multicast addresses */
- if (suser()) {
- set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
+ case DEPCA_CLR_MCA: /* Clear all multicast addresses */
+ if (!suser()) return -EPERM;
+ set_multicast_list(dev);
break;
+
case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
- if (suser()) {
+ if (!suser()) return -EPERM;
set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
-
break;
+
case DEPCA_GET_STATS: /* Get the driver statistics */
cli();
ioc->len = sizeof(lp->pktStats);
- if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) {
+ status = -EFAULT;
+ } else {
+ memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
}
sti();
-
break;
- case DEPCA_CLR_STATS: /* Zero out the driver statistics */
- if (suser()) {
- cli();
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- sti();
- } else {
- status = -EPERM;
- }
+ case DEPCA_CLR_STATS: /* Zero out the driver statistics */
+ if (!suser()) return -EPERM;
+ cli();
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ sti();
break;
+
case DEPCA_GET_REG: /* Get the DEPCA Registers */
i=0;
tmp.sval[i++] = inw(DEPCA_NICSR);
@@ -1830,25 +1998,25 @@
tmp.sval[i++] = inw(DEPCA_DATA);
memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
ioc->len = i+sizeof(struct depca_init);
- if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
- memcpy_tofs(ioc->data, tmp.addr, ioc->len);
- }
-
+ if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
break;
+
default:
- status = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
return status;
}
#ifdef MODULE
-static char devicename[9] = { 0, };
+static char devicename[9] = {0,};
static struct device thisDepca = {
devicename, /* device name is inserted by /linux/drivers/net/net_init.c */
0, 0, 0, 0,
0x200, 7, /* I/O address, IRQ */
- 0, 0, 0, NULL, depca_probe };
+ 0, 0, 0, NULL, depca_probe
+};
static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
static int io=0x200; /* Or use the irq= io= options to insmod */
@@ -1869,8 +2037,13 @@
void
cleanup_module(void)
{
- if (thisDepca.priv) {
- kfree(thisDepca.priv);
+ struct depca_private *lp = thisDepca.priv;
+ if (lp) {
+#ifdef CONFIG_MCA
+ if(lp->mca_slot != -1)
+ mca_mark_as_unused(lp->mca_slot);
+#endif
+ kfree(lp);
thisDepca.priv = NULL;
}
thisDepca.irq=0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov