162306a36Sopenharmony_ci/*====================================================================== 262306a36Sopenharmony_ci fmvj18x_cs.c 2.8 2002/03/23 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci A fmvj18x (and its compatibles) PCMCIA client driver 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci TDK LAK-CD021 and CONTEC C-NET(PC)C support added by 962306a36Sopenharmony_ci Nobuhiro Katayama, kata-n@po.iijnet.or.jp 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci The PCMCIA client code is based on code written by David Hinds. 1262306a36Sopenharmony_ci Network code is based on the "FMV-18x driver" by Yutaka TAMIYA 1362306a36Sopenharmony_ci but is actually largely Donald Becker's AT1700 driver, which 1462306a36Sopenharmony_ci carries the following attribution: 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci Written 1993-94 by Donald Becker. 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci Copyright 1993 United States Government as represented by the 1962306a36Sopenharmony_ci Director, National Security Agency. 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci This software may be used and distributed according to the terms 2262306a36Sopenharmony_ci of the GNU General Public License, incorporated herein by reference. 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci The author may be reached as becker@scyld.com, or C/O 2562306a36Sopenharmony_ci Scyld Computing Corporation 2662306a36Sopenharmony_ci 410 Severn Ave., Suite 210 2762306a36Sopenharmony_ci Annapolis MD 21403 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci======================================================================*/ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define DRV_NAME "fmvj18x_cs" 3462306a36Sopenharmony_ci#define DRV_VERSION "2.9" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/module.h> 3762306a36Sopenharmony_ci#include <linux/kernel.h> 3862306a36Sopenharmony_ci#include <linux/ptrace.h> 3962306a36Sopenharmony_ci#include <linux/slab.h> 4062306a36Sopenharmony_ci#include <linux/string.h> 4162306a36Sopenharmony_ci#include <linux/timer.h> 4262306a36Sopenharmony_ci#include <linux/interrupt.h> 4362306a36Sopenharmony_ci#include <linux/in.h> 4462306a36Sopenharmony_ci#include <linux/delay.h> 4562306a36Sopenharmony_ci#include <linux/ethtool.h> 4662306a36Sopenharmony_ci#include <linux/netdevice.h> 4762306a36Sopenharmony_ci#include <linux/etherdevice.h> 4862306a36Sopenharmony_ci#include <linux/skbuff.h> 4962306a36Sopenharmony_ci#include <linux/if_arp.h> 5062306a36Sopenharmony_ci#include <linux/ioport.h> 5162306a36Sopenharmony_ci#include <linux/crc32.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include <pcmcia/cistpl.h> 5462306a36Sopenharmony_ci#include <pcmcia/ciscode.h> 5562306a36Sopenharmony_ci#include <pcmcia/ds.h> 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#include <linux/uaccess.h> 5862306a36Sopenharmony_ci#include <asm/io.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/*====================================================================*/ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Module parameters */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciMODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver"); 6562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* SRAM configuration */ 7062306a36Sopenharmony_ci/* 0:4KB*2 TX buffer else:8KB*2 TX buffer */ 7162306a36Sopenharmony_ciINT_MODULE_PARM(sram_config, 0); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/*====================================================================*/ 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci PCMCIA event handlers 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistatic int fmvj18x_config(struct pcmcia_device *link); 7962306a36Sopenharmony_cistatic int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id); 8062306a36Sopenharmony_cistatic int fmvj18x_setup_mfc(struct pcmcia_device *link); 8162306a36Sopenharmony_cistatic void fmvj18x_release(struct pcmcia_device *link); 8262306a36Sopenharmony_cistatic void fmvj18x_detach(struct pcmcia_device *p_dev); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci LAN controller(MBH86960A) specific routines 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistatic int fjn_config(struct net_device *dev, struct ifmap *map); 8862306a36Sopenharmony_cistatic int fjn_open(struct net_device *dev); 8962306a36Sopenharmony_cistatic int fjn_close(struct net_device *dev); 9062306a36Sopenharmony_cistatic netdev_tx_t fjn_start_xmit(struct sk_buff *skb, 9162306a36Sopenharmony_ci struct net_device *dev); 9262306a36Sopenharmony_cistatic irqreturn_t fjn_interrupt(int irq, void *dev_id); 9362306a36Sopenharmony_cistatic void fjn_rx(struct net_device *dev); 9462306a36Sopenharmony_cistatic void fjn_reset(struct net_device *dev); 9562306a36Sopenharmony_cistatic void set_rx_mode(struct net_device *dev); 9662306a36Sopenharmony_cistatic void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue); 9762306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci card type 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_cienum cardtype { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, 10362306a36Sopenharmony_ci XXX10304, NEC, KME 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci driver specific data structure 10862306a36Sopenharmony_ci*/ 10962306a36Sopenharmony_cistruct local_info { 11062306a36Sopenharmony_ci struct pcmcia_device *p_dev; 11162306a36Sopenharmony_ci long open_time; 11262306a36Sopenharmony_ci uint tx_started:1; 11362306a36Sopenharmony_ci uint tx_queue; 11462306a36Sopenharmony_ci u_short tx_queue_len; 11562306a36Sopenharmony_ci enum cardtype cardtype; 11662306a36Sopenharmony_ci u_short sent; 11762306a36Sopenharmony_ci u_char __iomem *base; 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define MC_FILTERBREAK 64 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/*====================================================================*/ 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci ioport offset from the base address 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci#define TX_STATUS 0 /* transmit status register */ 12762306a36Sopenharmony_ci#define RX_STATUS 1 /* receive status register */ 12862306a36Sopenharmony_ci#define TX_INTR 2 /* transmit interrupt mask register */ 12962306a36Sopenharmony_ci#define RX_INTR 3 /* receive interrupt mask register */ 13062306a36Sopenharmony_ci#define TX_MODE 4 /* transmit mode register */ 13162306a36Sopenharmony_ci#define RX_MODE 5 /* receive mode register */ 13262306a36Sopenharmony_ci#define CONFIG_0 6 /* configuration register 0 */ 13362306a36Sopenharmony_ci#define CONFIG_1 7 /* configuration register 1 */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define NODE_ID 8 /* node ID register (bank 0) */ 13662306a36Sopenharmony_ci#define MAR_ADR 8 /* multicast address registers (bank 1) */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define DATAPORT 8 /* buffer mem port registers (bank 2) */ 13962306a36Sopenharmony_ci#define TX_START 10 /* transmit start register */ 14062306a36Sopenharmony_ci#define COL_CTRL 11 /* 16 collision control register */ 14162306a36Sopenharmony_ci#define BMPR12 12 /* reserved */ 14262306a36Sopenharmony_ci#define BMPR13 13 /* reserved */ 14362306a36Sopenharmony_ci#define RX_SKIP 14 /* skip received packet register */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define LAN_CTRL 16 /* LAN card control register */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define MAC_ID 0x1a /* hardware address */ 14862306a36Sopenharmony_ci#define UNGERMANN_MAC_ID 0x18 /* UNGERMANN-BASS hardware address */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* 15162306a36Sopenharmony_ci control bits 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci#define ENA_TMT_OK 0x80 15462306a36Sopenharmony_ci#define ENA_TMT_REC 0x20 15562306a36Sopenharmony_ci#define ENA_COL 0x04 15662306a36Sopenharmony_ci#define ENA_16_COL 0x02 15762306a36Sopenharmony_ci#define ENA_TBUS_ERR 0x01 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#define ENA_PKT_RDY 0x80 16062306a36Sopenharmony_ci#define ENA_BUS_ERR 0x40 16162306a36Sopenharmony_ci#define ENA_LEN_ERR 0x08 16262306a36Sopenharmony_ci#define ENA_ALG_ERR 0x04 16362306a36Sopenharmony_ci#define ENA_CRC_ERR 0x02 16462306a36Sopenharmony_ci#define ENA_OVR_FLO 0x01 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* flags */ 16762306a36Sopenharmony_ci#define F_TMT_RDY 0x80 /* can accept new packet */ 16862306a36Sopenharmony_ci#define F_NET_BSY 0x40 /* carrier is detected */ 16962306a36Sopenharmony_ci#define F_TMT_OK 0x20 /* send packet successfully */ 17062306a36Sopenharmony_ci#define F_SRT_PKT 0x10 /* short packet error */ 17162306a36Sopenharmony_ci#define F_COL_ERR 0x04 /* collision error */ 17262306a36Sopenharmony_ci#define F_16_COL 0x02 /* 16 collision error */ 17362306a36Sopenharmony_ci#define F_TBUS_ERR 0x01 /* bus read error */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#define F_PKT_RDY 0x80 /* packet(s) in buffer */ 17662306a36Sopenharmony_ci#define F_BUS_ERR 0x40 /* bus read error */ 17762306a36Sopenharmony_ci#define F_LEN_ERR 0x08 /* short packet */ 17862306a36Sopenharmony_ci#define F_ALG_ERR 0x04 /* frame error */ 17962306a36Sopenharmony_ci#define F_CRC_ERR 0x02 /* CRC error */ 18062306a36Sopenharmony_ci#define F_OVR_FLO 0x01 /* overflow error */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#define F_BUF_EMP 0x40 /* receive buffer is empty */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define F_SKP_PKT 0x05 /* drop packet in buffer */ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* default bitmaps */ 18762306a36Sopenharmony_ci#define D_TX_INTR ( ENA_TMT_OK ) 18862306a36Sopenharmony_ci#define D_RX_INTR ( ENA_PKT_RDY | ENA_LEN_ERR \ 18962306a36Sopenharmony_ci | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO ) 19062306a36Sopenharmony_ci#define TX_STAT_M ( F_TMT_RDY ) 19162306a36Sopenharmony_ci#define RX_STAT_M ( F_PKT_RDY | F_LEN_ERR \ 19262306a36Sopenharmony_ci | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO ) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* commands */ 19562306a36Sopenharmony_ci#define D_TX_MODE 0x06 /* no tests, detect carrier */ 19662306a36Sopenharmony_ci#define ID_MATCHED 0x02 /* (RX_MODE) */ 19762306a36Sopenharmony_ci#define RECV_ALL 0x03 /* (RX_MODE) */ 19862306a36Sopenharmony_ci#define CONFIG0_DFL 0x5a /* 16bit bus, 4K x 2 Tx queues */ 19962306a36Sopenharmony_ci#define CONFIG0_DFL_1 0x5e /* 16bit bus, 8K x 2 Tx queues */ 20062306a36Sopenharmony_ci#define CONFIG0_RST 0xda /* Data Link Controller off (CONFIG_0) */ 20162306a36Sopenharmony_ci#define CONFIG0_RST_1 0xde /* Data Link Controller off (CONFIG_0) */ 20262306a36Sopenharmony_ci#define BANK_0 0xa0 /* bank 0 (CONFIG_1) */ 20362306a36Sopenharmony_ci#define BANK_1 0xa4 /* bank 1 (CONFIG_1) */ 20462306a36Sopenharmony_ci#define BANK_2 0xa8 /* bank 2 (CONFIG_1) */ 20562306a36Sopenharmony_ci#define CHIP_OFF 0x80 /* contrl chip power off (CONFIG_1) */ 20662306a36Sopenharmony_ci#define DO_TX 0x80 /* do transmit packet */ 20762306a36Sopenharmony_ci#define SEND_PKT 0x81 /* send a packet */ 20862306a36Sopenharmony_ci#define AUTO_MODE 0x07 /* Auto skip packet on 16 col detected */ 20962306a36Sopenharmony_ci#define MANU_MODE 0x03 /* Stop and skip packet on 16 col */ 21062306a36Sopenharmony_ci#define TDK_AUTO_MODE 0x47 /* Auto skip packet on 16 col detected */ 21162306a36Sopenharmony_ci#define TDK_MANU_MODE 0x43 /* Stop and skip packet on 16 col */ 21262306a36Sopenharmony_ci#define INTR_OFF 0x0d /* LAN controller ignores interrupts */ 21362306a36Sopenharmony_ci#define INTR_ON 0x1d /* LAN controller will catch interrupts */ 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#define TX_TIMEOUT ((400*HZ)/1000) 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci#define BANK_0U 0x20 /* bank 0 (CONFIG_1) */ 21862306a36Sopenharmony_ci#define BANK_1U 0x24 /* bank 1 (CONFIG_1) */ 21962306a36Sopenharmony_ci#define BANK_2U 0x28 /* bank 2 (CONFIG_1) */ 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic const struct net_device_ops fjn_netdev_ops = { 22262306a36Sopenharmony_ci .ndo_open = fjn_open, 22362306a36Sopenharmony_ci .ndo_stop = fjn_close, 22462306a36Sopenharmony_ci .ndo_start_xmit = fjn_start_xmit, 22562306a36Sopenharmony_ci .ndo_tx_timeout = fjn_tx_timeout, 22662306a36Sopenharmony_ci .ndo_set_config = fjn_config, 22762306a36Sopenharmony_ci .ndo_set_rx_mode = set_rx_mode, 22862306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 22962306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int fmvj18x_probe(struct pcmcia_device *link) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct local_info *lp; 23562306a36Sopenharmony_ci struct net_device *dev; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci dev_dbg(&link->dev, "fmvj18x_attach()\n"); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Make up a FMVJ18x specific data structure */ 24062306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct local_info)); 24162306a36Sopenharmony_ci if (!dev) 24262306a36Sopenharmony_ci return -ENOMEM; 24362306a36Sopenharmony_ci lp = netdev_priv(dev); 24462306a36Sopenharmony_ci link->priv = dev; 24562306a36Sopenharmony_ci lp->p_dev = link; 24662306a36Sopenharmony_ci lp->base = NULL; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* The io structure describes IO port mapping */ 24962306a36Sopenharmony_ci link->resource[0]->end = 32; 25062306a36Sopenharmony_ci link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* General socket configuration */ 25362306a36Sopenharmony_ci link->config_flags |= CONF_ENABLE_IRQ; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dev->netdev_ops = &fjn_netdev_ops; 25662306a36Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci dev->ethtool_ops = &netdev_ethtool_ops; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return fmvj18x_config(link); 26162306a36Sopenharmony_ci} /* fmvj18x_attach */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/*====================================================================*/ 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic void fmvj18x_detach(struct pcmcia_device *link) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct net_device *dev = link->priv; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci dev_dbg(&link->dev, "fmvj18x_detach\n"); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci unregister_netdev(dev); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci fmvj18x_release(link); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci free_netdev(dev); 27662306a36Sopenharmony_ci} /* fmvj18x_detach */ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/*====================================================================*/ 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int mfc_try_io_port(struct pcmcia_device *link) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int i, ret; 28362306a36Sopenharmony_ci static const unsigned int serial_base[5] = 28462306a36Sopenharmony_ci { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 28762306a36Sopenharmony_ci link->resource[1]->start = serial_base[i]; 28862306a36Sopenharmony_ci link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; 28962306a36Sopenharmony_ci if (link->resource[1]->start == 0) { 29062306a36Sopenharmony_ci link->resource[1]->end = 0; 29162306a36Sopenharmony_ci pr_notice("out of resource for serial\n"); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci ret = pcmcia_request_io(link); 29462306a36Sopenharmony_ci if (ret == 0) 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci return ret; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int ungermann_try_io_port(struct pcmcia_device *link) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci int ret; 30362306a36Sopenharmony_ci unsigned int ioaddr; 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360 30662306a36Sopenharmony_ci 0x380,0x3c0 only for ioport. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) { 30962306a36Sopenharmony_ci link->resource[0]->start = ioaddr; 31062306a36Sopenharmony_ci ret = pcmcia_request_io(link); 31162306a36Sopenharmony_ci if (ret == 0) { 31262306a36Sopenharmony_ci /* calculate ConfigIndex value */ 31362306a36Sopenharmony_ci link->config_index = 31462306a36Sopenharmony_ci ((link->resource[0]->start & 0x0f0) >> 3) | 0x22; 31562306a36Sopenharmony_ci return ret; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci return ret; /* RequestIO failed */ 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci return 0; /* strange, but that's what the code did already before... */ 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int fmvj18x_config(struct pcmcia_device *link) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct net_device *dev = link->priv; 32962306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 33062306a36Sopenharmony_ci int i, ret; 33162306a36Sopenharmony_ci unsigned int ioaddr; 33262306a36Sopenharmony_ci enum cardtype cardtype; 33362306a36Sopenharmony_ci char *card_name = "unknown"; 33462306a36Sopenharmony_ci u8 *buf; 33562306a36Sopenharmony_ci size_t len; 33662306a36Sopenharmony_ci u_char buggybuf[32]; 33762306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci dev_dbg(&link->dev, "fmvj18x_config\n"); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci link->io_lines = 5; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); 34462306a36Sopenharmony_ci kfree(buf); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (len) { 34762306a36Sopenharmony_ci /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ 34862306a36Sopenharmony_ci ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); 34962306a36Sopenharmony_ci if (ret != 0) 35062306a36Sopenharmony_ci goto failed; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci switch (link->manf_id) { 35362306a36Sopenharmony_ci case MANFID_TDK: 35462306a36Sopenharmony_ci cardtype = TDK; 35562306a36Sopenharmony_ci if (link->card_id == PRODID_TDK_GN3410 || 35662306a36Sopenharmony_ci link->card_id == PRODID_TDK_NP9610 || 35762306a36Sopenharmony_ci link->card_id == PRODID_TDK_MN3200) { 35862306a36Sopenharmony_ci /* MultiFunction Card */ 35962306a36Sopenharmony_ci link->config_base = 0x800; 36062306a36Sopenharmony_ci link->config_index = 0x47; 36162306a36Sopenharmony_ci link->resource[1]->end = 8; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci case MANFID_NEC: 36562306a36Sopenharmony_ci cardtype = NEC; /* MultiFunction Card */ 36662306a36Sopenharmony_ci link->config_base = 0x800; 36762306a36Sopenharmony_ci link->config_index = 0x47; 36862306a36Sopenharmony_ci link->resource[1]->end = 8; 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci case MANFID_KME: 37162306a36Sopenharmony_ci cardtype = KME; /* MultiFunction Card */ 37262306a36Sopenharmony_ci link->config_base = 0x800; 37362306a36Sopenharmony_ci link->config_index = 0x47; 37462306a36Sopenharmony_ci link->resource[1]->end = 8; 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case MANFID_CONTEC: 37762306a36Sopenharmony_ci cardtype = CONTEC; 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci case MANFID_FUJITSU: 38062306a36Sopenharmony_ci if (link->config_base == 0x0fe0) 38162306a36Sopenharmony_ci cardtype = MBH10302; 38262306a36Sopenharmony_ci else if (link->card_id == PRODID_FUJITSU_MBH10302) 38362306a36Sopenharmony_ci /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302), 38462306a36Sopenharmony_ci but these are MBH10304 based card. */ 38562306a36Sopenharmony_ci cardtype = MBH10304; 38662306a36Sopenharmony_ci else if (link->card_id == PRODID_FUJITSU_MBH10304) 38762306a36Sopenharmony_ci cardtype = MBH10304; 38862306a36Sopenharmony_ci else 38962306a36Sopenharmony_ci cardtype = LA501; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci default: 39262306a36Sopenharmony_ci cardtype = MBH10304; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } else { 39562306a36Sopenharmony_ci /* old type card */ 39662306a36Sopenharmony_ci switch (link->manf_id) { 39762306a36Sopenharmony_ci case MANFID_FUJITSU: 39862306a36Sopenharmony_ci if (link->card_id == PRODID_FUJITSU_MBH10304) { 39962306a36Sopenharmony_ci cardtype = XXX10304; /* MBH10304 with buggy CIS */ 40062306a36Sopenharmony_ci link->config_index = 0x20; 40162306a36Sopenharmony_ci } else { 40262306a36Sopenharmony_ci cardtype = MBH10302; /* NextCom NC5310, etc. */ 40362306a36Sopenharmony_ci link->config_index = 1; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci case MANFID_UNGERMANN: 40762306a36Sopenharmony_ci cardtype = UNGERMANN; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci default: 41062306a36Sopenharmony_ci cardtype = MBH10302; 41162306a36Sopenharmony_ci link->config_index = 1; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (link->resource[1]->end != 0) { 41662306a36Sopenharmony_ci ret = mfc_try_io_port(link); 41762306a36Sopenharmony_ci if (ret != 0) goto failed; 41862306a36Sopenharmony_ci } else if (cardtype == UNGERMANN) { 41962306a36Sopenharmony_ci ret = ungermann_try_io_port(link); 42062306a36Sopenharmony_ci if (ret != 0) goto failed; 42162306a36Sopenharmony_ci } else { 42262306a36Sopenharmony_ci ret = pcmcia_request_io(link); 42362306a36Sopenharmony_ci if (ret) 42462306a36Sopenharmony_ci goto failed; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci ret = pcmcia_request_irq(link, fjn_interrupt); 42762306a36Sopenharmony_ci if (ret) 42862306a36Sopenharmony_ci goto failed; 42962306a36Sopenharmony_ci ret = pcmcia_enable_device(link); 43062306a36Sopenharmony_ci if (ret) 43162306a36Sopenharmony_ci goto failed; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci dev->irq = link->irq; 43462306a36Sopenharmony_ci dev->base_addr = link->resource[0]->start; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (resource_size(link->resource[1]) != 0) { 43762306a36Sopenharmony_ci ret = fmvj18x_setup_mfc(link); 43862306a36Sopenharmony_ci if (ret != 0) goto failed; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ioaddr = dev->base_addr; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Reset controller */ 44462306a36Sopenharmony_ci if (sram_config == 0) 44562306a36Sopenharmony_ci outb(CONFIG0_RST, ioaddr + CONFIG_0); 44662306a36Sopenharmony_ci else 44762306a36Sopenharmony_ci outb(CONFIG0_RST_1, ioaddr + CONFIG_0); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Power On chip and select bank 0 */ 45062306a36Sopenharmony_ci if (cardtype == MBH10302) 45162306a36Sopenharmony_ci outb(BANK_0, ioaddr + CONFIG_1); 45262306a36Sopenharmony_ci else 45362306a36Sopenharmony_ci outb(BANK_0U, ioaddr + CONFIG_1); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Set hardware address */ 45662306a36Sopenharmony_ci switch (cardtype) { 45762306a36Sopenharmony_ci case MBH10304: 45862306a36Sopenharmony_ci case TDK: 45962306a36Sopenharmony_ci case LA501: 46062306a36Sopenharmony_ci case CONTEC: 46162306a36Sopenharmony_ci case NEC: 46262306a36Sopenharmony_ci case KME: 46362306a36Sopenharmony_ci if (cardtype == MBH10304) { 46462306a36Sopenharmony_ci card_name = "FMV-J182"; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); 46762306a36Sopenharmony_ci if (len < 11) { 46862306a36Sopenharmony_ci kfree(buf); 46962306a36Sopenharmony_ci goto failed; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci /* Read MACID from CIS */ 47262306a36Sopenharmony_ci eth_hw_addr_set(dev, &buf[5]); 47362306a36Sopenharmony_ci kfree(buf); 47462306a36Sopenharmony_ci } else { 47562306a36Sopenharmony_ci if (pcmcia_get_mac_from_cis(link, dev)) 47662306a36Sopenharmony_ci goto failed; 47762306a36Sopenharmony_ci if( cardtype == TDK ) { 47862306a36Sopenharmony_ci card_name = "TDK LAK-CD021"; 47962306a36Sopenharmony_ci } else if( cardtype == LA501 ) { 48062306a36Sopenharmony_ci card_name = "LA501"; 48162306a36Sopenharmony_ci } else if( cardtype == NEC ) { 48262306a36Sopenharmony_ci card_name = "PK-UG-J001"; 48362306a36Sopenharmony_ci } else if( cardtype == KME ) { 48462306a36Sopenharmony_ci card_name = "Panasonic"; 48562306a36Sopenharmony_ci } else { 48662306a36Sopenharmony_ci card_name = "C-NET(PC)C"; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci case UNGERMANN: 49162306a36Sopenharmony_ci /* Read MACID from register */ 49262306a36Sopenharmony_ci for (i = 0; i < 6; i++) 49362306a36Sopenharmony_ci addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i); 49462306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 49562306a36Sopenharmony_ci card_name = "Access/CARD"; 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case XXX10304: 49862306a36Sopenharmony_ci /* Read MACID from Buggy CIS */ 49962306a36Sopenharmony_ci if (fmvj18x_get_hwinfo(link, buggybuf) == -1) { 50062306a36Sopenharmony_ci pr_notice("unable to read hardware net address\n"); 50162306a36Sopenharmony_ci goto failed; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci eth_hw_addr_set(dev, buggybuf); 50462306a36Sopenharmony_ci card_name = "FMV-J182"; 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci case MBH10302: 50762306a36Sopenharmony_ci default: 50862306a36Sopenharmony_ci /* Read MACID from register */ 50962306a36Sopenharmony_ci for (i = 0; i < 6; i++) 51062306a36Sopenharmony_ci addr[i] = inb(ioaddr + MAC_ID + i); 51162306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 51262306a36Sopenharmony_ci card_name = "FMV-J181"; 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci lp->cardtype = cardtype; 51762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &link->dev); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (register_netdev(dev) != 0) { 52062306a36Sopenharmony_ci pr_notice("register_netdev() failed\n"); 52162306a36Sopenharmony_ci goto failed; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* print current configuration */ 52562306a36Sopenharmony_ci netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n", 52662306a36Sopenharmony_ci card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 52762306a36Sopenharmony_ci dev->base_addr, dev->irq, dev->dev_addr); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cifailed: 53262306a36Sopenharmony_ci fmvj18x_release(link); 53362306a36Sopenharmony_ci return -ENODEV; 53462306a36Sopenharmony_ci} /* fmvj18x_config */ 53562306a36Sopenharmony_ci/*====================================================================*/ 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci u_char __iomem *base; 54062306a36Sopenharmony_ci int i, j; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* Allocate a small memory window */ 54362306a36Sopenharmony_ci link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; 54462306a36Sopenharmony_ci link->resource[2]->start = 0; link->resource[2]->end = 0; 54562306a36Sopenharmony_ci i = pcmcia_request_window(link, link->resource[2], 0); 54662306a36Sopenharmony_ci if (i != 0) 54762306a36Sopenharmony_ci return -1; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci base = ioremap(link->resource[2]->start, resource_size(link->resource[2])); 55062306a36Sopenharmony_ci if (!base) { 55162306a36Sopenharmony_ci pcmcia_release_window(link, link->resource[2]); 55262306a36Sopenharmony_ci return -1; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci pcmcia_map_mem_page(link, link->resource[2], 0); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* 55862306a36Sopenharmony_ci * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format 55962306a36Sopenharmony_ci * 22 0d xx xx xx 04 06 yy yy yy yy yy yy ff 56062306a36Sopenharmony_ci * 'xx' is garbage. 56162306a36Sopenharmony_ci * 'yy' is MAC address. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci for (i = 0; i < 0x200; i++) { 56462306a36Sopenharmony_ci if (readb(base+i*2) == 0x22) { 56562306a36Sopenharmony_ci if (readb(base+(i-1)*2) == 0xff && 56662306a36Sopenharmony_ci readb(base+(i+5)*2) == 0x04 && 56762306a36Sopenharmony_ci readb(base+(i+6)*2) == 0x06 && 56862306a36Sopenharmony_ci readb(base+(i+13)*2) == 0xff) 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (i != 0x200) { 57462306a36Sopenharmony_ci for (j = 0 ; j < 6; j++,i++) { 57562306a36Sopenharmony_ci node_id[j] = readb(base+(i+7)*2); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci iounmap(base); 58062306a36Sopenharmony_ci j = pcmcia_release_window(link, link->resource[2]); 58162306a36Sopenharmony_ci return (i != 0x200) ? 0 : -1; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci} /* fmvj18x_get_hwinfo */ 58462306a36Sopenharmony_ci/*====================================================================*/ 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic int fmvj18x_setup_mfc(struct pcmcia_device *link) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci int i; 58962306a36Sopenharmony_ci struct net_device *dev = link->priv; 59062306a36Sopenharmony_ci unsigned int ioaddr; 59162306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Allocate a small memory window */ 59462306a36Sopenharmony_ci link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; 59562306a36Sopenharmony_ci link->resource[3]->start = link->resource[3]->end = 0; 59662306a36Sopenharmony_ci i = pcmcia_request_window(link, link->resource[3], 0); 59762306a36Sopenharmony_ci if (i != 0) 59862306a36Sopenharmony_ci return -1; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci lp->base = ioremap(link->resource[3]->start, 60162306a36Sopenharmony_ci resource_size(link->resource[3])); 60262306a36Sopenharmony_ci if (lp->base == NULL) { 60362306a36Sopenharmony_ci netdev_notice(dev, "ioremap failed\n"); 60462306a36Sopenharmony_ci return -1; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci i = pcmcia_map_mem_page(link, link->resource[3], 0); 60862306a36Sopenharmony_ci if (i != 0) { 60962306a36Sopenharmony_ci iounmap(lp->base); 61062306a36Sopenharmony_ci lp->base = NULL; 61162306a36Sopenharmony_ci return -1; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ioaddr = dev->base_addr; 61562306a36Sopenharmony_ci writeb(0x47, lp->base+0x800); /* Config Option Register of LAN */ 61662306a36Sopenharmony_ci writeb(0x0, lp->base+0x802); /* Config and Status Register */ 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci writeb(ioaddr & 0xff, lp->base+0x80a); /* I/O Base(Low) of LAN */ 61962306a36Sopenharmony_ci writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */ 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */ 62262306a36Sopenharmony_ci writeb(0x8, lp->base+0x822); /* Config and Status Register */ 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci/*====================================================================*/ 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void fmvj18x_release(struct pcmcia_device *link) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci struct net_device *dev = link->priv; 63362306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 63462306a36Sopenharmony_ci u_char __iomem *tmp; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci dev_dbg(&link->dev, "fmvj18x_release\n"); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (lp->base != NULL) { 63962306a36Sopenharmony_ci tmp = lp->base; 64062306a36Sopenharmony_ci lp->base = NULL; /* set NULL before iounmap */ 64162306a36Sopenharmony_ci iounmap(tmp); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci pcmcia_disable_device(link); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int fmvj18x_suspend(struct pcmcia_device *link) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct net_device *dev = link->priv; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (link->open) 65362306a36Sopenharmony_ci netif_device_detach(dev); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return 0; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int fmvj18x_resume(struct pcmcia_device *link) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct net_device *dev = link->priv; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (link->open) { 66362306a36Sopenharmony_ci fjn_reset(dev); 66462306a36Sopenharmony_ci netif_device_attach(dev); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/*====================================================================*/ 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic const struct pcmcia_device_id fmvj18x_ids[] = { 67362306a36Sopenharmony_ci PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004), 67462306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59), 67562306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922), 67662306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922), 67762306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db), 67862306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e), 67962306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2), 68062306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4), 68162306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0 ", 0x8cef4d3a, 0x075fc7b6), 68262306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0 ", 0x8cef4d3a, 0xbccf43e6), 68362306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666), 68462306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70), 68562306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a), 68662306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2), 68762306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304 ES", 0x2599f454), 68862306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da), 68962306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080), 69062306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed), 69162306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064), 69262306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a), 69362306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a), 69462306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01), 69562306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05), 69662306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05), 69762306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101), 69862306a36Sopenharmony_ci PCMCIA_DEVICE_NULL, 69962306a36Sopenharmony_ci}; 70062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic struct pcmcia_driver fmvj18x_cs_driver = { 70362306a36Sopenharmony_ci .owner = THIS_MODULE, 70462306a36Sopenharmony_ci .name = "fmvj18x_cs", 70562306a36Sopenharmony_ci .probe = fmvj18x_probe, 70662306a36Sopenharmony_ci .remove = fmvj18x_detach, 70762306a36Sopenharmony_ci .id_table = fmvj18x_ids, 70862306a36Sopenharmony_ci .suspend = fmvj18x_suspend, 70962306a36Sopenharmony_ci .resume = fmvj18x_resume, 71062306a36Sopenharmony_ci}; 71162306a36Sopenharmony_cimodule_pcmcia_driver(fmvj18x_cs_driver); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci/*====================================================================*/ 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic irqreturn_t fjn_interrupt(int dummy, void *dev_id) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct net_device *dev = dev_id; 71862306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 71962306a36Sopenharmony_ci unsigned int ioaddr; 72062306a36Sopenharmony_ci unsigned short tx_stat, rx_stat; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ioaddr = dev->base_addr; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* avoid multiple interrupts */ 72562306a36Sopenharmony_ci outw(0x0000, ioaddr + TX_INTR); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* wait for a while */ 72862306a36Sopenharmony_ci udelay(1); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* get status */ 73162306a36Sopenharmony_ci tx_stat = inb(ioaddr + TX_STATUS); 73262306a36Sopenharmony_ci rx_stat = inb(ioaddr + RX_STATUS); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* clear status */ 73562306a36Sopenharmony_ci outb(tx_stat, ioaddr + TX_STATUS); 73662306a36Sopenharmony_ci outb(rx_stat, ioaddr + RX_STATUS); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat); 73962306a36Sopenharmony_ci pr_debug(" tx_status %02x.\n", tx_stat); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { 74262306a36Sopenharmony_ci /* there is packet(s) in rx buffer */ 74362306a36Sopenharmony_ci fjn_rx(dev); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci if (tx_stat & F_TMT_RDY) { 74662306a36Sopenharmony_ci dev->stats.tx_packets += lp->sent ; 74762306a36Sopenharmony_ci lp->sent = 0 ; 74862306a36Sopenharmony_ci if (lp->tx_queue) { 74962306a36Sopenharmony_ci outb(DO_TX | lp->tx_queue, ioaddr + TX_START); 75062306a36Sopenharmony_ci lp->sent = lp->tx_queue ; 75162306a36Sopenharmony_ci lp->tx_queue = 0; 75262306a36Sopenharmony_ci lp->tx_queue_len = 0; 75362306a36Sopenharmony_ci netif_trans_update(dev); 75462306a36Sopenharmony_ci } else { 75562306a36Sopenharmony_ci lp->tx_started = 0; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci netif_wake_queue(dev); 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci pr_debug("%s: exiting interrupt,\n", dev->name); 76062306a36Sopenharmony_ci pr_debug(" tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci outb(D_TX_INTR, ioaddr + TX_INTR); 76362306a36Sopenharmony_ci outb(D_RX_INTR, ioaddr + RX_INTR); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (lp->base != NULL) { 76662306a36Sopenharmony_ci /* Ack interrupt for multifunction card */ 76762306a36Sopenharmony_ci writeb(0x01, lp->base+0x802); 76862306a36Sopenharmony_ci writeb(0x09, lp->base+0x822); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return IRQ_HANDLED; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci} /* fjn_interrupt */ 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci/*====================================================================*/ 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 78062306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci netdev_notice(dev, "transmit timed out with status %04x, %s?\n", 78362306a36Sopenharmony_ci htons(inw(ioaddr + TX_STATUS)), 78462306a36Sopenharmony_ci inb(ioaddr + TX_STATUS) & F_TMT_RDY 78562306a36Sopenharmony_ci ? "IRQ conflict" : "network cable problem"); 78662306a36Sopenharmony_ci netdev_notice(dev, "timeout registers: %04x %04x %04x " 78762306a36Sopenharmony_ci "%04x %04x %04x %04x %04x.\n", 78862306a36Sopenharmony_ci htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)), 78962306a36Sopenharmony_ci htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)), 79062306a36Sopenharmony_ci htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)), 79162306a36Sopenharmony_ci htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14))); 79262306a36Sopenharmony_ci dev->stats.tx_errors++; 79362306a36Sopenharmony_ci /* ToDo: We should try to restart the adaptor... */ 79462306a36Sopenharmony_ci local_irq_disable(); 79562306a36Sopenharmony_ci fjn_reset(dev); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci lp->tx_started = 0; 79862306a36Sopenharmony_ci lp->tx_queue = 0; 79962306a36Sopenharmony_ci lp->tx_queue_len = 0; 80062306a36Sopenharmony_ci lp->sent = 0; 80162306a36Sopenharmony_ci lp->open_time = jiffies; 80262306a36Sopenharmony_ci local_irq_enable(); 80362306a36Sopenharmony_ci netif_wake_queue(dev); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic netdev_tx_t fjn_start_xmit(struct sk_buff *skb, 80762306a36Sopenharmony_ci struct net_device *dev) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 81062306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 81162306a36Sopenharmony_ci short length = skb->len; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (length < ETH_ZLEN) 81462306a36Sopenharmony_ci { 81562306a36Sopenharmony_ci if (skb_padto(skb, ETH_ZLEN)) 81662306a36Sopenharmony_ci return NETDEV_TX_OK; 81762306a36Sopenharmony_ci length = ETH_ZLEN; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci netif_stop_queue(dev); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci { 82362306a36Sopenharmony_ci unsigned char *buf = skb->data; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (length > ETH_FRAME_LEN) { 82662306a36Sopenharmony_ci netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n", 82762306a36Sopenharmony_ci length); 82862306a36Sopenharmony_ci return NETDEV_TX_BUSY; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci netdev_dbg(dev, "Transmitting a packet of length %lu\n", 83262306a36Sopenharmony_ci (unsigned long)skb->len); 83362306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* Disable both interrupts. */ 83662306a36Sopenharmony_ci outw(0x0000, ioaddr + TX_INTR); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* wait for a while */ 83962306a36Sopenharmony_ci udelay(1); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci outw(length, ioaddr + DATAPORT); 84262306a36Sopenharmony_ci outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci lp->tx_queue++; 84562306a36Sopenharmony_ci lp->tx_queue_len += ((length+3) & ~1); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (lp->tx_started == 0) { 84862306a36Sopenharmony_ci /* If the Tx is idle, always trigger a transmit. */ 84962306a36Sopenharmony_ci outb(DO_TX | lp->tx_queue, ioaddr + TX_START); 85062306a36Sopenharmony_ci lp->sent = lp->tx_queue ; 85162306a36Sopenharmony_ci lp->tx_queue = 0; 85262306a36Sopenharmony_ci lp->tx_queue_len = 0; 85362306a36Sopenharmony_ci lp->tx_started = 1; 85462306a36Sopenharmony_ci netif_start_queue(dev); 85562306a36Sopenharmony_ci } else { 85662306a36Sopenharmony_ci if( sram_config == 0 ) { 85762306a36Sopenharmony_ci if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) ) 85862306a36Sopenharmony_ci /* Yes, there is room for one more packet. */ 85962306a36Sopenharmony_ci netif_start_queue(dev); 86062306a36Sopenharmony_ci } else { 86162306a36Sopenharmony_ci if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 86262306a36Sopenharmony_ci lp->tx_queue < 127 ) 86362306a36Sopenharmony_ci /* Yes, there is room for one more packet. */ 86462306a36Sopenharmony_ci netif_start_queue(dev); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* Re-enable interrupts */ 86962306a36Sopenharmony_ci outb(D_TX_INTR, ioaddr + TX_INTR); 87062306a36Sopenharmony_ci outb(D_RX_INTR, ioaddr + RX_INTR); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci dev_kfree_skb (skb); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return NETDEV_TX_OK; 87562306a36Sopenharmony_ci} /* fjn_start_xmit */ 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/*====================================================================*/ 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void fjn_reset(struct net_device *dev) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 88262306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 88362306a36Sopenharmony_ci int i; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci netdev_dbg(dev, "fjn_reset() called\n"); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Reset controller */ 88862306a36Sopenharmony_ci if( sram_config == 0 ) 88962306a36Sopenharmony_ci outb(CONFIG0_RST, ioaddr + CONFIG_0); 89062306a36Sopenharmony_ci else 89162306a36Sopenharmony_ci outb(CONFIG0_RST_1, ioaddr + CONFIG_0); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* Power On chip and select bank 0 */ 89462306a36Sopenharmony_ci if (lp->cardtype == MBH10302) 89562306a36Sopenharmony_ci outb(BANK_0, ioaddr + CONFIG_1); 89662306a36Sopenharmony_ci else 89762306a36Sopenharmony_ci outb(BANK_0U, ioaddr + CONFIG_1); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* Set Tx modes */ 90062306a36Sopenharmony_ci outb(D_TX_MODE, ioaddr + TX_MODE); 90162306a36Sopenharmony_ci /* set Rx modes */ 90262306a36Sopenharmony_ci outb(ID_MATCHED, ioaddr + RX_MODE); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* Set hardware address */ 90562306a36Sopenharmony_ci for (i = 0; i < 6; i++) 90662306a36Sopenharmony_ci outb(dev->dev_addr[i], ioaddr + NODE_ID + i); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci /* (re)initialize the multicast table */ 90962306a36Sopenharmony_ci set_rx_mode(dev); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* Switch to bank 2 (runtime mode) */ 91262306a36Sopenharmony_ci if (lp->cardtype == MBH10302) 91362306a36Sopenharmony_ci outb(BANK_2, ioaddr + CONFIG_1); 91462306a36Sopenharmony_ci else 91562306a36Sopenharmony_ci outb(BANK_2U, ioaddr + CONFIG_1); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* set 16col ctrl bits */ 91862306a36Sopenharmony_ci if( lp->cardtype == TDK || lp->cardtype == CONTEC) 91962306a36Sopenharmony_ci outb(TDK_AUTO_MODE, ioaddr + COL_CTRL); 92062306a36Sopenharmony_ci else 92162306a36Sopenharmony_ci outb(AUTO_MODE, ioaddr + COL_CTRL); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* clear Reserved Regs */ 92462306a36Sopenharmony_ci outb(0x00, ioaddr + BMPR12); 92562306a36Sopenharmony_ci outb(0x00, ioaddr + BMPR13); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* reset Skip packet reg. */ 92862306a36Sopenharmony_ci outb(0x01, ioaddr + RX_SKIP); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* Enable Tx and Rx */ 93162306a36Sopenharmony_ci if( sram_config == 0 ) 93262306a36Sopenharmony_ci outb(CONFIG0_DFL, ioaddr + CONFIG_0); 93362306a36Sopenharmony_ci else 93462306a36Sopenharmony_ci outb(CONFIG0_DFL_1, ioaddr + CONFIG_0); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Init receive pointer ? */ 93762306a36Sopenharmony_ci inw(ioaddr + DATAPORT); 93862306a36Sopenharmony_ci inw(ioaddr + DATAPORT); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* Clear all status */ 94162306a36Sopenharmony_ci outb(0xff, ioaddr + TX_STATUS); 94262306a36Sopenharmony_ci outb(0xff, ioaddr + RX_STATUS); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (lp->cardtype == MBH10302) 94562306a36Sopenharmony_ci outb(INTR_OFF, ioaddr + LAN_CTRL); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Turn on Rx interrupts */ 94862306a36Sopenharmony_ci outb(D_TX_INTR, ioaddr + TX_INTR); 94962306a36Sopenharmony_ci outb(D_RX_INTR, ioaddr + RX_INTR); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* Turn on interrupts from LAN card controller */ 95262306a36Sopenharmony_ci if (lp->cardtype == MBH10302) 95362306a36Sopenharmony_ci outb(INTR_ON, ioaddr + LAN_CTRL); 95462306a36Sopenharmony_ci} /* fjn_reset */ 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci/*====================================================================*/ 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic void fjn_rx(struct net_device *dev) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 96162306a36Sopenharmony_ci int boguscount = 10; /* 5 -> 10: by agy 19940922 */ 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci pr_debug("%s: in rx_packet(), rx_status %02x.\n", 96462306a36Sopenharmony_ci dev->name, inb(ioaddr + RX_STATUS)); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { 96762306a36Sopenharmony_ci u_short status = inw(ioaddr + DATAPORT); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n", 97062306a36Sopenharmony_ci inb(ioaddr + RX_MODE), status); 97162306a36Sopenharmony_ci#ifndef final_version 97262306a36Sopenharmony_ci if (status == 0) { 97362306a36Sopenharmony_ci outb(F_SKP_PKT, ioaddr + RX_SKIP); 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci#endif 97762306a36Sopenharmony_ci if ((status & 0xF0) != 0x20) { /* There was an error. */ 97862306a36Sopenharmony_ci dev->stats.rx_errors++; 97962306a36Sopenharmony_ci if (status & F_LEN_ERR) dev->stats.rx_length_errors++; 98062306a36Sopenharmony_ci if (status & F_ALG_ERR) dev->stats.rx_frame_errors++; 98162306a36Sopenharmony_ci if (status & F_CRC_ERR) dev->stats.rx_crc_errors++; 98262306a36Sopenharmony_ci if (status & F_OVR_FLO) dev->stats.rx_over_errors++; 98362306a36Sopenharmony_ci } else { 98462306a36Sopenharmony_ci u_short pkt_len = inw(ioaddr + DATAPORT); 98562306a36Sopenharmony_ci /* Malloc up new buffer. */ 98662306a36Sopenharmony_ci struct sk_buff *skb; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (pkt_len > 1550) { 98962306a36Sopenharmony_ci netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n", 99062306a36Sopenharmony_ci pkt_len); 99162306a36Sopenharmony_ci outb(F_SKP_PKT, ioaddr + RX_SKIP); 99262306a36Sopenharmony_ci dev->stats.rx_errors++; 99362306a36Sopenharmony_ci break; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci skb = netdev_alloc_skb(dev, pkt_len + 2); 99662306a36Sopenharmony_ci if (skb == NULL) { 99762306a36Sopenharmony_ci outb(F_SKP_PKT, ioaddr + RX_SKIP); 99862306a36Sopenharmony_ci dev->stats.rx_dropped++; 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci skb_reserve(skb, 2); 100362306a36Sopenharmony_ci insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), 100462306a36Sopenharmony_ci (pkt_len + 1) >> 1); 100562306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci { 100862306a36Sopenharmony_ci int i; 100962306a36Sopenharmony_ci pr_debug("%s: Rxed packet of length %d: ", 101062306a36Sopenharmony_ci dev->name, pkt_len); 101162306a36Sopenharmony_ci for (i = 0; i < 14; i++) 101262306a36Sopenharmony_ci pr_debug(" %02x", skb->data[i]); 101362306a36Sopenharmony_ci pr_debug(".\n"); 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci netif_rx(skb); 101762306a36Sopenharmony_ci dev->stats.rx_packets++; 101862306a36Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci if (--boguscount <= 0) 102162306a36Sopenharmony_ci break; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* If any worth-while packets have been received, dev_rint() 102562306a36Sopenharmony_ci has done a netif_wake_queue() for us and will work on them 102662306a36Sopenharmony_ci when we get to the bottom-half routine. */ 102762306a36Sopenharmony_ci/* 102862306a36Sopenharmony_ci if (lp->cardtype != TDK) { 102962306a36Sopenharmony_ci int i; 103062306a36Sopenharmony_ci for (i = 0; i < 20; i++) { 103162306a36Sopenharmony_ci if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP) 103262306a36Sopenharmony_ci break; 103362306a36Sopenharmony_ci (void)inw(ioaddr + DATAPORT); /+ dummy status read +/ 103462306a36Sopenharmony_ci outb(F_SKP_PKT, ioaddr + RX_SKIP); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (i > 0) 103862306a36Sopenharmony_ci pr_debug("%s: Exint Rx packet with mode %02x after " 103962306a36Sopenharmony_ci "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci*/ 104262306a36Sopenharmony_ci} /* fjn_rx */ 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci/*====================================================================*/ 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev, 104762306a36Sopenharmony_ci struct ethtool_drvinfo *info) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 105062306a36Sopenharmony_ci strscpy(info->version, DRV_VERSION, sizeof(info->version)); 105162306a36Sopenharmony_ci snprintf(info->bus_info, sizeof(info->bus_info), 105262306a36Sopenharmony_ci "PCMCIA 0x%lx", dev->base_addr); 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = { 105662306a36Sopenharmony_ci .get_drvinfo = netdev_get_drvinfo, 105762306a36Sopenharmony_ci}; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic int fjn_config(struct net_device *dev, struct ifmap *map){ 106062306a36Sopenharmony_ci return 0; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic int fjn_open(struct net_device *dev) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 106662306a36Sopenharmony_ci struct pcmcia_device *link = lp->p_dev; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci pr_debug("fjn_open('%s').\n", dev->name); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (!pcmcia_dev_present(link)) 107162306a36Sopenharmony_ci return -ENODEV; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci link->open++; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci fjn_reset(dev); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci lp->tx_started = 0; 107862306a36Sopenharmony_ci lp->tx_queue = 0; 107962306a36Sopenharmony_ci lp->tx_queue_len = 0; 108062306a36Sopenharmony_ci lp->open_time = jiffies; 108162306a36Sopenharmony_ci netif_start_queue(dev); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci} /* fjn_open */ 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci/*====================================================================*/ 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic int fjn_close(struct net_device *dev) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 109162306a36Sopenharmony_ci struct pcmcia_device *link = lp->p_dev; 109262306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci pr_debug("fjn_close('%s').\n", dev->name); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci lp->open_time = 0; 109762306a36Sopenharmony_ci netif_stop_queue(dev); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci /* Set configuration register 0 to disable Tx and Rx. */ 110062306a36Sopenharmony_ci if( sram_config == 0 ) 110162306a36Sopenharmony_ci outb(CONFIG0_RST ,ioaddr + CONFIG_0); 110262306a36Sopenharmony_ci else 110362306a36Sopenharmony_ci outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Update the statistics -- ToDo. */ 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Power-down the chip. Green, green, green! */ 110862306a36Sopenharmony_ci outb(CHIP_OFF ,ioaddr + CONFIG_1); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Set the ethernet adaptor disable IRQ */ 111162306a36Sopenharmony_ci if (lp->cardtype == MBH10302) 111262306a36Sopenharmony_ci outb(INTR_OFF, ioaddr + LAN_CTRL); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci link->open--; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci return 0; 111762306a36Sopenharmony_ci} /* fjn_close */ 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci/*====================================================================*/ 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci/* 112262306a36Sopenharmony_ci Set the multicast/promiscuous mode for this adaptor. 112362306a36Sopenharmony_ci*/ 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic void set_rx_mode(struct net_device *dev) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 112862306a36Sopenharmony_ci u_char mc_filter[8]; /* Multicast hash filter */ 112962306a36Sopenharmony_ci u_long flags; 113062306a36Sopenharmony_ci int i; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci int saved_bank; 113362306a36Sopenharmony_ci int saved_config_0 = inb(ioaddr + CONFIG_0); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci local_irq_save(flags); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci /* Disable Tx and Rx */ 113862306a36Sopenharmony_ci if (sram_config == 0) 113962306a36Sopenharmony_ci outb(CONFIG0_RST, ioaddr + CONFIG_0); 114062306a36Sopenharmony_ci else 114162306a36Sopenharmony_ci outb(CONFIG0_RST_1, ioaddr + CONFIG_0); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 114462306a36Sopenharmony_ci memset(mc_filter, 0xff, sizeof(mc_filter)); 114562306a36Sopenharmony_ci outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ 114662306a36Sopenharmony_ci } else if (netdev_mc_count(dev) > MC_FILTERBREAK || 114762306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI)) { 114862306a36Sopenharmony_ci /* Too many to filter perfectly -- accept all multicasts. */ 114962306a36Sopenharmony_ci memset(mc_filter, 0xff, sizeof(mc_filter)); 115062306a36Sopenharmony_ci outb(2, ioaddr + RX_MODE); /* Use normal mode. */ 115162306a36Sopenharmony_ci } else if (netdev_mc_empty(dev)) { 115262306a36Sopenharmony_ci memset(mc_filter, 0x00, sizeof(mc_filter)); 115362306a36Sopenharmony_ci outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */ 115462306a36Sopenharmony_ci } else { 115562306a36Sopenharmony_ci struct netdev_hw_addr *ha; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci memset(mc_filter, 0, sizeof(mc_filter)); 115862306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 115962306a36Sopenharmony_ci unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26; 116062306a36Sopenharmony_ci mc_filter[bit >> 3] |= (1 << (bit & 7)); 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci outb(2, ioaddr + RX_MODE); /* Use normal mode. */ 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* Switch to bank 1 and set the multicast table. */ 116662306a36Sopenharmony_ci saved_bank = inb(ioaddr + CONFIG_1); 116762306a36Sopenharmony_ci outb(0xe4, ioaddr + CONFIG_1); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci for (i = 0; i < 8; i++) 117062306a36Sopenharmony_ci outb(mc_filter[i], ioaddr + MAR_ADR + i); 117162306a36Sopenharmony_ci outb(saved_bank, ioaddr + CONFIG_1); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci outb(saved_config_0, ioaddr + CONFIG_0); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci local_irq_restore(flags); 117662306a36Sopenharmony_ci} 1177