/*
* 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
* 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>
{ 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 */
#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);
+ local_irq_save(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;
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;
break;
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
static int
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) {
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;
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;
}
outb (ENISR_RDC, addr + EN0_ISR);
- ei_local->dmaing &= ~1;
+ ei_local->dmaing = 0;
}
/*
return;
}
- ei_local->dmaing |= 1;
+ ei_local->dmaing = 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
insb (dma_addr, buf, count);
outb (ENISR_RDC, addr + EN0_ISR);
- ei_local->dmaing &= ~1;
+ ei_local->dmaing = 0;
}
/*
return;
}
- ei_local->dmaing |= 1;
+ ei_local->dmaing = 1;
addr = dev->base_addr;
dma_addr = dev->mem_start;
insb (dma_addr, hdr, sizeof (*hdr));
outb (ENISR_RDC, addr + EN0_ISR);
- ei_local->dmaing &= ~1;
+ ei_local->dmaing = 0;
}
/*
return 0;
}
-static void etherh_irq_enable(ecard_t *ec, int irqnr)
-{
- unsigned int ctrl_addr = (unsigned int)ec->irq_data;
- outb(inb(ctrl_addr) | ETHERH_CP_IE, ctrl_addr);
-}
-
-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);
-}
-
-static expansioncard_ops_t etherh_ops = {
- irqenable: etherh_irq_enable,
- irqdisable: etherh_irq_disable,
-};
-
/*
* Initialisation
*/
{
struct ei_device *ei_local;
struct net_device *dev;
+ struct etherh_priv *eh;
const char *dev_type;
int i, size;
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->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->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:
goto free;
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:
goto free;
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;
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);
+ dev->mem_start = dev->base_addr + ETHERH600_DATAPORT;
+ eh->ctrl_port = dev->base_addr + ETHERH600_CTRLPORT;
break;
default:
if (ethdev_init(dev))
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.
release:
release_region(dev->base_addr, 16);
free:
+ kfree(eh);
+out_nopriv:
unregister_netdev(dev);
kfree(dev);
out:
}
if (e_card[i]) {
e_card[i]->ops = NULL;
+ kfree(e_card[i]->irq_data);
ecard_release(e_card[i]);
e_card[i] = NULL;
}