1644570b8SJeff Kirsher /* 2644570b8SJeff Kirsher * linux/drivers/acorn/net/etherh.c 3644570b8SJeff Kirsher * 4644570b8SJeff Kirsher * Copyright (C) 2000-2002 Russell King 5644570b8SJeff Kirsher * 6644570b8SJeff Kirsher * This program is free software; you can redistribute it and/or modify 7644570b8SJeff Kirsher * it under the terms of the GNU General Public License version 2 as 8644570b8SJeff Kirsher * published by the Free Software Foundation. 9644570b8SJeff Kirsher * 10644570b8SJeff Kirsher * NS8390 I-cubed EtherH and ANT EtherM specific driver 11644570b8SJeff Kirsher * Thanks to I-Cubed for information on their cards. 12644570b8SJeff Kirsher * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton 13644570b8SJeff Kirsher * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan) 14644570b8SJeff Kirsher * EtherM integration re-engineered by Russell King. 15644570b8SJeff Kirsher * 16644570b8SJeff Kirsher * Changelog: 17644570b8SJeff Kirsher * 08-12-1996 RMK 1.00 Created 18644570b8SJeff Kirsher * RMK 1.03 Added support for EtherLan500 cards 19644570b8SJeff Kirsher * 23-11-1997 RMK 1.04 Added media autodetection 20644570b8SJeff Kirsher * 16-04-1998 RMK 1.05 Improved media autodetection 21644570b8SJeff Kirsher * 10-02-2000 RMK 1.06 Updated for 2.3.43 22644570b8SJeff Kirsher * 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8 23644570b8SJeff Kirsher * 12-10-1999 CK/TEW EtherM driver first release 24644570b8SJeff Kirsher * 21-12-2000 TTC EtherH/EtherM integration 25644570b8SJeff Kirsher * 25-12-2000 RMK 1.08 Clean integration of EtherM into this driver. 26644570b8SJeff Kirsher * 03-01-2002 RMK 1.09 Always enable IRQs if we're in the nic slot. 27644570b8SJeff Kirsher */ 28644570b8SJeff Kirsher 29644570b8SJeff Kirsher #include <linux/module.h> 30644570b8SJeff Kirsher #include <linux/kernel.h> 31644570b8SJeff Kirsher #include <linux/types.h> 32644570b8SJeff Kirsher #include <linux/fcntl.h> 33644570b8SJeff Kirsher #include <linux/interrupt.h> 34644570b8SJeff Kirsher #include <linux/ioport.h> 35644570b8SJeff Kirsher #include <linux/in.h> 36644570b8SJeff Kirsher #include <linux/string.h> 37644570b8SJeff Kirsher #include <linux/errno.h> 38644570b8SJeff Kirsher #include <linux/netdevice.h> 39644570b8SJeff Kirsher #include <linux/etherdevice.h> 40644570b8SJeff Kirsher #include <linux/ethtool.h> 41644570b8SJeff Kirsher #include <linux/skbuff.h> 42644570b8SJeff Kirsher #include <linux/delay.h> 43644570b8SJeff Kirsher #include <linux/device.h> 44644570b8SJeff Kirsher #include <linux/init.h> 45644570b8SJeff Kirsher #include <linux/bitops.h> 46644570b8SJeff Kirsher #include <linux/jiffies.h> 47644570b8SJeff Kirsher 48644570b8SJeff Kirsher #include <asm/ecard.h> 49644570b8SJeff Kirsher #include <asm/io.h> 509f97da78SDavid Howells #include <asm/system_info.h> 51644570b8SJeff Kirsher 52644570b8SJeff Kirsher #define EI_SHIFT(x) (ei_local->reg_offset[x]) 53644570b8SJeff Kirsher 54644570b8SJeff Kirsher #define ei_inb(_p) readb((void __iomem *)_p) 55644570b8SJeff Kirsher #define ei_outb(_v,_p) writeb(_v,(void __iomem *)_p) 56644570b8SJeff Kirsher #define ei_inb_p(_p) readb((void __iomem *)_p) 57644570b8SJeff Kirsher #define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p) 58644570b8SJeff Kirsher 59644570b8SJeff Kirsher #define DRV_NAME "etherh" 60644570b8SJeff Kirsher #define DRV_VERSION "1.11" 61644570b8SJeff Kirsher 62*335802d1SOlof Johansson static char version[] = 63644570b8SJeff Kirsher "EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n"; 64644570b8SJeff Kirsher 65644570b8SJeff Kirsher #include "lib8390.c" 66644570b8SJeff Kirsher 67c45f812fSMatthew Whitehead static u32 etherh_msg_enable; 68644570b8SJeff Kirsher 69644570b8SJeff Kirsher struct etherh_priv { 70644570b8SJeff Kirsher void __iomem *ioc_fast; 71644570b8SJeff Kirsher void __iomem *memc; 72644570b8SJeff Kirsher void __iomem *dma_base; 73644570b8SJeff Kirsher unsigned int id; 74644570b8SJeff Kirsher void __iomem *ctrl_port; 75644570b8SJeff Kirsher unsigned char ctrl; 76644570b8SJeff Kirsher u32 supported; 77644570b8SJeff Kirsher }; 78644570b8SJeff Kirsher 79644570b8SJeff Kirsher struct etherh_data { 80644570b8SJeff Kirsher unsigned long ns8390_offset; 81644570b8SJeff Kirsher unsigned long dataport_offset; 82644570b8SJeff Kirsher unsigned long ctrlport_offset; 83644570b8SJeff Kirsher int ctrl_ioc; 84644570b8SJeff Kirsher const char name[16]; 85644570b8SJeff Kirsher u32 supported; 86644570b8SJeff Kirsher unsigned char tx_start_page; 87644570b8SJeff Kirsher unsigned char stop_page; 88644570b8SJeff Kirsher }; 89644570b8SJeff Kirsher 90644570b8SJeff Kirsher MODULE_AUTHOR("Russell King"); 91644570b8SJeff Kirsher MODULE_DESCRIPTION("EtherH/EtherM driver"); 92644570b8SJeff Kirsher MODULE_LICENSE("GPL"); 93644570b8SJeff Kirsher 94644570b8SJeff Kirsher #define ETHERH500_DATAPORT 0x800 /* MEMC */ 95644570b8SJeff Kirsher #define ETHERH500_NS8390 0x000 /* MEMC */ 96644570b8SJeff Kirsher #define ETHERH500_CTRLPORT 0x800 /* IOC */ 97644570b8SJeff Kirsher 98644570b8SJeff Kirsher #define ETHERH600_DATAPORT 0x040 /* MEMC */ 99644570b8SJeff Kirsher #define ETHERH600_NS8390 0x800 /* MEMC */ 100644570b8SJeff Kirsher #define ETHERH600_CTRLPORT 0x200 /* MEMC */ 101644570b8SJeff Kirsher 102644570b8SJeff Kirsher #define ETHERH_CP_IE 1 103644570b8SJeff Kirsher #define ETHERH_CP_IF 2 104644570b8SJeff Kirsher #define ETHERH_CP_HEARTBEAT 2 105644570b8SJeff Kirsher 106644570b8SJeff Kirsher #define ETHERH_TX_START_PAGE 1 107644570b8SJeff Kirsher #define ETHERH_STOP_PAGE 127 108644570b8SJeff Kirsher 109644570b8SJeff Kirsher /* 110644570b8SJeff Kirsher * These came from CK/TEW 111644570b8SJeff Kirsher */ 112644570b8SJeff Kirsher #define ETHERM_DATAPORT 0x200 /* MEMC */ 113644570b8SJeff Kirsher #define ETHERM_NS8390 0x800 /* MEMC */ 114644570b8SJeff Kirsher #define ETHERM_CTRLPORT 0x23c /* MEMC */ 115644570b8SJeff Kirsher 116644570b8SJeff Kirsher #define ETHERM_TX_START_PAGE 64 117644570b8SJeff Kirsher #define ETHERM_STOP_PAGE 127 118644570b8SJeff Kirsher 119644570b8SJeff Kirsher /* ------------------------------------------------------------------------ */ 120644570b8SJeff Kirsher 121644570b8SJeff Kirsher #define etherh_priv(dev) \ 122644570b8SJeff Kirsher ((struct etherh_priv *)(((char *)netdev_priv(dev)) + sizeof(struct ei_device))) 123644570b8SJeff Kirsher 124644570b8SJeff Kirsher static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned char mask) 125644570b8SJeff Kirsher { 126644570b8SJeff Kirsher unsigned char ctrl = eh->ctrl | mask; 127644570b8SJeff Kirsher eh->ctrl = ctrl; 128644570b8SJeff Kirsher writeb(ctrl, eh->ctrl_port); 129644570b8SJeff Kirsher } 130644570b8SJeff Kirsher 131644570b8SJeff Kirsher static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned char mask) 132644570b8SJeff Kirsher { 133644570b8SJeff Kirsher unsigned char ctrl = eh->ctrl & ~mask; 134644570b8SJeff Kirsher eh->ctrl = ctrl; 135644570b8SJeff Kirsher writeb(ctrl, eh->ctrl_port); 136644570b8SJeff Kirsher } 137644570b8SJeff Kirsher 138644570b8SJeff Kirsher static inline unsigned int etherh_get_stat(struct etherh_priv *eh) 139644570b8SJeff Kirsher { 140644570b8SJeff Kirsher return readb(eh->ctrl_port); 141644570b8SJeff Kirsher } 142644570b8SJeff Kirsher 143644570b8SJeff Kirsher 144644570b8SJeff Kirsher 145644570b8SJeff Kirsher 146644570b8SJeff Kirsher static void etherh_irq_enable(ecard_t *ec, int irqnr) 147644570b8SJeff Kirsher { 148644570b8SJeff Kirsher struct etherh_priv *eh = ec->irq_data; 149644570b8SJeff Kirsher 150644570b8SJeff Kirsher etherh_set_ctrl(eh, ETHERH_CP_IE); 151644570b8SJeff Kirsher } 152644570b8SJeff Kirsher 153644570b8SJeff Kirsher static void etherh_irq_disable(ecard_t *ec, int irqnr) 154644570b8SJeff Kirsher { 155644570b8SJeff Kirsher struct etherh_priv *eh = ec->irq_data; 156644570b8SJeff Kirsher 157644570b8SJeff Kirsher etherh_clr_ctrl(eh, ETHERH_CP_IE); 158644570b8SJeff Kirsher } 159644570b8SJeff Kirsher 160644570b8SJeff Kirsher static expansioncard_ops_t etherh_ops = { 161644570b8SJeff Kirsher .irqenable = etherh_irq_enable, 162644570b8SJeff Kirsher .irqdisable = etherh_irq_disable, 163644570b8SJeff Kirsher }; 164644570b8SJeff Kirsher 165644570b8SJeff Kirsher 166644570b8SJeff Kirsher 167644570b8SJeff Kirsher 168644570b8SJeff Kirsher static void 169644570b8SJeff Kirsher etherh_setif(struct net_device *dev) 170644570b8SJeff Kirsher { 171644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 172644570b8SJeff Kirsher unsigned long flags; 173644570b8SJeff Kirsher void __iomem *addr; 174644570b8SJeff Kirsher 175644570b8SJeff Kirsher local_irq_save(flags); 176644570b8SJeff Kirsher 177644570b8SJeff Kirsher /* set the interface type */ 178644570b8SJeff Kirsher switch (etherh_priv(dev)->id) { 179644570b8SJeff Kirsher case PROD_I3_ETHERLAN600: 180644570b8SJeff Kirsher case PROD_I3_ETHERLAN600A: 181644570b8SJeff Kirsher addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; 182644570b8SJeff Kirsher 183644570b8SJeff Kirsher switch (dev->if_port) { 184644570b8SJeff Kirsher case IF_PORT_10BASE2: 185644570b8SJeff Kirsher writeb((readb(addr) & 0xf8) | 1, addr); 186644570b8SJeff Kirsher break; 187644570b8SJeff Kirsher case IF_PORT_10BASET: 188644570b8SJeff Kirsher writeb((readb(addr) & 0xf8), addr); 189644570b8SJeff Kirsher break; 190644570b8SJeff Kirsher } 191644570b8SJeff Kirsher break; 192644570b8SJeff Kirsher 193644570b8SJeff Kirsher case PROD_I3_ETHERLAN500: 194644570b8SJeff Kirsher switch (dev->if_port) { 195644570b8SJeff Kirsher case IF_PORT_10BASE2: 196644570b8SJeff Kirsher etherh_clr_ctrl(etherh_priv(dev), ETHERH_CP_IF); 197644570b8SJeff Kirsher break; 198644570b8SJeff Kirsher 199644570b8SJeff Kirsher case IF_PORT_10BASET: 200644570b8SJeff Kirsher etherh_set_ctrl(etherh_priv(dev), ETHERH_CP_IF); 201644570b8SJeff Kirsher break; 202644570b8SJeff Kirsher } 203644570b8SJeff Kirsher break; 204644570b8SJeff Kirsher 205644570b8SJeff Kirsher default: 206644570b8SJeff Kirsher break; 207644570b8SJeff Kirsher } 208644570b8SJeff Kirsher 209644570b8SJeff Kirsher local_irq_restore(flags); 210644570b8SJeff Kirsher } 211644570b8SJeff Kirsher 212644570b8SJeff Kirsher static int 213644570b8SJeff Kirsher etherh_getifstat(struct net_device *dev) 214644570b8SJeff Kirsher { 215644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 216644570b8SJeff Kirsher void __iomem *addr; 217644570b8SJeff Kirsher int stat = 0; 218644570b8SJeff Kirsher 219644570b8SJeff Kirsher switch (etherh_priv(dev)->id) { 220644570b8SJeff Kirsher case PROD_I3_ETHERLAN600: 221644570b8SJeff Kirsher case PROD_I3_ETHERLAN600A: 222644570b8SJeff Kirsher addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; 223644570b8SJeff Kirsher switch (dev->if_port) { 224644570b8SJeff Kirsher case IF_PORT_10BASE2: 225644570b8SJeff Kirsher stat = 1; 226644570b8SJeff Kirsher break; 227644570b8SJeff Kirsher case IF_PORT_10BASET: 228644570b8SJeff Kirsher stat = readb(addr) & 4; 229644570b8SJeff Kirsher break; 230644570b8SJeff Kirsher } 231644570b8SJeff Kirsher break; 232644570b8SJeff Kirsher 233644570b8SJeff Kirsher case PROD_I3_ETHERLAN500: 234644570b8SJeff Kirsher switch (dev->if_port) { 235644570b8SJeff Kirsher case IF_PORT_10BASE2: 236644570b8SJeff Kirsher stat = 1; 237644570b8SJeff Kirsher break; 238644570b8SJeff Kirsher case IF_PORT_10BASET: 239644570b8SJeff Kirsher stat = etherh_get_stat(etherh_priv(dev)) & ETHERH_CP_HEARTBEAT; 240644570b8SJeff Kirsher break; 241644570b8SJeff Kirsher } 242644570b8SJeff Kirsher break; 243644570b8SJeff Kirsher 244644570b8SJeff Kirsher default: 245644570b8SJeff Kirsher stat = 0; 246644570b8SJeff Kirsher break; 247644570b8SJeff Kirsher } 248644570b8SJeff Kirsher 249644570b8SJeff Kirsher return stat != 0; 250644570b8SJeff Kirsher } 251644570b8SJeff Kirsher 252644570b8SJeff Kirsher /* 253644570b8SJeff Kirsher * Configure the interface. Note that we ignore the other 254644570b8SJeff Kirsher * parts of ifmap, since its mostly meaningless for this driver. 255644570b8SJeff Kirsher */ 256644570b8SJeff Kirsher static int etherh_set_config(struct net_device *dev, struct ifmap *map) 257644570b8SJeff Kirsher { 258644570b8SJeff Kirsher switch (map->port) { 259644570b8SJeff Kirsher case IF_PORT_10BASE2: 260644570b8SJeff Kirsher case IF_PORT_10BASET: 261644570b8SJeff Kirsher /* 262644570b8SJeff Kirsher * If the user explicitly sets the interface 263644570b8SJeff Kirsher * media type, turn off automedia detection. 264644570b8SJeff Kirsher */ 265644570b8SJeff Kirsher dev->flags &= ~IFF_AUTOMEDIA; 266644570b8SJeff Kirsher dev->if_port = map->port; 267644570b8SJeff Kirsher break; 268644570b8SJeff Kirsher 269644570b8SJeff Kirsher default: 270644570b8SJeff Kirsher return -EINVAL; 271644570b8SJeff Kirsher } 272644570b8SJeff Kirsher 273644570b8SJeff Kirsher etherh_setif(dev); 274644570b8SJeff Kirsher 275644570b8SJeff Kirsher return 0; 276644570b8SJeff Kirsher } 277644570b8SJeff Kirsher 278644570b8SJeff Kirsher /* 279644570b8SJeff Kirsher * Reset the 8390 (hard reset). Note that we can't actually do this. 280644570b8SJeff Kirsher */ 281644570b8SJeff Kirsher static void 282644570b8SJeff Kirsher etherh_reset(struct net_device *dev) 283644570b8SJeff Kirsher { 284644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 285644570b8SJeff Kirsher void __iomem *addr = (void __iomem *)dev->base_addr; 286644570b8SJeff Kirsher 287644570b8SJeff Kirsher writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); 288644570b8SJeff Kirsher 289644570b8SJeff Kirsher /* 290644570b8SJeff Kirsher * See if we need to change the interface type. 291644570b8SJeff Kirsher * Note that we use 'interface_num' as a flag 292644570b8SJeff Kirsher * to indicate that we need to change the media. 293644570b8SJeff Kirsher */ 294644570b8SJeff Kirsher if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) { 295644570b8SJeff Kirsher ei_local->interface_num = 0; 296644570b8SJeff Kirsher 297644570b8SJeff Kirsher if (dev->if_port == IF_PORT_10BASET) 298644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASE2; 299644570b8SJeff Kirsher else 300644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASET; 301644570b8SJeff Kirsher 302644570b8SJeff Kirsher etherh_setif(dev); 303644570b8SJeff Kirsher } 304644570b8SJeff Kirsher } 305644570b8SJeff Kirsher 306644570b8SJeff Kirsher /* 307644570b8SJeff Kirsher * Write a block of data out to the 8390 308644570b8SJeff Kirsher */ 309644570b8SJeff Kirsher static void 310644570b8SJeff Kirsher etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) 311644570b8SJeff Kirsher { 312644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 313644570b8SJeff Kirsher unsigned long dma_start; 314644570b8SJeff Kirsher void __iomem *dma_base, *addr; 315644570b8SJeff Kirsher 316644570b8SJeff Kirsher if (ei_local->dmaing) { 317c45f812fSMatthew Whitehead netdev_err(dev, "DMAing conflict in etherh_block_input: " 318c45f812fSMatthew Whitehead " DMAstat %d irqlock %d\n", 319644570b8SJeff Kirsher ei_local->dmaing, ei_local->irqlock); 320644570b8SJeff Kirsher return; 321644570b8SJeff Kirsher } 322644570b8SJeff Kirsher 323644570b8SJeff Kirsher /* 324644570b8SJeff Kirsher * Make sure we have a round number of bytes if we're in word mode. 325644570b8SJeff Kirsher */ 326644570b8SJeff Kirsher if (count & 1 && ei_local->word16) 327644570b8SJeff Kirsher count++; 328644570b8SJeff Kirsher 329644570b8SJeff Kirsher ei_local->dmaing = 1; 330644570b8SJeff Kirsher 331644570b8SJeff Kirsher addr = (void __iomem *)dev->base_addr; 332644570b8SJeff Kirsher dma_base = etherh_priv(dev)->dma_base; 333644570b8SJeff Kirsher 334644570b8SJeff Kirsher count = (count + 1) & ~1; 335644570b8SJeff Kirsher writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); 336644570b8SJeff Kirsher 337644570b8SJeff Kirsher writeb (0x42, addr + EN0_RCNTLO); 338644570b8SJeff Kirsher writeb (0x00, addr + EN0_RCNTHI); 339644570b8SJeff Kirsher writeb (0x42, addr + EN0_RSARLO); 340644570b8SJeff Kirsher writeb (0x00, addr + EN0_RSARHI); 341644570b8SJeff Kirsher writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); 342644570b8SJeff Kirsher 343644570b8SJeff Kirsher udelay (1); 344644570b8SJeff Kirsher 345644570b8SJeff Kirsher writeb (ENISR_RDC, addr + EN0_ISR); 346644570b8SJeff Kirsher writeb (count, addr + EN0_RCNTLO); 347644570b8SJeff Kirsher writeb (count >> 8, addr + EN0_RCNTHI); 348644570b8SJeff Kirsher writeb (0, addr + EN0_RSARLO); 349644570b8SJeff Kirsher writeb (start_page, addr + EN0_RSARHI); 350644570b8SJeff Kirsher writeb (E8390_RWRITE | E8390_START, addr + E8390_CMD); 351644570b8SJeff Kirsher 352644570b8SJeff Kirsher if (ei_local->word16) 353644570b8SJeff Kirsher writesw (dma_base, buf, count >> 1); 354644570b8SJeff Kirsher else 355644570b8SJeff Kirsher writesb (dma_base, buf, count); 356644570b8SJeff Kirsher 357644570b8SJeff Kirsher dma_start = jiffies; 358644570b8SJeff Kirsher 359644570b8SJeff Kirsher while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0) 360644570b8SJeff Kirsher if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ 361c45f812fSMatthew Whitehead netdev_warn(dev, "timeout waiting for TX RDC\n"); 362644570b8SJeff Kirsher etherh_reset (dev); 363644570b8SJeff Kirsher __NS8390_init (dev, 1); 364644570b8SJeff Kirsher break; 365644570b8SJeff Kirsher } 366644570b8SJeff Kirsher 367644570b8SJeff Kirsher writeb (ENISR_RDC, addr + EN0_ISR); 368644570b8SJeff Kirsher ei_local->dmaing = 0; 369644570b8SJeff Kirsher } 370644570b8SJeff Kirsher 371644570b8SJeff Kirsher /* 372644570b8SJeff Kirsher * Read a block of data from the 8390 373644570b8SJeff Kirsher */ 374644570b8SJeff Kirsher static void 375644570b8SJeff Kirsher etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) 376644570b8SJeff Kirsher { 377644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 378644570b8SJeff Kirsher unsigned char *buf; 379644570b8SJeff Kirsher void __iomem *dma_base, *addr; 380644570b8SJeff Kirsher 381644570b8SJeff Kirsher if (ei_local->dmaing) { 382c45f812fSMatthew Whitehead netdev_err(dev, "DMAing conflict in etherh_block_input: " 383c45f812fSMatthew Whitehead " DMAstat %d irqlock %d\n", 384644570b8SJeff Kirsher ei_local->dmaing, ei_local->irqlock); 385644570b8SJeff Kirsher return; 386644570b8SJeff Kirsher } 387644570b8SJeff Kirsher 388644570b8SJeff Kirsher ei_local->dmaing = 1; 389644570b8SJeff Kirsher 390644570b8SJeff Kirsher addr = (void __iomem *)dev->base_addr; 391644570b8SJeff Kirsher dma_base = etherh_priv(dev)->dma_base; 392644570b8SJeff Kirsher 393644570b8SJeff Kirsher buf = skb->data; 394644570b8SJeff Kirsher writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); 395644570b8SJeff Kirsher writeb (count, addr + EN0_RCNTLO); 396644570b8SJeff Kirsher writeb (count >> 8, addr + EN0_RCNTHI); 397644570b8SJeff Kirsher writeb (ring_offset, addr + EN0_RSARLO); 398644570b8SJeff Kirsher writeb (ring_offset >> 8, addr + EN0_RSARHI); 399644570b8SJeff Kirsher writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); 400644570b8SJeff Kirsher 401644570b8SJeff Kirsher if (ei_local->word16) { 402644570b8SJeff Kirsher readsw (dma_base, buf, count >> 1); 403644570b8SJeff Kirsher if (count & 1) 404644570b8SJeff Kirsher buf[count - 1] = readb (dma_base); 405644570b8SJeff Kirsher } else 406644570b8SJeff Kirsher readsb (dma_base, buf, count); 407644570b8SJeff Kirsher 408644570b8SJeff Kirsher writeb (ENISR_RDC, addr + EN0_ISR); 409644570b8SJeff Kirsher ei_local->dmaing = 0; 410644570b8SJeff Kirsher } 411644570b8SJeff Kirsher 412644570b8SJeff Kirsher /* 413644570b8SJeff Kirsher * Read a header from the 8390 414644570b8SJeff Kirsher */ 415644570b8SJeff Kirsher static void 416644570b8SJeff Kirsher etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) 417644570b8SJeff Kirsher { 418644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 419644570b8SJeff Kirsher void __iomem *dma_base, *addr; 420644570b8SJeff Kirsher 421644570b8SJeff Kirsher if (ei_local->dmaing) { 422c45f812fSMatthew Whitehead netdev_err(dev, "DMAing conflict in etherh_get_header: " 423c45f812fSMatthew Whitehead " DMAstat %d irqlock %d\n", 424644570b8SJeff Kirsher ei_local->dmaing, ei_local->irqlock); 425644570b8SJeff Kirsher return; 426644570b8SJeff Kirsher } 427644570b8SJeff Kirsher 428644570b8SJeff Kirsher ei_local->dmaing = 1; 429644570b8SJeff Kirsher 430644570b8SJeff Kirsher addr = (void __iomem *)dev->base_addr; 431644570b8SJeff Kirsher dma_base = etherh_priv(dev)->dma_base; 432644570b8SJeff Kirsher 433644570b8SJeff Kirsher writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); 434644570b8SJeff Kirsher writeb (sizeof (*hdr), addr + EN0_RCNTLO); 435644570b8SJeff Kirsher writeb (0, addr + EN0_RCNTHI); 436644570b8SJeff Kirsher writeb (0, addr + EN0_RSARLO); 437644570b8SJeff Kirsher writeb (ring_page, addr + EN0_RSARHI); 438644570b8SJeff Kirsher writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); 439644570b8SJeff Kirsher 440644570b8SJeff Kirsher if (ei_local->word16) 441644570b8SJeff Kirsher readsw (dma_base, hdr, sizeof (*hdr) >> 1); 442644570b8SJeff Kirsher else 443644570b8SJeff Kirsher readsb (dma_base, hdr, sizeof (*hdr)); 444644570b8SJeff Kirsher 445644570b8SJeff Kirsher writeb (ENISR_RDC, addr + EN0_ISR); 446644570b8SJeff Kirsher ei_local->dmaing = 0; 447644570b8SJeff Kirsher } 448644570b8SJeff Kirsher 449644570b8SJeff Kirsher /* 450644570b8SJeff Kirsher * Open/initialize the board. This is called (in the current kernel) 451644570b8SJeff Kirsher * sometime after booting when the 'ifconfig' program is run. 452644570b8SJeff Kirsher * 453644570b8SJeff Kirsher * This routine should set everything up anew at each open, even 454644570b8SJeff Kirsher * registers that "should" only need to be set once at boot, so that 455644570b8SJeff Kirsher * there is non-reboot way to recover if something goes wrong. 456644570b8SJeff Kirsher */ 457644570b8SJeff Kirsher static int 458644570b8SJeff Kirsher etherh_open(struct net_device *dev) 459644570b8SJeff Kirsher { 460644570b8SJeff Kirsher struct ei_device *ei_local = netdev_priv(dev); 461644570b8SJeff Kirsher 462644570b8SJeff Kirsher if (request_irq(dev->irq, __ei_interrupt, 0, dev->name, dev)) 463644570b8SJeff Kirsher return -EAGAIN; 464644570b8SJeff Kirsher 465644570b8SJeff Kirsher /* 466644570b8SJeff Kirsher * Make sure that we aren't going to change the 467644570b8SJeff Kirsher * media type on the next reset - we are about to 468644570b8SJeff Kirsher * do automedia manually now. 469644570b8SJeff Kirsher */ 470644570b8SJeff Kirsher ei_local->interface_num = 0; 471644570b8SJeff Kirsher 472644570b8SJeff Kirsher /* 473644570b8SJeff Kirsher * If we are doing automedia detection, do it now. 474644570b8SJeff Kirsher * This is more reliable than the 8390's detection. 475644570b8SJeff Kirsher */ 476644570b8SJeff Kirsher if (dev->flags & IFF_AUTOMEDIA) { 477644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASET; 478644570b8SJeff Kirsher etherh_setif(dev); 479644570b8SJeff Kirsher mdelay(1); 480644570b8SJeff Kirsher if (!etherh_getifstat(dev)) { 481644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASE2; 482644570b8SJeff Kirsher etherh_setif(dev); 483644570b8SJeff Kirsher } 484644570b8SJeff Kirsher } else 485644570b8SJeff Kirsher etherh_setif(dev); 486644570b8SJeff Kirsher 487644570b8SJeff Kirsher etherh_reset(dev); 488644570b8SJeff Kirsher __ei_open(dev); 489644570b8SJeff Kirsher 490644570b8SJeff Kirsher return 0; 491644570b8SJeff Kirsher } 492644570b8SJeff Kirsher 493644570b8SJeff Kirsher /* 494644570b8SJeff Kirsher * The inverse routine to etherh_open(). 495644570b8SJeff Kirsher */ 496644570b8SJeff Kirsher static int 497644570b8SJeff Kirsher etherh_close(struct net_device *dev) 498644570b8SJeff Kirsher { 499644570b8SJeff Kirsher __ei_close (dev); 500644570b8SJeff Kirsher free_irq (dev->irq, dev); 501644570b8SJeff Kirsher return 0; 502644570b8SJeff Kirsher } 503644570b8SJeff Kirsher 504644570b8SJeff Kirsher /* 505644570b8SJeff Kirsher * Initialisation 506644570b8SJeff Kirsher */ 507644570b8SJeff Kirsher 508644570b8SJeff Kirsher static void __init etherh_banner(void) 509644570b8SJeff Kirsher { 510644570b8SJeff Kirsher static int version_printed; 511644570b8SJeff Kirsher 512c45f812fSMatthew Whitehead if ((etherh_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0)) 513c45f812fSMatthew Whitehead pr_info("%s", version); 514644570b8SJeff Kirsher } 515644570b8SJeff Kirsher 516644570b8SJeff Kirsher /* 517644570b8SJeff Kirsher * Read the ethernet address string from the on board rom. 518644570b8SJeff Kirsher * This is an ascii string... 519644570b8SJeff Kirsher */ 5204168ac0eSBill Pemberton static int etherh_addr(char *addr, struct expansion_card *ec) 521644570b8SJeff Kirsher { 522644570b8SJeff Kirsher struct in_chunk_dir cd; 523644570b8SJeff Kirsher char *s; 524644570b8SJeff Kirsher 525644570b8SJeff Kirsher if (!ecard_readchunk(&cd, ec, 0xf5, 0)) { 526644570b8SJeff Kirsher printk(KERN_ERR "%s: unable to read podule description string\n", 527644570b8SJeff Kirsher dev_name(&ec->dev)); 528644570b8SJeff Kirsher goto no_addr; 529644570b8SJeff Kirsher } 530644570b8SJeff Kirsher 531644570b8SJeff Kirsher s = strchr(cd.d.string, '('); 532644570b8SJeff Kirsher if (s) { 533644570b8SJeff Kirsher int i; 534644570b8SJeff Kirsher 535644570b8SJeff Kirsher for (i = 0; i < 6; i++) { 536644570b8SJeff Kirsher addr[i] = simple_strtoul(s + 1, &s, 0x10); 537644570b8SJeff Kirsher if (*s != (i == 5? ')' : ':')) 538644570b8SJeff Kirsher break; 539644570b8SJeff Kirsher } 540644570b8SJeff Kirsher 541644570b8SJeff Kirsher if (i == 6) 542644570b8SJeff Kirsher return 0; 543644570b8SJeff Kirsher } 544644570b8SJeff Kirsher 545644570b8SJeff Kirsher printk(KERN_ERR "%s: unable to parse MAC address: %s\n", 546644570b8SJeff Kirsher dev_name(&ec->dev), cd.d.string); 547644570b8SJeff Kirsher 548644570b8SJeff Kirsher no_addr: 549644570b8SJeff Kirsher return -ENODEV; 550644570b8SJeff Kirsher } 551644570b8SJeff Kirsher 552644570b8SJeff Kirsher /* 553644570b8SJeff Kirsher * Create an ethernet address from the system serial number. 554644570b8SJeff Kirsher */ 555644570b8SJeff Kirsher static int __init etherm_addr(char *addr) 556644570b8SJeff Kirsher { 557644570b8SJeff Kirsher unsigned int serial; 558644570b8SJeff Kirsher 559644570b8SJeff Kirsher if (system_serial_low == 0 && system_serial_high == 0) 560644570b8SJeff Kirsher return -ENODEV; 561644570b8SJeff Kirsher 562644570b8SJeff Kirsher serial = system_serial_low | system_serial_high; 563644570b8SJeff Kirsher 564644570b8SJeff Kirsher addr[0] = 0; 565644570b8SJeff Kirsher addr[1] = 0; 566644570b8SJeff Kirsher addr[2] = 0xa4; 567644570b8SJeff Kirsher addr[3] = 0x10 + (serial >> 24); 568644570b8SJeff Kirsher addr[4] = serial >> 16; 569644570b8SJeff Kirsher addr[5] = serial >> 8; 570644570b8SJeff Kirsher return 0; 571644570b8SJeff Kirsher } 572644570b8SJeff Kirsher 573644570b8SJeff Kirsher static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 574644570b8SJeff Kirsher { 575644570b8SJeff Kirsher strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 576644570b8SJeff Kirsher strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 577644570b8SJeff Kirsher strlcpy(info->bus_info, dev_name(dev->dev.parent), 578644570b8SJeff Kirsher sizeof(info->bus_info)); 579644570b8SJeff Kirsher } 580644570b8SJeff Kirsher 581644570b8SJeff Kirsher static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 582644570b8SJeff Kirsher { 583644570b8SJeff Kirsher cmd->supported = etherh_priv(dev)->supported; 584644570b8SJeff Kirsher ethtool_cmd_speed_set(cmd, SPEED_10); 585644570b8SJeff Kirsher cmd->duplex = DUPLEX_HALF; 586644570b8SJeff Kirsher cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; 587644570b8SJeff Kirsher cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ? 588644570b8SJeff Kirsher AUTONEG_ENABLE : AUTONEG_DISABLE); 589644570b8SJeff Kirsher return 0; 590644570b8SJeff Kirsher } 591644570b8SJeff Kirsher 592644570b8SJeff Kirsher static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 593644570b8SJeff Kirsher { 594644570b8SJeff Kirsher switch (cmd->autoneg) { 595644570b8SJeff Kirsher case AUTONEG_ENABLE: 596644570b8SJeff Kirsher dev->flags |= IFF_AUTOMEDIA; 597644570b8SJeff Kirsher break; 598644570b8SJeff Kirsher 599644570b8SJeff Kirsher case AUTONEG_DISABLE: 600644570b8SJeff Kirsher switch (cmd->port) { 601644570b8SJeff Kirsher case PORT_TP: 602644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASET; 603644570b8SJeff Kirsher break; 604644570b8SJeff Kirsher 605644570b8SJeff Kirsher case PORT_BNC: 606644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASE2; 607644570b8SJeff Kirsher break; 608644570b8SJeff Kirsher 609644570b8SJeff Kirsher default: 610644570b8SJeff Kirsher return -EINVAL; 611644570b8SJeff Kirsher } 612644570b8SJeff Kirsher dev->flags &= ~IFF_AUTOMEDIA; 613644570b8SJeff Kirsher break; 614644570b8SJeff Kirsher 615644570b8SJeff Kirsher default: 616644570b8SJeff Kirsher return -EINVAL; 617644570b8SJeff Kirsher } 618644570b8SJeff Kirsher 619644570b8SJeff Kirsher etherh_setif(dev); 620644570b8SJeff Kirsher 621644570b8SJeff Kirsher return 0; 622644570b8SJeff Kirsher } 623644570b8SJeff Kirsher 624c45f812fSMatthew Whitehead static u32 etherh_get_msglevel(struct net_device *dev) 625c45f812fSMatthew Whitehead { 626c45f812fSMatthew Whitehead struct ei_device *ei_local = netdev_priv(dev); 627c45f812fSMatthew Whitehead 628c45f812fSMatthew Whitehead return ei_local->msg_enable; 629c45f812fSMatthew Whitehead } 630c45f812fSMatthew Whitehead 631c45f812fSMatthew Whitehead static void etherh_set_msglevel(struct net_device *dev, u32 v) 632c45f812fSMatthew Whitehead { 633c45f812fSMatthew Whitehead struct ei_device *ei_local = netdev_priv(dev); 634c45f812fSMatthew Whitehead 635c45f812fSMatthew Whitehead ei_local->msg_enable = v; 636c45f812fSMatthew Whitehead } 637c45f812fSMatthew Whitehead 638644570b8SJeff Kirsher static const struct ethtool_ops etherh_ethtool_ops = { 639644570b8SJeff Kirsher .get_settings = etherh_get_settings, 640644570b8SJeff Kirsher .set_settings = etherh_set_settings, 641644570b8SJeff Kirsher .get_drvinfo = etherh_get_drvinfo, 64265198be2SRichard Cochran .get_ts_info = ethtool_op_get_ts_info, 643c45f812fSMatthew Whitehead .get_msglevel = etherh_get_msglevel, 644c45f812fSMatthew Whitehead .set_msglevel = etherh_set_msglevel, 645644570b8SJeff Kirsher }; 646644570b8SJeff Kirsher 647644570b8SJeff Kirsher static const struct net_device_ops etherh_netdev_ops = { 648644570b8SJeff Kirsher .ndo_open = etherh_open, 649644570b8SJeff Kirsher .ndo_stop = etherh_close, 650644570b8SJeff Kirsher .ndo_set_config = etherh_set_config, 651644570b8SJeff Kirsher .ndo_start_xmit = __ei_start_xmit, 652644570b8SJeff Kirsher .ndo_tx_timeout = __ei_tx_timeout, 653644570b8SJeff Kirsher .ndo_get_stats = __ei_get_stats, 654afc4b13dSJiri Pirko .ndo_set_rx_mode = __ei_set_multicast_list, 655644570b8SJeff Kirsher .ndo_validate_addr = eth_validate_addr, 656644570b8SJeff Kirsher .ndo_set_mac_address = eth_mac_addr, 657644570b8SJeff Kirsher .ndo_change_mtu = eth_change_mtu, 658644570b8SJeff Kirsher #ifdef CONFIG_NET_POLL_CONTROLLER 659644570b8SJeff Kirsher .ndo_poll_controller = __ei_poll, 660644570b8SJeff Kirsher #endif 661644570b8SJeff Kirsher }; 662644570b8SJeff Kirsher 663644570b8SJeff Kirsher static u32 etherh_regoffsets[16]; 664644570b8SJeff Kirsher static u32 etherm_regoffsets[16]; 665644570b8SJeff Kirsher 6664168ac0eSBill Pemberton static int 667644570b8SJeff Kirsher etherh_probe(struct expansion_card *ec, const struct ecard_id *id) 668644570b8SJeff Kirsher { 669644570b8SJeff Kirsher const struct etherh_data *data = id->data; 670644570b8SJeff Kirsher struct ei_device *ei_local; 671644570b8SJeff Kirsher struct net_device *dev; 672644570b8SJeff Kirsher struct etherh_priv *eh; 673644570b8SJeff Kirsher int ret; 674644570b8SJeff Kirsher 675644570b8SJeff Kirsher etherh_banner(); 676644570b8SJeff Kirsher 677644570b8SJeff Kirsher ret = ecard_request_resources(ec); 678644570b8SJeff Kirsher if (ret) 679644570b8SJeff Kirsher goto out; 680644570b8SJeff Kirsher 681644570b8SJeff Kirsher dev = ____alloc_ei_netdev(sizeof(struct etherh_priv)); 682644570b8SJeff Kirsher if (!dev) { 683644570b8SJeff Kirsher ret = -ENOMEM; 684644570b8SJeff Kirsher goto release; 685644570b8SJeff Kirsher } 686644570b8SJeff Kirsher 687644570b8SJeff Kirsher SET_NETDEV_DEV(dev, &ec->dev); 688644570b8SJeff Kirsher 689644570b8SJeff Kirsher dev->netdev_ops = ðerh_netdev_ops; 690644570b8SJeff Kirsher dev->irq = ec->irq; 691644570b8SJeff Kirsher dev->ethtool_ops = ðerh_ethtool_ops; 692644570b8SJeff Kirsher 693644570b8SJeff Kirsher if (data->supported & SUPPORTED_Autoneg) 694644570b8SJeff Kirsher dev->flags |= IFF_AUTOMEDIA; 695644570b8SJeff Kirsher if (data->supported & SUPPORTED_TP) { 696644570b8SJeff Kirsher dev->flags |= IFF_PORTSEL; 697644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASET; 698644570b8SJeff Kirsher } else if (data->supported & SUPPORTED_BNC) { 699644570b8SJeff Kirsher dev->flags |= IFF_PORTSEL; 700644570b8SJeff Kirsher dev->if_port = IF_PORT_10BASE2; 701644570b8SJeff Kirsher } else 702644570b8SJeff Kirsher dev->if_port = IF_PORT_UNKNOWN; 703644570b8SJeff Kirsher 704644570b8SJeff Kirsher eh = etherh_priv(dev); 705644570b8SJeff Kirsher eh->supported = data->supported; 706644570b8SJeff Kirsher eh->ctrl = 0; 707644570b8SJeff Kirsher eh->id = ec->cid.product; 708644570b8SJeff Kirsher eh->memc = ecardm_iomap(ec, ECARD_RES_MEMC, 0, PAGE_SIZE); 709644570b8SJeff Kirsher if (!eh->memc) { 710644570b8SJeff Kirsher ret = -ENOMEM; 711644570b8SJeff Kirsher goto free; 712644570b8SJeff Kirsher } 713644570b8SJeff Kirsher 714644570b8SJeff Kirsher eh->ctrl_port = eh->memc; 715644570b8SJeff Kirsher if (data->ctrl_ioc) { 716644570b8SJeff Kirsher eh->ioc_fast = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, PAGE_SIZE); 717644570b8SJeff Kirsher if (!eh->ioc_fast) { 718644570b8SJeff Kirsher ret = -ENOMEM; 719644570b8SJeff Kirsher goto free; 720644570b8SJeff Kirsher } 721644570b8SJeff Kirsher eh->ctrl_port = eh->ioc_fast; 722644570b8SJeff Kirsher } 723644570b8SJeff Kirsher 724644570b8SJeff Kirsher dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset; 725644570b8SJeff Kirsher eh->dma_base = eh->memc + data->dataport_offset; 726644570b8SJeff Kirsher eh->ctrl_port += data->ctrlport_offset; 727644570b8SJeff Kirsher 728644570b8SJeff Kirsher /* 729644570b8SJeff Kirsher * IRQ and control port handling - only for non-NIC slot cards. 730644570b8SJeff Kirsher */ 731644570b8SJeff Kirsher if (ec->slot_no != 8) { 732644570b8SJeff Kirsher ecard_setirq(ec, ðerh_ops, eh); 733644570b8SJeff Kirsher } else { 734644570b8SJeff Kirsher /* 735644570b8SJeff Kirsher * If we're in the NIC slot, make sure the IRQ is enabled 736644570b8SJeff Kirsher */ 737644570b8SJeff Kirsher etherh_set_ctrl(eh, ETHERH_CP_IE); 738644570b8SJeff Kirsher } 739644570b8SJeff Kirsher 740644570b8SJeff Kirsher ei_local = netdev_priv(dev); 741644570b8SJeff Kirsher spin_lock_init(&ei_local->page_lock); 742644570b8SJeff Kirsher 743644570b8SJeff Kirsher if (ec->cid.product == PROD_ANT_ETHERM) { 744644570b8SJeff Kirsher etherm_addr(dev->dev_addr); 745644570b8SJeff Kirsher ei_local->reg_offset = etherm_regoffsets; 746644570b8SJeff Kirsher } else { 747644570b8SJeff Kirsher etherh_addr(dev->dev_addr, ec); 748644570b8SJeff Kirsher ei_local->reg_offset = etherh_regoffsets; 749644570b8SJeff Kirsher } 750644570b8SJeff Kirsher 751644570b8SJeff Kirsher ei_local->name = dev->name; 752644570b8SJeff Kirsher ei_local->word16 = 1; 753644570b8SJeff Kirsher ei_local->tx_start_page = data->tx_start_page; 754644570b8SJeff Kirsher ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES; 755644570b8SJeff Kirsher ei_local->stop_page = data->stop_page; 756644570b8SJeff Kirsher ei_local->reset_8390 = etherh_reset; 757644570b8SJeff Kirsher ei_local->block_input = etherh_block_input; 758644570b8SJeff Kirsher ei_local->block_output = etherh_block_output; 759644570b8SJeff Kirsher ei_local->get_8390_hdr = etherh_get_header; 760644570b8SJeff Kirsher ei_local->interface_num = 0; 761c45f812fSMatthew Whitehead ei_local->msg_enable = etherh_msg_enable; 762644570b8SJeff Kirsher 763644570b8SJeff Kirsher etherh_reset(dev); 764644570b8SJeff Kirsher __NS8390_init(dev, 0); 765644570b8SJeff Kirsher 766644570b8SJeff Kirsher ret = register_netdev(dev); 767644570b8SJeff Kirsher if (ret) 768644570b8SJeff Kirsher goto free; 769644570b8SJeff Kirsher 770c45f812fSMatthew Whitehead netdev_info(dev, "%s in slot %d, %pM\n", 771c45f812fSMatthew Whitehead data->name, ec->slot_no, dev->dev_addr); 772644570b8SJeff Kirsher 773644570b8SJeff Kirsher ecard_set_drvdata(ec, dev); 774644570b8SJeff Kirsher 775644570b8SJeff Kirsher return 0; 776644570b8SJeff Kirsher 777644570b8SJeff Kirsher free: 778644570b8SJeff Kirsher free_netdev(dev); 779644570b8SJeff Kirsher release: 780644570b8SJeff Kirsher ecard_release_resources(ec); 781644570b8SJeff Kirsher out: 782644570b8SJeff Kirsher return ret; 783644570b8SJeff Kirsher } 784644570b8SJeff Kirsher 7854168ac0eSBill Pemberton static void etherh_remove(struct expansion_card *ec) 786644570b8SJeff Kirsher { 787644570b8SJeff Kirsher struct net_device *dev = ecard_get_drvdata(ec); 788644570b8SJeff Kirsher 789644570b8SJeff Kirsher ecard_set_drvdata(ec, NULL); 790644570b8SJeff Kirsher 791644570b8SJeff Kirsher unregister_netdev(dev); 792644570b8SJeff Kirsher 793644570b8SJeff Kirsher free_netdev(dev); 794644570b8SJeff Kirsher 795644570b8SJeff Kirsher ecard_release_resources(ec); 796644570b8SJeff Kirsher } 797644570b8SJeff Kirsher 798644570b8SJeff Kirsher static struct etherh_data etherm_data = { 799644570b8SJeff Kirsher .ns8390_offset = ETHERM_NS8390, 800644570b8SJeff Kirsher .dataport_offset = ETHERM_NS8390 + ETHERM_DATAPORT, 801644570b8SJeff Kirsher .ctrlport_offset = ETHERM_NS8390 + ETHERM_CTRLPORT, 802644570b8SJeff Kirsher .name = "ANT EtherM", 803644570b8SJeff Kirsher .supported = SUPPORTED_10baseT_Half, 804644570b8SJeff Kirsher .tx_start_page = ETHERM_TX_START_PAGE, 805644570b8SJeff Kirsher .stop_page = ETHERM_STOP_PAGE, 806644570b8SJeff Kirsher }; 807644570b8SJeff Kirsher 808644570b8SJeff Kirsher static struct etherh_data etherlan500_data = { 809644570b8SJeff Kirsher .ns8390_offset = ETHERH500_NS8390, 810644570b8SJeff Kirsher .dataport_offset = ETHERH500_NS8390 + ETHERH500_DATAPORT, 811644570b8SJeff Kirsher .ctrlport_offset = ETHERH500_CTRLPORT, 812644570b8SJeff Kirsher .ctrl_ioc = 1, 813644570b8SJeff Kirsher .name = "i3 EtherH 500", 814644570b8SJeff Kirsher .supported = SUPPORTED_10baseT_Half, 815644570b8SJeff Kirsher .tx_start_page = ETHERH_TX_START_PAGE, 816644570b8SJeff Kirsher .stop_page = ETHERH_STOP_PAGE, 817644570b8SJeff Kirsher }; 818644570b8SJeff Kirsher 819644570b8SJeff Kirsher static struct etherh_data etherlan600_data = { 820644570b8SJeff Kirsher .ns8390_offset = ETHERH600_NS8390, 821644570b8SJeff Kirsher .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, 822644570b8SJeff Kirsher .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, 823644570b8SJeff Kirsher .name = "i3 EtherH 600", 824644570b8SJeff Kirsher .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, 825644570b8SJeff Kirsher .tx_start_page = ETHERH_TX_START_PAGE, 826644570b8SJeff Kirsher .stop_page = ETHERH_STOP_PAGE, 827644570b8SJeff Kirsher }; 828644570b8SJeff Kirsher 829644570b8SJeff Kirsher static struct etherh_data etherlan600a_data = { 830644570b8SJeff Kirsher .ns8390_offset = ETHERH600_NS8390, 831644570b8SJeff Kirsher .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, 832644570b8SJeff Kirsher .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, 833644570b8SJeff Kirsher .name = "i3 EtherH 600A", 834644570b8SJeff Kirsher .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, 835644570b8SJeff Kirsher .tx_start_page = ETHERH_TX_START_PAGE, 836644570b8SJeff Kirsher .stop_page = ETHERH_STOP_PAGE, 837644570b8SJeff Kirsher }; 838644570b8SJeff Kirsher 839644570b8SJeff Kirsher static const struct ecard_id etherh_ids[] = { 840644570b8SJeff Kirsher { MANU_ANT, PROD_ANT_ETHERM, ðerm_data }, 841644570b8SJeff Kirsher { MANU_I3, PROD_I3_ETHERLAN500, ðerlan500_data }, 842644570b8SJeff Kirsher { MANU_I3, PROD_I3_ETHERLAN600, ðerlan600_data }, 843644570b8SJeff Kirsher { MANU_I3, PROD_I3_ETHERLAN600A, ðerlan600a_data }, 844644570b8SJeff Kirsher { 0xffff, 0xffff } 845644570b8SJeff Kirsher }; 846644570b8SJeff Kirsher 847644570b8SJeff Kirsher static struct ecard_driver etherh_driver = { 848644570b8SJeff Kirsher .probe = etherh_probe, 8494168ac0eSBill Pemberton .remove = etherh_remove, 850644570b8SJeff Kirsher .id_table = etherh_ids, 851644570b8SJeff Kirsher .drv = { 852644570b8SJeff Kirsher .name = DRV_NAME, 853644570b8SJeff Kirsher }, 854644570b8SJeff Kirsher }; 855644570b8SJeff Kirsher 856644570b8SJeff Kirsher static int __init etherh_init(void) 857644570b8SJeff Kirsher { 858644570b8SJeff Kirsher int i; 859644570b8SJeff Kirsher 860644570b8SJeff Kirsher for (i = 0; i < 16; i++) { 861644570b8SJeff Kirsher etherh_regoffsets[i] = i << 2; 862644570b8SJeff Kirsher etherm_regoffsets[i] = i << 5; 863644570b8SJeff Kirsher } 864644570b8SJeff Kirsher 865644570b8SJeff Kirsher return ecard_register_driver(ðerh_driver); 866644570b8SJeff Kirsher } 867644570b8SJeff Kirsher 868644570b8SJeff Kirsher static void __exit etherh_exit(void) 869644570b8SJeff Kirsher { 870644570b8SJeff Kirsher ecard_remove_driver(ðerh_driver); 871644570b8SJeff Kirsher } 872644570b8SJeff Kirsher 873644570b8SJeff Kirsher module_init(etherh_init); 874644570b8SJeff Kirsher module_exit(etherh_exit); 875