patch-2.4.22 linux-2.4.22/drivers/acorn/net/etherh.c
Next file: linux-2.4.22/drivers/acorn/scsi/arxescsi.c
Previous file: linux-2.4.22/drivers/acorn/net/ether3.c
Back to the patch index
Back to the overall index
- Lines: 411
- Date:
2003-08-25 04:44:40.000000000 -0700
- Orig file:
linux-2.4.21/drivers/acorn/net/etherh.c
- Orig date:
2002-08-02 17:39:43.000000000 -0700
diff -urN linux-2.4.21/drivers/acorn/net/etherh.c linux-2.4.22/drivers/acorn/net/etherh.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/acorn/net/etherh.c
*
- * Copyright (C) 2000 Russell King
+ * Copyright (C) 2000-2002 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,6 +23,7 @@
* 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.
+ * 03-01-2002 RMK 1.09 Always enable IRQs if we're in the nic slot.
*/
#include <linux/module.h>
@@ -64,13 +65,18 @@
{ 0xffff, 0xffff }
};
+struct etherh_priv {
+ unsigned int id;
+ unsigned int ctrl_port;
+ unsigned int ctrl;
+};
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("EtherH/EtherM driver");
MODULE_LICENSE("GPL");
static char version[] __initdata =
- "EtherH/EtherM Driver (c) 2000 Russell King v1.08\n";
+ "EtherH/EtherM Driver (c) 2002 Russell King v1.09\n";
#define ETHERH500_DATAPORT 0x200 /* MEMC */
#define ETHERH500_NS8390 0x000 /* MEMC */
@@ -97,18 +103,61 @@
#define ETHERM_TX_START_PAGE 64
#define ETHERM_STOP_PAGE 127
-/* --------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------ */
+
+static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned int mask)
+{
+ eh->ctrl |= mask;
+ outb(eh->ctrl, eh->ctrl_port);
+}
+
+static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned int mask)
+{
+ eh->ctrl &= ~mask;
+ outb(eh->ctrl, eh->ctrl_port);
+}
+
+static inline unsigned int etherh_get_stat(struct etherh_priv *eh)
+{
+ return inb(eh->ctrl_port);
+}
+
+
+
+
+static void etherh_irq_enable(ecard_t *ec, int irqnr)
+{
+ struct etherh_priv *eh = ec->irq_data;
+
+ etherh_set_ctrl(eh, ETHERH_CP_IE);
+}
+
+static void etherh_irq_disable(ecard_t *ec, int irqnr)
+{
+ struct etherh_priv *eh = ec->irq_data;
+
+ etherh_clr_ctrl(eh, ETHERH_CP_IE);
+}
+
+static expansioncard_ops_t etherh_ops = {
+ irqenable: etherh_irq_enable,
+ irqdisable: etherh_irq_disable,
+};
+
+
+
static void
etherh_setif(struct net_device *dev)
{
struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ struct etherh_priv *eh = (struct etherh_priv *)dev->rmem_start;
unsigned long addr, flags;
save_flags_cli(flags);
/* set the interface type */
- switch (dev->mem_end) {
+ switch (eh->id) {
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
addr = dev->base_addr + EN0_RCNTHI;
@@ -124,14 +173,13 @@
break;
case PROD_I3_ETHERLAN500:
- addr = dev->rmem_start;
-
switch (dev->if_port) {
case IF_PORT_10BASE2:
- outb(inb(addr) & ~ETHERH_CP_IF, addr);
+ etherh_clr_ctrl(eh, ETHERH_CP_IF);
break;
+
case IF_PORT_10BASET:
- outb(inb(addr) | ETHERH_CP_IF, addr);
+ etherh_set_ctrl(eh, ETHERH_CP_IF);
break;
}
break;
@@ -147,9 +195,10 @@
etherh_getifstat(struct net_device *dev)
{
struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ struct etherh_priv *eh = (struct etherh_priv *)dev->rmem_start;
int stat = 0;
- switch (dev->mem_end) {
+ switch (eh->id) {
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
switch (dev->if_port) {
@@ -168,7 +217,7 @@
stat = 1;
break;
case IF_PORT_10BASET:
- stat = inb(dev->rmem_start) & ETHERH_CP_HEARTBEAT;
+ stat = etherh_get_stat(eh) & ETHERH_CP_HEARTBEAT;
break;
}
break;
@@ -251,7 +300,13 @@
return;
}
- ei_local->dmaing |= 1;
+ /*
+ * Make sure we have a round number of bytes if we're in word mode.
+ */
+ if (count & 1 && ei_local->word16)
+ count++;
+
+ ei_local->dmaing = 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
@@ -291,7 +346,7 @@
}
outb (ENISR_RDC, addr + EN0_ISR);
- ei_local->dmaing &= ~1;
+ ei_local->dmaing = 0;
}
/*
@@ -311,7 +366,7 @@
return;
}
- ei_local->dmaing |= 1;
+ ei_local->dmaing = 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
@@ -332,7 +387,7 @@
insb (dma_addr, buf, count);
outb (ENISR_RDC, addr + EN0_ISR);
- ei_local->dmaing &= ~1;
+ ei_local->dmaing = 0;
}
/*
@@ -351,7 +406,7 @@
return;
}
- ei_local->dmaing |= 1;
+ ei_local->dmaing = 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
@@ -369,7 +424,7 @@
insb (dma_addr, hdr, sizeof (*hdr));
outb (ENISR_RDC, addr + EN0_ISR);
- ei_local->dmaing &= ~1;
+ ei_local->dmaing = 0;
}
/*
@@ -385,6 +440,12 @@
{
struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_WARNING "%s: invalid ethernet address\n",
+ dev->name);
+ return -EINVAL;
+ }
+
if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
return -EAGAIN;
@@ -427,22 +488,22 @@
return 0;
}
-static void etherh_irq_enable(ecard_t *ec, int irqnr)
+static int
+etherh_set_mac_address(struct net_device *dev, void *p)
{
- unsigned int ctrl_addr = (unsigned int)ec->irq_data;
- outb(inb(ctrl_addr) | ETHERH_CP_IE, ctrl_addr);
-}
+ struct sockaddr *addr = p;
-static void etherh_irq_disable(ecard_t *ec, int irqnr)
-{
- unsigned int ctrl_addr = (unsigned int)ec->irq_data;
- outb(inb(ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr);
-}
+ if (netif_running(dev))
+ return -EBUSY;
-static expansioncard_ops_t etherh_ops = {
- irqenable: etherh_irq_enable,
- irqdisable: etherh_irq_disable,
-};
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /*
+ * We'll set the MAC address on the chip when we open it.
+ */
+
+ return 0;
+}
/*
* Initialisation
@@ -460,11 +521,13 @@
* Read the ethernet address string from the on board rom.
* This is an ascii string...
*/
-static int __init etherh_addr(char *addr, struct expansion_card *ec)
+static void __init etherh_addr(char *addr, struct expansion_card *ec)
{
struct in_chunk_dir cd;
char *s;
+ memset(addr, 0, 6);
+
if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
int i;
for (i = 0; i < 6; i++) {
@@ -472,31 +535,25 @@
if (*s != (i == 5? ')' : ':'))
break;
}
- if (i == 6)
- return 0;
}
- return -ENODEV;
}
/*
* Create an ethernet address from the system serial number.
*/
-static int __init etherm_addr(char *addr)
+static void __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;
+ if (serial != 0) {
+ addr[0] = 0;
+ addr[1] = 0;
+ addr[2] = 0xa4;
+ addr[3] = 0x10 + (serial >> 24);
+ addr[4] = serial >> 16;
+ addr[5] = serial >> 8;
+ }
}
static u32 etherh_regoffsets[16];
@@ -506,6 +563,7 @@
{
struct ei_device *ei_local;
struct net_device *dev;
+ struct etherh_priv *eh;
const char *dev_type;
int i, size;
@@ -517,42 +575,50 @@
if (!dev)
goto out;
+ eh = kmalloc(sizeof(struct etherh_priv), GFP_KERNEL);
+ if (!eh)
+ goto out_nopriv;
+
SET_MODULE_OWNER(dev);
- dev->open = etherh_open;
- dev->stop = etherh_close;
- dev->set_config = etherh_set_config;
- dev->irq = ec->irq;
- dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
- dev->mem_end = ec->cid.product;
+ dev->open = etherh_open;
+ dev->stop = etherh_close;
+ dev->set_mac_address = etherh_set_mac_address;
+ dev->set_config = etherh_set_config;
+ dev->irq = ec->irq;
+ dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
+ dev->rmem_start = (unsigned long)eh;
+
+ /*
+ * IRQ and control port handling
+ */
ec->ops = ðerh_ops;
+ ec->irq_data = eh;
+ eh->ctrl = 0;
+ eh->id = ec->cid.product;
switch (ec->cid.product) {
case PROD_ANT_ETHERM:
- if (etherm_addr(dev->dev_addr))
- goto free;
+ etherm_addr(dev->dev_addr);
dev->base_addr += ETHERM_NS8390;
dev->mem_start = dev->base_addr + ETHERM_DATAPORT;
- ec->irq_data = (void *)(dev->base_addr + ETHERM_CTRLPORT);
+ eh->ctrl_port = dev->base_addr + ETHERM_CTRLPORT;
break;
case PROD_I3_ETHERLAN500:
- if (etherh_addr(dev->dev_addr, ec))
- goto free;
+ etherh_addr(dev->dev_addr, ec);
dev->base_addr += ETHERH500_NS8390;
dev->mem_start = dev->base_addr + ETHERH500_DATAPORT;
- dev->rmem_start = (unsigned long)
- ec->irq_data = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST)
+ eh->ctrl_port = ecard_address (ec, ECARD_IOC, ECARD_FAST)
+ ETHERH500_CTRLPORT;
break;
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
- if (etherh_addr(dev->dev_addr, ec))
- goto free;
+ etherh_addr(dev->dev_addr, ec);
dev->base_addr += ETHERH600_NS8390;
- dev->mem_start = dev->base_addr + ETHERH600_DATAPORT;
- ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT);
+ dev->mem_start = dev->base_addr + ETHERH600_DATAPORT;
+ eh->ctrl_port = dev->base_addr + ETHERH600_CTRLPORT;
break;
default:
@@ -572,6 +638,12 @@
goto release;
/*
+ * If we're in the NIC slot, make sure the IRQ is enabled
+ */
+ if (dev->irq == 11)
+ etherh_set_ctrl(eh, ETHERH_CP_IE);
+
+ /*
* Unfortunately, ethdev_init eventually calls
* ether_setup, which re-writes dev->flags.
*/
@@ -636,6 +708,8 @@
release:
release_region(dev->base_addr, 16);
free:
+ kfree(eh);
+out_nopriv:
unregister_netdev(dev);
kfree(dev);
out:
@@ -696,6 +770,7 @@
}
if (e_card[i]) {
e_card[i]->ops = NULL;
+ kfree(e_card[i]->irq_data);
ecard_release(e_card[i]);
e_card[i] = NULL;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)