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

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		= &etherh_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)