patch-2.4.9 linux/drivers/acorn/net/etherh.c
Next file: linux/drivers/acorn/scsi/acornscsi.c
Previous file: linux/drivers/acorn/char/mouse_ps2.c
Back to the patch index
Back to the overall index
- Lines: 527
- Date:
Sun Aug 12 10:38:48 2001
- Orig file:
v2.4.8/linux/drivers/acorn/net/etherh.c
- Orig date:
Fri Feb 9 11:30:22 2001
diff -u --recursive --new-file v2.4.8/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c
@@ -7,10 +7,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * NS8390 ANT etherh specific driver
- * For Acorn machines
- *
+ * NS8390 I-cubed EtherH and ANT EtherM specific driver
* Thanks to I-Cubed for information on their cards.
+ * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton
+ * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan)
+ * EtherM integration re-engineered by Russell King.
*
* Changelog:
* 08-12-1996 RMK 1.00 Created
@@ -19,12 +20,9 @@
* 16-04-1998 RMK 1.05 Improved media autodetection
* 10-02-2000 RMK 1.06 Updated for 2.3.43
* 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8
- *
- * Insmod Module Parameters
- * ------------------------
- * io=<io_base>
- * irq=<irqno>
- * xcvr=<0|1> 0 = 10bT, 1=10b2 (Lan600/600A only)
+ * 12-10-1999 CK/TEW EtherM driver first release
+ * 21-12-2000 TTC EtherH/EtherM integration
+ * 25-12-2000 RMK 1.08 Clean integration of EtherM into this driver.
*/
#include <linux/module.h>
@@ -57,18 +55,21 @@
#define DEBUG_INIT 2
static unsigned int net_debug = NET_DEBUG;
+
static const card_ids __init etherh_cids[] = {
- { MANU_I3, PROD_I3_ETHERLAN500 },
- { MANU_I3, PROD_I3_ETHERLAN600 },
- { MANU_I3, PROD_I3_ETHERLAN600A },
- { 0xffff, 0xffff }
+ { MANU_ANT, PROD_ANT_ETHERM },
+ { MANU_I3, PROD_I3_ETHERLAN500 },
+ { MANU_I3, PROD_I3_ETHERLAN600 },
+ { MANU_I3, PROD_I3_ETHERLAN600A },
+ { 0xffff, 0xffff }
};
+
MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("i3 EtherH driver");
+MODULE_DESCRIPTION("EtherH/EtherM driver");
-static const char version[] __initdata =
- "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.07\n";
+static char version[] __initdata =
+ "EtherH/EtherM Driver (c) 2000 Russell King v1.08\n";
#define ETHERH500_DATAPORT 0x200 /* MEMC */
#define ETHERH500_NS8390 0x000 /* MEMC */
@@ -83,13 +84,24 @@
#define ETHERH_CP_HEARTBEAT 2
#define ETHERH_TX_START_PAGE 1
-#define ETHERH_STOP_PAGE 0x7f
+#define ETHERH_STOP_PAGE 127
+
+/*
+ * These came from CK/TEW
+ */
+#define ETHERM_DATAPORT 0x080 /* MEMC */
+#define ETHERM_NS8390 0x200 /* MEMC */
+#define ETHERM_CTRLPORT 0x08f /* MEMC */
+
+#define ETHERM_TX_START_PAGE 64
+#define ETHERM_STOP_PAGE 127
/* --------------------------------------------------------------------------- */
static void
etherh_setif(struct net_device *dev)
{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
unsigned long addr, flags;
save_flags_cli(flags);
@@ -133,6 +145,7 @@
static int
etherh_getifstat(struct net_device *dev)
{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
int stat = 0;
switch (dev->mem_end) {
@@ -199,6 +212,8 @@
static void
etherh_reset(struct net_device *dev)
{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
/*
@@ -206,8 +221,8 @@
* Note that we use 'interface_num' as a flag
* to indicate that we need to change the media.
*/
- if (dev->flags & IFF_AUTOMEDIA && ei_status.interface_num) {
- ei_status.interface_num = 0;
+ if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) {
+ ei_local->interface_num = 0;
if (dev->if_port == IF_PORT_10BASET)
dev->if_port = IF_PORT_10BASE2;
@@ -224,17 +239,18 @@
static void
etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page)
{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
unsigned int addr, dma_addr;
unsigned long dma_start;
-
- if (ei_status.dmaing) {
- printk ("%s: DMAing conflict in etherh_block_input: "
+
+ if (ei_local->dmaing) {
+ printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: "
" DMAstat %d irqlock %d\n", dev->name,
- ei_status.dmaing, ei_status.irqlock);
+ ei_local->dmaing, ei_local->irqlock);
return;
}
- ei_status.dmaing |= 1;
+ ei_local->dmaing |= 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
@@ -257,7 +273,7 @@
outb (start_page, addr + EN0_RSARHI);
outb (E8390_RWRITE | E8390_START, addr + E8390_CMD);
- if (ei_status.word16)
+ if (ei_local->word16)
outsw (dma_addr, buf, count >> 1);
else
outsb (dma_addr, buf, count);
@@ -266,14 +282,15 @@
while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0)
if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
- printk ("%s: timeout waiting for TX RDC\n", dev->name);
+ printk(KERN_ERR "%s: timeout waiting for TX RDC\n",
+ dev->name);
etherh_reset (dev);
NS8390_init (dev, 1);
break;
}
outb (ENISR_RDC, addr + EN0_ISR);
- ei_status.dmaing &= ~1;
+ ei_local->dmaing &= ~1;
}
/*
@@ -282,17 +299,18 @@
static void
etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
unsigned int addr, dma_addr;
unsigned char *buf;
- if (ei_status.dmaing) {
- printk ("%s: DMAing conflict in etherh_block_input: "
+ if (ei_local->dmaing) {
+ printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: "
" DMAstat %d irqlock %d\n", dev->name,
- ei_status.dmaing, ei_status.irqlock);
+ ei_local->dmaing, ei_local->irqlock);
return;
}
- ei_status.dmaing |= 1;
+ ei_local->dmaing |= 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
@@ -305,7 +323,7 @@
outb (ring_offset >> 8, addr + EN0_RSARHI);
outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
- if (ei_status.word16) {
+ if (ei_local->word16) {
insw (dma_addr, buf, count >> 1);
if (count & 1)
buf[count - 1] = inb (dma_addr);
@@ -313,7 +331,7 @@
insb (dma_addr, buf, count);
outb (ENISR_RDC, addr + EN0_ISR);
- ei_status.dmaing &= ~1;
+ ei_local->dmaing &= ~1;
}
/*
@@ -322,16 +340,17 @@
static void
etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
unsigned int addr, dma_addr;
- if (ei_status.dmaing) {
- printk ("%s: DMAing conflict in etherh_get_header: "
+ if (ei_local->dmaing) {
+ printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: "
" DMAstat %d irqlock %d\n", dev->name,
- ei_status.dmaing, ei_status.irqlock);
+ ei_local->dmaing, ei_local->irqlock);
return;
}
- ei_status.dmaing |= 1;
+ ei_local->dmaing |= 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
@@ -343,13 +362,13 @@
outb (ring_page, addr + EN0_RSARHI);
outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
- if (ei_status.word16)
+ if (ei_local->word16)
insw (dma_addr, hdr, sizeof (*hdr) >> 1);
else
insb (dma_addr, hdr, sizeof (*hdr));
outb (ENISR_RDC, addr + EN0_ISR);
- ei_status.dmaing &= ~1;
+ ei_local->dmaing &= ~1;
}
/*
@@ -363,7 +382,9 @@
static int
etherh_open(struct net_device *dev)
{
- if (request_irq(dev->irq, ei_interrupt, 0, "etherh", dev))
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
return -EAGAIN;
/*
@@ -371,7 +392,7 @@
* media type on the next reset - we are about to
* do automedia manually now.
*/
- ei_status.interface_num = 0;
+ ei_local->interface_num = 0;
/*
* If we are doing automedia detection, do it now.
@@ -431,36 +452,7 @@
static int version_printed;
if (net_debug && version_printed++ == 0)
- printk(version);
-}
-
-static int __init etherh_check_presence(struct net_device *dev)
-{
- unsigned int addr = dev->base_addr, reg0, tmp;
-
- reg0 = inb(addr);
- if (reg0 == 0xff) {
- if (net_debug & DEBUG_INIT)
- printk("%s: etherh error: NS8390 command register wrong\n",
- dev->name);
- return -ENODEV;
- }
-
- outb(E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD);
- tmp = inb(addr + 13);
- outb(0xff, addr + 13);
- outb(E8390_NODMA | E8390_PAGE0, addr + E8390_CMD);
- inb(addr + EN0_COUNTER0);
- if (inb(addr + EN0_COUNTER0) != 0) {
- if (net_debug & DEBUG_INIT)
- printk("%s: etherh error: NS8390 not found\n",
- dev->name);
- outb(reg0, addr);
- outb(tmp, addr + 13);
- return -ENODEV;
- }
-
- return 0;
+ printk(KERN_INFO "%s", version);
}
/*
@@ -485,11 +477,36 @@
return ENODEV;
}
+/*
+ * Create an ethernet address from the system serial number.
+ */
+static int __init etherm_addr(char *addr)
+{
+ unsigned int serial;
+
+ if (system_serial_low == 0 && system_serial_high == 0)
+ return ENODEV;
+
+ serial = system_serial_low | system_serial_high;
+
+ addr[0] = 0;
+ addr[1] = 0;
+ addr[2] = 0xa4;
+ addr[3] = 0x10 + (serial >> 24);
+ addr[4] = serial >> 16;
+ addr[5] = serial >> 8;
+ return 0;
+}
+
+static u32 etherh_regoffsets[16];
+static u32 etherm_regoffsets[16];
+
static struct net_device * __init etherh_init_one(struct expansion_card *ec)
{
+ struct ei_device *ei_local;
struct net_device *dev;
const char *dev_type;
- int i;
+ int i, size;
etherh_banner();
@@ -501,8 +518,6 @@
SET_MODULE_OWNER(dev);
- etherh_addr(dev->dev_addr, ec);
-
dev->open = etherh_open;
dev->stop = etherh_close;
dev->set_config = etherh_set_config;
@@ -512,7 +527,17 @@
ec->ops = ðerh_ops;
switch (ec->cid.product) {
+ case PROD_ANT_ETHERM:
+ if (etherm_addr(dev->dev_addr))
+ goto free;
+ dev->base_addr += ETHERM_NS8390;
+ dev->mem_start = dev->base_addr + ETHERM_DATAPORT;
+ ec->irq_data = (void *)(dev->base_addr + ETHERM_CTRLPORT);
+ break;
+
case PROD_I3_ETHERLAN500:
+ if (etherh_addr(dev->dev_addr, ec))
+ goto free;
dev->base_addr += ETHERH500_NS8390;
dev->mem_start = dev->base_addr + ETHERH500_DATAPORT;
dev->rmem_start = (unsigned long)
@@ -522,34 +547,54 @@
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
+ if (etherh_addr(dev->dev_addr, ec))
+ goto free;
dev->base_addr += ETHERH600_NS8390;
dev->mem_start = dev->base_addr + ETHERH600_DATAPORT;
ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT);
break;
default:
- printk("%s: etherh error: unknown card type %x\n",
+ printk(KERN_ERR "%s: unknown card type %x\n",
dev->name, ec->cid.product);
- goto out;
+ goto free;
}
- if (!request_region(dev->base_addr, 16, dev->name))
- goto region_not_free;
+ size = 16;
+ if (ec->cid.product == PROD_ANT_ETHERM)
+ size <<= 3;
+
+ if (!request_region(dev->base_addr, size, dev->name))
+ goto free;
- if (etherh_check_presence(dev) || ethdev_init(dev))
+ if (ethdev_init(dev))
goto release;
+ /*
+ * Unfortunately, ethdev_init eventually calls
+ * ether_setup, which re-writes dev->flags.
+ */
switch (ec->cid.product) {
+ case PROD_ANT_ETHERM:
+ dev_type = "ANT EtherM";
+ dev->if_port = IF_PORT_UNKNOWN;
+ break;
+
case PROD_I3_ETHERLAN500:
- dev_type = "500";
+ dev_type = "i3 EtherH 500";
+ dev->if_port = IF_PORT_UNKNOWN;
break;
case PROD_I3_ETHERLAN600:
- dev_type = "600";
+ dev_type = "i3 EtherH 600";
+ dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
+ dev->if_port = IF_PORT_10BASET;
break;
case PROD_I3_ETHERLAN600A:
- dev_type = "600A";
+ dev_type = "i3 EtherH 600A";
+ dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
+ dev->if_port = IF_PORT_10BASET;
break;
default:
@@ -557,39 +602,31 @@
break;
}
- printk("%s: etherh %s at %lx, IRQ%d, ether address ",
- dev->name, dev_type, dev->base_addr, dev->irq);
+ printk(KERN_INFO "%s: %s in slot %d, ",
+ dev->name, dev_type, ec->slot_no);
for (i = 0; i < 6; i++)
- printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
- /*
- * Unfortunately, ethdev_init eventually calls
- * ether_setup, which re-writes dev->flags.
- */
- switch (ec->cid.product) {
- case PROD_I3_ETHERLAN500:
- dev->if_port = IF_PORT_UNKNOWN;
- break;
-
- case PROD_I3_ETHERLAN600:
- case PROD_I3_ETHERLAN600A:
- dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
- dev->if_port = IF_PORT_10BASET;
- break;
- }
-
- ei_status.name = dev->name;
- ei_status.word16 = 1;
- ei_status.tx_start_page = ETHERH_TX_START_PAGE;
- ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
- ei_status.stop_page = ETHERH_STOP_PAGE;
-
- ei_status.reset_8390 = etherh_reset;
- ei_status.block_input = etherh_block_input;
- ei_status.block_output = etherh_block_output;
- ei_status.get_8390_hdr = etherh_get_header;
- ei_status.interface_num = 0;
+ ei_local = (struct ei_device *) dev->priv;
+ if (ec->cid.product == PROD_ANT_ETHERM) {
+ ei_local->tx_start_page = ETHERM_TX_START_PAGE;
+ ei_local->stop_page = ETHERM_STOP_PAGE;
+ ei_local->reg_offset = etherm_regoffsets;
+ } else {
+ ei_local->tx_start_page = ETHERH_TX_START_PAGE;
+ ei_local->stop_page = ETHERH_STOP_PAGE;
+ ei_local->reg_offset = etherh_regoffsets;
+ }
+
+ ei_local->name = dev->name;
+ ei_local->word16 = 1;
+ ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES;
+ ei_local->reset_8390 = etherh_reset;
+ ei_local->block_input = etherh_block_input;
+ ei_local->block_output = etherh_block_output;
+ ei_local->get_8390_hdr = etherh_get_header;
+ ei_local->interface_num = 0;
etherh_reset(dev);
NS8390_init(dev, 0);
@@ -597,7 +634,7 @@
release:
release_region(dev->base_addr, 16);
-region_not_free:
+free:
unregister_netdev(dev);
kfree(dev);
out:
@@ -614,6 +651,11 @@
{
int i, ret = -ENODEV;
+ for (i = 0; i < 16; i++) {
+ etherh_regoffsets[i] = i;
+ etherm_regoffsets[i] = i << 3;
+ }
+
ecard_startfind();
for (i = 0; i < MAX_ECARDS; i++) {
@@ -642,8 +684,12 @@
for (i = 0; i < MAX_ETHERH_CARDS; i++) {
if (e_dev[i]) {
+ int size;
unregister_netdev(e_dev[i]);
- release_region(e_dev[i]->base_addr, 16);
+ size = 16;
+ if (e_card[i]->cid.product == PROD_ANT_ETHERM)
+ size <<= 3;
+ release_region(e_dev[i]->base_addr, size);
kfree(e_dev[i]);
e_dev[i] = NULL;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)