xref: /openbmc/linux/drivers/net/ethernet/fujitsu/fmvj18x_cs.c (revision 562ef98a666eef8e32a6057af37a577163ab6946)
15346ebf6SJeff Kirsher /*======================================================================
25346ebf6SJeff Kirsher     fmvj18x_cs.c 2.8 2002/03/23
35346ebf6SJeff Kirsher 
45346ebf6SJeff Kirsher     A fmvj18x (and its compatibles) PCMCIA client driver
55346ebf6SJeff Kirsher 
65346ebf6SJeff Kirsher     Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp
75346ebf6SJeff Kirsher 
85346ebf6SJeff Kirsher     TDK LAK-CD021 and CONTEC C-NET(PC)C support added by
95346ebf6SJeff Kirsher     Nobuhiro Katayama, kata-n@po.iijnet.or.jp
105346ebf6SJeff Kirsher 
115346ebf6SJeff Kirsher     The PCMCIA client code is based on code written by David Hinds.
125346ebf6SJeff Kirsher     Network code is based on the "FMV-18x driver" by Yutaka TAMIYA
135346ebf6SJeff Kirsher     but is actually largely Donald Becker's AT1700 driver, which
145346ebf6SJeff Kirsher     carries the following attribution:
155346ebf6SJeff Kirsher 
165346ebf6SJeff Kirsher     Written 1993-94 by Donald Becker.
175346ebf6SJeff Kirsher 
185346ebf6SJeff Kirsher     Copyright 1993 United States Government as represented by the
195346ebf6SJeff Kirsher     Director, National Security Agency.
205346ebf6SJeff Kirsher 
215346ebf6SJeff Kirsher     This software may be used and distributed according to the terms
225346ebf6SJeff Kirsher     of the GNU General Public License, incorporated herein by reference.
235346ebf6SJeff Kirsher 
245346ebf6SJeff Kirsher     The author may be reached as becker@scyld.com, or C/O
255346ebf6SJeff Kirsher     Scyld Computing Corporation
265346ebf6SJeff Kirsher     410 Severn Ave., Suite 210
275346ebf6SJeff Kirsher     Annapolis MD 21403
285346ebf6SJeff Kirsher 
295346ebf6SJeff Kirsher ======================================================================*/
305346ebf6SJeff Kirsher 
315346ebf6SJeff Kirsher #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
325346ebf6SJeff Kirsher 
335346ebf6SJeff Kirsher #define DRV_NAME	"fmvj18x_cs"
345346ebf6SJeff Kirsher #define DRV_VERSION	"2.9"
355346ebf6SJeff Kirsher 
365346ebf6SJeff Kirsher #include <linux/module.h>
375346ebf6SJeff Kirsher #include <linux/kernel.h>
385346ebf6SJeff Kirsher #include <linux/ptrace.h>
395346ebf6SJeff Kirsher #include <linux/slab.h>
405346ebf6SJeff Kirsher #include <linux/string.h>
415346ebf6SJeff Kirsher #include <linux/timer.h>
425346ebf6SJeff Kirsher #include <linux/interrupt.h>
435346ebf6SJeff Kirsher #include <linux/in.h>
445346ebf6SJeff Kirsher #include <linux/delay.h>
455346ebf6SJeff Kirsher #include <linux/ethtool.h>
465346ebf6SJeff Kirsher #include <linux/netdevice.h>
475346ebf6SJeff Kirsher #include <linux/etherdevice.h>
485346ebf6SJeff Kirsher #include <linux/skbuff.h>
495346ebf6SJeff Kirsher #include <linux/if_arp.h>
505346ebf6SJeff Kirsher #include <linux/ioport.h>
515346ebf6SJeff Kirsher #include <linux/crc32.h>
525346ebf6SJeff Kirsher 
535346ebf6SJeff Kirsher #include <pcmcia/cistpl.h>
545346ebf6SJeff Kirsher #include <pcmcia/ciscode.h>
555346ebf6SJeff Kirsher #include <pcmcia/ds.h>
565346ebf6SJeff Kirsher 
577c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
585346ebf6SJeff Kirsher #include <asm/io.h>
595346ebf6SJeff Kirsher 
605346ebf6SJeff Kirsher /*====================================================================*/
615346ebf6SJeff Kirsher 
625346ebf6SJeff Kirsher /* Module parameters */
635346ebf6SJeff Kirsher 
645346ebf6SJeff Kirsher MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
655346ebf6SJeff Kirsher MODULE_LICENSE("GPL");
665346ebf6SJeff Kirsher 
675346ebf6SJeff Kirsher #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
685346ebf6SJeff Kirsher 
695346ebf6SJeff Kirsher /* SRAM configuration */
705346ebf6SJeff Kirsher /* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
715346ebf6SJeff Kirsher INT_MODULE_PARM(sram_config, 0);
725346ebf6SJeff Kirsher 
735346ebf6SJeff Kirsher 
745346ebf6SJeff Kirsher /*====================================================================*/
755346ebf6SJeff Kirsher /*
765346ebf6SJeff Kirsher     PCMCIA event handlers
775346ebf6SJeff Kirsher  */
785346ebf6SJeff Kirsher static int fmvj18x_config(struct pcmcia_device *link);
795346ebf6SJeff Kirsher static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id);
805346ebf6SJeff Kirsher static int fmvj18x_setup_mfc(struct pcmcia_device *link);
815346ebf6SJeff Kirsher static void fmvj18x_release(struct pcmcia_device *link);
825346ebf6SJeff Kirsher static void fmvj18x_detach(struct pcmcia_device *p_dev);
835346ebf6SJeff Kirsher 
845346ebf6SJeff Kirsher /*
855346ebf6SJeff Kirsher     LAN controller(MBH86960A) specific routines
865346ebf6SJeff Kirsher  */
875346ebf6SJeff Kirsher static int fjn_config(struct net_device *dev, struct ifmap *map);
885346ebf6SJeff Kirsher static int fjn_open(struct net_device *dev);
895346ebf6SJeff Kirsher static int fjn_close(struct net_device *dev);
905346ebf6SJeff Kirsher static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
915346ebf6SJeff Kirsher 					struct net_device *dev);
925346ebf6SJeff Kirsher static irqreturn_t fjn_interrupt(int irq, void *dev_id);
935346ebf6SJeff Kirsher static void fjn_rx(struct net_device *dev);
945346ebf6SJeff Kirsher static void fjn_reset(struct net_device *dev);
955346ebf6SJeff Kirsher static void set_rx_mode(struct net_device *dev);
960290bd29SMichael S. Tsirkin static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue);
975346ebf6SJeff Kirsher static const struct ethtool_ops netdev_ethtool_ops;
985346ebf6SJeff Kirsher 
995346ebf6SJeff Kirsher /*
1005346ebf6SJeff Kirsher     card type
1015346ebf6SJeff Kirsher  */
102f073d52dSHimangi Saraogi enum cardtype { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
1035346ebf6SJeff Kirsher 	       XXX10304, NEC, KME
104f073d52dSHimangi Saraogi };
1055346ebf6SJeff Kirsher 
1065346ebf6SJeff Kirsher /*
1075346ebf6SJeff Kirsher     driver specific data structure
1085346ebf6SJeff Kirsher */
109f073d52dSHimangi Saraogi struct local_info {
1105346ebf6SJeff Kirsher 	struct pcmcia_device	*p_dev;
1115346ebf6SJeff Kirsher     long open_time;
1125346ebf6SJeff Kirsher     uint tx_started:1;
1135346ebf6SJeff Kirsher     uint tx_queue;
1145346ebf6SJeff Kirsher     u_short tx_queue_len;
115f073d52dSHimangi Saraogi     enum cardtype cardtype;
1165346ebf6SJeff Kirsher     u_short sent;
1175346ebf6SJeff Kirsher     u_char __iomem *base;
118f073d52dSHimangi Saraogi };
1195346ebf6SJeff Kirsher 
1205346ebf6SJeff Kirsher #define MC_FILTERBREAK 64
1215346ebf6SJeff Kirsher 
1225346ebf6SJeff Kirsher /*====================================================================*/
1235346ebf6SJeff Kirsher /*
1245346ebf6SJeff Kirsher     ioport offset from the base address
1255346ebf6SJeff Kirsher  */
1265346ebf6SJeff Kirsher #define TX_STATUS               0 /* transmit status register */
1275346ebf6SJeff Kirsher #define RX_STATUS               1 /* receive status register */
1285346ebf6SJeff Kirsher #define TX_INTR                 2 /* transmit interrupt mask register */
1295346ebf6SJeff Kirsher #define RX_INTR                 3 /* receive interrupt mask register */
1305346ebf6SJeff Kirsher #define TX_MODE                 4 /* transmit mode register */
1315346ebf6SJeff Kirsher #define RX_MODE                 5 /* receive mode register */
1325346ebf6SJeff Kirsher #define CONFIG_0                6 /* configuration register 0 */
1335346ebf6SJeff Kirsher #define CONFIG_1                7 /* configuration register 1 */
1345346ebf6SJeff Kirsher 
1355346ebf6SJeff Kirsher #define NODE_ID                 8 /* node ID register            (bank 0) */
1365346ebf6SJeff Kirsher #define MAR_ADR                 8 /* multicast address registers (bank 1) */
1375346ebf6SJeff Kirsher 
1385346ebf6SJeff Kirsher #define DATAPORT                8 /* buffer mem port registers   (bank 2) */
1395346ebf6SJeff Kirsher #define TX_START               10 /* transmit start register */
1405346ebf6SJeff Kirsher #define COL_CTRL               11 /* 16 collision control register */
1415346ebf6SJeff Kirsher #define BMPR12                 12 /* reserved */
1425346ebf6SJeff Kirsher #define BMPR13                 13 /* reserved */
1435346ebf6SJeff Kirsher #define RX_SKIP                14 /* skip received packet register */
1445346ebf6SJeff Kirsher 
1455346ebf6SJeff Kirsher #define LAN_CTRL               16 /* LAN card control register */
1465346ebf6SJeff Kirsher 
1475346ebf6SJeff Kirsher #define MAC_ID               0x1a /* hardware address */
1485346ebf6SJeff Kirsher #define UNGERMANN_MAC_ID     0x18 /* UNGERMANN-BASS hardware address */
1495346ebf6SJeff Kirsher 
1505346ebf6SJeff Kirsher /*
1515346ebf6SJeff Kirsher     control bits
1525346ebf6SJeff Kirsher  */
1535346ebf6SJeff Kirsher #define ENA_TMT_OK           0x80
1545346ebf6SJeff Kirsher #define ENA_TMT_REC          0x20
1555346ebf6SJeff Kirsher #define ENA_COL              0x04
1565346ebf6SJeff Kirsher #define ENA_16_COL           0x02
1575346ebf6SJeff Kirsher #define ENA_TBUS_ERR         0x01
1585346ebf6SJeff Kirsher 
1595346ebf6SJeff Kirsher #define ENA_PKT_RDY          0x80
1605346ebf6SJeff Kirsher #define ENA_BUS_ERR          0x40
1615346ebf6SJeff Kirsher #define ENA_LEN_ERR          0x08
1625346ebf6SJeff Kirsher #define ENA_ALG_ERR          0x04
1635346ebf6SJeff Kirsher #define ENA_CRC_ERR          0x02
1645346ebf6SJeff Kirsher #define ENA_OVR_FLO          0x01
1655346ebf6SJeff Kirsher 
1665346ebf6SJeff Kirsher /* flags */
1675346ebf6SJeff Kirsher #define F_TMT_RDY            0x80 /* can accept new packet */
1685346ebf6SJeff Kirsher #define F_NET_BSY            0x40 /* carrier is detected */
1695346ebf6SJeff Kirsher #define F_TMT_OK             0x20 /* send packet successfully */
1705346ebf6SJeff Kirsher #define F_SRT_PKT            0x10 /* short packet error */
1715346ebf6SJeff Kirsher #define F_COL_ERR            0x04 /* collision error */
1725346ebf6SJeff Kirsher #define F_16_COL             0x02 /* 16 collision error */
1735346ebf6SJeff Kirsher #define F_TBUS_ERR           0x01 /* bus read error */
1745346ebf6SJeff Kirsher 
1755346ebf6SJeff Kirsher #define F_PKT_RDY            0x80 /* packet(s) in buffer */
1765346ebf6SJeff Kirsher #define F_BUS_ERR            0x40 /* bus read error */
1775346ebf6SJeff Kirsher #define F_LEN_ERR            0x08 /* short packet */
1785346ebf6SJeff Kirsher #define F_ALG_ERR            0x04 /* frame error */
1795346ebf6SJeff Kirsher #define F_CRC_ERR            0x02 /* CRC error */
1805346ebf6SJeff Kirsher #define F_OVR_FLO            0x01 /* overflow error */
1815346ebf6SJeff Kirsher 
1825346ebf6SJeff Kirsher #define F_BUF_EMP            0x40 /* receive buffer is empty */
1835346ebf6SJeff Kirsher 
1845346ebf6SJeff Kirsher #define F_SKP_PKT            0x05 /* drop packet in buffer */
1855346ebf6SJeff Kirsher 
1865346ebf6SJeff Kirsher /* default bitmaps */
1875346ebf6SJeff Kirsher #define D_TX_INTR  ( ENA_TMT_OK )
1885346ebf6SJeff Kirsher #define D_RX_INTR  ( ENA_PKT_RDY | ENA_LEN_ERR \
1895346ebf6SJeff Kirsher 		   | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
1905346ebf6SJeff Kirsher #define TX_STAT_M  ( F_TMT_RDY )
1915346ebf6SJeff Kirsher #define RX_STAT_M  ( F_PKT_RDY | F_LEN_ERR \
1925346ebf6SJeff Kirsher                    | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
1935346ebf6SJeff Kirsher 
1945346ebf6SJeff Kirsher /* commands */
1955346ebf6SJeff Kirsher #define D_TX_MODE            0x06 /* no tests, detect carrier */
1965346ebf6SJeff Kirsher #define ID_MATCHED           0x02 /* (RX_MODE) */
1975346ebf6SJeff Kirsher #define RECV_ALL             0x03 /* (RX_MODE) */
1985346ebf6SJeff Kirsher #define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
1995346ebf6SJeff Kirsher #define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
2005346ebf6SJeff Kirsher #define CONFIG0_RST          0xda /* Data Link Controller off (CONFIG_0) */
2015346ebf6SJeff Kirsher #define CONFIG0_RST_1        0xde /* Data Link Controller off (CONFIG_0) */
2025346ebf6SJeff Kirsher #define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
2035346ebf6SJeff Kirsher #define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
2045346ebf6SJeff Kirsher #define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
2055346ebf6SJeff Kirsher #define CHIP_OFF             0x80 /* contrl chip power off (CONFIG_1) */
2065346ebf6SJeff Kirsher #define DO_TX                0x80 /* do transmit packet */
2075346ebf6SJeff Kirsher #define SEND_PKT             0x81 /* send a packet */
2085346ebf6SJeff Kirsher #define AUTO_MODE            0x07 /* Auto skip packet on 16 col detected */
2095346ebf6SJeff Kirsher #define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
2105346ebf6SJeff Kirsher #define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
2115346ebf6SJeff Kirsher #define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
2125346ebf6SJeff Kirsher #define INTR_OFF             0x0d /* LAN controller ignores interrupts */
2135346ebf6SJeff Kirsher #define INTR_ON              0x1d /* LAN controller will catch interrupts */
2145346ebf6SJeff Kirsher 
2155346ebf6SJeff Kirsher #define TX_TIMEOUT		((400*HZ)/1000)
2165346ebf6SJeff Kirsher 
2175346ebf6SJeff Kirsher #define BANK_0U              0x20 /* bank 0 (CONFIG_1) */
2185346ebf6SJeff Kirsher #define BANK_1U              0x24 /* bank 1 (CONFIG_1) */
2195346ebf6SJeff Kirsher #define BANK_2U              0x28 /* bank 2 (CONFIG_1) */
2205346ebf6SJeff Kirsher 
2215346ebf6SJeff Kirsher static const struct net_device_ops fjn_netdev_ops = {
2225346ebf6SJeff Kirsher 	.ndo_open 		= fjn_open,
2235346ebf6SJeff Kirsher 	.ndo_stop		= fjn_close,
2245346ebf6SJeff Kirsher 	.ndo_start_xmit 	= fjn_start_xmit,
2255346ebf6SJeff Kirsher 	.ndo_tx_timeout 	= fjn_tx_timeout,
2265346ebf6SJeff Kirsher 	.ndo_set_config 	= fjn_config,
227afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= set_rx_mode,
2285346ebf6SJeff Kirsher 	.ndo_set_mac_address 	= eth_mac_addr,
2295346ebf6SJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
2305346ebf6SJeff Kirsher };
2315346ebf6SJeff Kirsher 
2325346ebf6SJeff Kirsher static int fmvj18x_probe(struct pcmcia_device *link)
2335346ebf6SJeff Kirsher {
234f073d52dSHimangi Saraogi     struct local_info *lp;
2355346ebf6SJeff Kirsher     struct net_device *dev;
2365346ebf6SJeff Kirsher 
2375346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_attach()\n");
2385346ebf6SJeff Kirsher 
2395346ebf6SJeff Kirsher     /* Make up a FMVJ18x specific data structure */
240f073d52dSHimangi Saraogi     dev = alloc_etherdev(sizeof(struct local_info));
2415346ebf6SJeff Kirsher     if (!dev)
2425346ebf6SJeff Kirsher 	return -ENOMEM;
2435346ebf6SJeff Kirsher     lp = netdev_priv(dev);
2445346ebf6SJeff Kirsher     link->priv = dev;
2455346ebf6SJeff Kirsher     lp->p_dev = link;
2465346ebf6SJeff Kirsher     lp->base = NULL;
2475346ebf6SJeff Kirsher 
2485346ebf6SJeff Kirsher     /* The io structure describes IO port mapping */
2495346ebf6SJeff Kirsher     link->resource[0]->end = 32;
2505346ebf6SJeff Kirsher     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
2515346ebf6SJeff Kirsher 
2525346ebf6SJeff Kirsher     /* General socket configuration */
2535346ebf6SJeff Kirsher     link->config_flags |= CONF_ENABLE_IRQ;
2545346ebf6SJeff Kirsher 
2555346ebf6SJeff Kirsher     dev->netdev_ops = &fjn_netdev_ops;
2565346ebf6SJeff Kirsher     dev->watchdog_timeo = TX_TIMEOUT;
2575346ebf6SJeff Kirsher 
2587ad24ea4SWilfried Klaebe     dev->ethtool_ops = &netdev_ethtool_ops;
2595346ebf6SJeff Kirsher 
2605346ebf6SJeff Kirsher     return fmvj18x_config(link);
2615346ebf6SJeff Kirsher } /* fmvj18x_attach */
2625346ebf6SJeff Kirsher 
2635346ebf6SJeff Kirsher /*====================================================================*/
2645346ebf6SJeff Kirsher 
2655346ebf6SJeff Kirsher static void fmvj18x_detach(struct pcmcia_device *link)
2665346ebf6SJeff Kirsher {
2675346ebf6SJeff Kirsher     struct net_device *dev = link->priv;
2685346ebf6SJeff Kirsher 
2695346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_detach\n");
2705346ebf6SJeff Kirsher 
2715346ebf6SJeff Kirsher     unregister_netdev(dev);
2725346ebf6SJeff Kirsher 
2735346ebf6SJeff Kirsher     fmvj18x_release(link);
2745346ebf6SJeff Kirsher 
2755346ebf6SJeff Kirsher     free_netdev(dev);
2765346ebf6SJeff Kirsher } /* fmvj18x_detach */
2775346ebf6SJeff Kirsher 
2785346ebf6SJeff Kirsher /*====================================================================*/
2795346ebf6SJeff Kirsher 
2805346ebf6SJeff Kirsher static int mfc_try_io_port(struct pcmcia_device *link)
2815346ebf6SJeff Kirsher {
2825346ebf6SJeff Kirsher     int i, ret;
2835346ebf6SJeff Kirsher     static const unsigned int serial_base[5] =
2845346ebf6SJeff Kirsher 	{ 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
2855346ebf6SJeff Kirsher 
2865346ebf6SJeff Kirsher     for (i = 0; i < 5; i++) {
2875346ebf6SJeff Kirsher 	link->resource[1]->start = serial_base[i];
2885346ebf6SJeff Kirsher 	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
2895346ebf6SJeff Kirsher 	if (link->resource[1]->start == 0) {
2905346ebf6SJeff Kirsher 	    link->resource[1]->end = 0;
2915346ebf6SJeff Kirsher 	    pr_notice("out of resource for serial\n");
2925346ebf6SJeff Kirsher 	}
2935346ebf6SJeff Kirsher 	ret = pcmcia_request_io(link);
2945346ebf6SJeff Kirsher 	if (ret == 0)
2955346ebf6SJeff Kirsher 		return ret;
2965346ebf6SJeff Kirsher     }
2975346ebf6SJeff Kirsher     return ret;
2985346ebf6SJeff Kirsher }
2995346ebf6SJeff Kirsher 
3005346ebf6SJeff Kirsher static int ungermann_try_io_port(struct pcmcia_device *link)
3015346ebf6SJeff Kirsher {
3025346ebf6SJeff Kirsher     int ret;
3035346ebf6SJeff Kirsher     unsigned int ioaddr;
3045346ebf6SJeff Kirsher     /*
3055346ebf6SJeff Kirsher 	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
3065346ebf6SJeff Kirsher 	0x380,0x3c0 only for ioport.
3075346ebf6SJeff Kirsher     */
3085346ebf6SJeff Kirsher     for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
3095346ebf6SJeff Kirsher 	link->resource[0]->start = ioaddr;
3105346ebf6SJeff Kirsher 	ret = pcmcia_request_io(link);
3115346ebf6SJeff Kirsher 	if (ret == 0) {
3125346ebf6SJeff Kirsher 	    /* calculate ConfigIndex value */
3135346ebf6SJeff Kirsher 	    link->config_index =
3145346ebf6SJeff Kirsher 		((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
3155346ebf6SJeff Kirsher 	    return ret;
3165346ebf6SJeff Kirsher 	}
3175346ebf6SJeff Kirsher     }
3185346ebf6SJeff Kirsher     return ret;	/* RequestIO failed */
3195346ebf6SJeff Kirsher }
3205346ebf6SJeff Kirsher 
3215346ebf6SJeff Kirsher static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
3225346ebf6SJeff Kirsher {
3235346ebf6SJeff Kirsher 	return 0; /* strange, but that's what the code did already before... */
3245346ebf6SJeff Kirsher }
3255346ebf6SJeff Kirsher 
3265346ebf6SJeff Kirsher static int fmvj18x_config(struct pcmcia_device *link)
3275346ebf6SJeff Kirsher {
3285346ebf6SJeff Kirsher     struct net_device *dev = link->priv;
329f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
3305346ebf6SJeff Kirsher     int i, ret;
3315346ebf6SJeff Kirsher     unsigned int ioaddr;
332f073d52dSHimangi Saraogi     enum cardtype cardtype;
3335346ebf6SJeff Kirsher     char *card_name = "unknown";
3345346ebf6SJeff Kirsher     u8 *buf;
3355346ebf6SJeff Kirsher     size_t len;
3365346ebf6SJeff Kirsher     u_char buggybuf[32];
3375346ebf6SJeff Kirsher 
3385346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_config\n");
3395346ebf6SJeff Kirsher 
3405346ebf6SJeff Kirsher     link->io_lines = 5;
3415346ebf6SJeff Kirsher 
3425346ebf6SJeff Kirsher     len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
3435346ebf6SJeff Kirsher     kfree(buf);
3445346ebf6SJeff Kirsher 
3455346ebf6SJeff Kirsher     if (len) {
3465346ebf6SJeff Kirsher 	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
3475346ebf6SJeff Kirsher 	ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL);
3485346ebf6SJeff Kirsher 	if (ret != 0)
3495346ebf6SJeff Kirsher 		goto failed;
3505346ebf6SJeff Kirsher 
3515346ebf6SJeff Kirsher 	switch (link->manf_id) {
3525346ebf6SJeff Kirsher 	case MANFID_TDK:
3535346ebf6SJeff Kirsher 	    cardtype = TDK;
3545346ebf6SJeff Kirsher 	    if (link->card_id == PRODID_TDK_GN3410 ||
3555346ebf6SJeff Kirsher 		link->card_id == PRODID_TDK_NP9610 ||
3565346ebf6SJeff Kirsher 		link->card_id == PRODID_TDK_MN3200) {
3575346ebf6SJeff Kirsher 		/* MultiFunction Card */
3585346ebf6SJeff Kirsher 		link->config_base = 0x800;
3595346ebf6SJeff Kirsher 		link->config_index = 0x47;
3605346ebf6SJeff Kirsher 		link->resource[1]->end = 8;
3615346ebf6SJeff Kirsher 	    }
3625346ebf6SJeff Kirsher 	    break;
3635346ebf6SJeff Kirsher 	case MANFID_NEC:
3645346ebf6SJeff Kirsher 	    cardtype = NEC; /* MultiFunction Card */
3655346ebf6SJeff Kirsher 	    link->config_base = 0x800;
3665346ebf6SJeff Kirsher 	    link->config_index = 0x47;
3675346ebf6SJeff Kirsher 	    link->resource[1]->end = 8;
3685346ebf6SJeff Kirsher 	    break;
3695346ebf6SJeff Kirsher 	case MANFID_KME:
3705346ebf6SJeff Kirsher 	    cardtype = KME; /* MultiFunction Card */
3715346ebf6SJeff Kirsher 	    link->config_base = 0x800;
3725346ebf6SJeff Kirsher 	    link->config_index = 0x47;
3735346ebf6SJeff Kirsher 	    link->resource[1]->end = 8;
3745346ebf6SJeff Kirsher 	    break;
3755346ebf6SJeff Kirsher 	case MANFID_CONTEC:
3765346ebf6SJeff Kirsher 	    cardtype = CONTEC;
3775346ebf6SJeff Kirsher 	    break;
3785346ebf6SJeff Kirsher 	case MANFID_FUJITSU:
3795346ebf6SJeff Kirsher 	    if (link->config_base == 0x0fe0)
3805346ebf6SJeff Kirsher 		cardtype = MBH10302;
3815346ebf6SJeff Kirsher 	    else if (link->card_id == PRODID_FUJITSU_MBH10302)
3825346ebf6SJeff Kirsher                 /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
3835346ebf6SJeff Kirsher                    but these are MBH10304 based card. */
3845346ebf6SJeff Kirsher 		cardtype = MBH10304;
3855346ebf6SJeff Kirsher 	    else if (link->card_id == PRODID_FUJITSU_MBH10304)
3865346ebf6SJeff Kirsher 		cardtype = MBH10304;
3875346ebf6SJeff Kirsher 	    else
3885346ebf6SJeff Kirsher 		cardtype = LA501;
3895346ebf6SJeff Kirsher 	    break;
3905346ebf6SJeff Kirsher 	default:
3915346ebf6SJeff Kirsher 	    cardtype = MBH10304;
3925346ebf6SJeff Kirsher 	}
3935346ebf6SJeff Kirsher     } else {
3945346ebf6SJeff Kirsher 	/* old type card */
3955346ebf6SJeff Kirsher 	switch (link->manf_id) {
3965346ebf6SJeff Kirsher 	case MANFID_FUJITSU:
3975346ebf6SJeff Kirsher 	    if (link->card_id == PRODID_FUJITSU_MBH10304) {
3985346ebf6SJeff Kirsher 		cardtype = XXX10304;    /* MBH10304 with buggy CIS */
3995346ebf6SJeff Kirsher 		link->config_index = 0x20;
4005346ebf6SJeff Kirsher 	    } else {
4015346ebf6SJeff Kirsher 		cardtype = MBH10302;    /* NextCom NC5310, etc. */
4025346ebf6SJeff Kirsher 		link->config_index = 1;
4035346ebf6SJeff Kirsher 	    }
4045346ebf6SJeff Kirsher 	    break;
4055346ebf6SJeff Kirsher 	case MANFID_UNGERMANN:
4065346ebf6SJeff Kirsher 	    cardtype = UNGERMANN;
4075346ebf6SJeff Kirsher 	    break;
4085346ebf6SJeff Kirsher 	default:
4095346ebf6SJeff Kirsher 	    cardtype = MBH10302;
4105346ebf6SJeff Kirsher 	    link->config_index = 1;
4115346ebf6SJeff Kirsher 	}
4125346ebf6SJeff Kirsher     }
4135346ebf6SJeff Kirsher 
4145346ebf6SJeff Kirsher     if (link->resource[1]->end != 0) {
4155346ebf6SJeff Kirsher 	ret = mfc_try_io_port(link);
4165346ebf6SJeff Kirsher 	if (ret != 0) goto failed;
4175346ebf6SJeff Kirsher     } else if (cardtype == UNGERMANN) {
4185346ebf6SJeff Kirsher 	ret = ungermann_try_io_port(link);
4195346ebf6SJeff Kirsher 	if (ret != 0) goto failed;
4205346ebf6SJeff Kirsher     } else {
4215346ebf6SJeff Kirsher 	    ret = pcmcia_request_io(link);
4225346ebf6SJeff Kirsher 	    if (ret)
4235346ebf6SJeff Kirsher 		    goto failed;
4245346ebf6SJeff Kirsher     }
4255346ebf6SJeff Kirsher     ret = pcmcia_request_irq(link, fjn_interrupt);
4265346ebf6SJeff Kirsher     if (ret)
4275346ebf6SJeff Kirsher 	    goto failed;
4285346ebf6SJeff Kirsher     ret = pcmcia_enable_device(link);
4295346ebf6SJeff Kirsher     if (ret)
4305346ebf6SJeff Kirsher 	    goto failed;
4315346ebf6SJeff Kirsher 
4325346ebf6SJeff Kirsher     dev->irq = link->irq;
4335346ebf6SJeff Kirsher     dev->base_addr = link->resource[0]->start;
4345346ebf6SJeff Kirsher 
4355346ebf6SJeff Kirsher     if (resource_size(link->resource[1]) != 0) {
4365346ebf6SJeff Kirsher 	ret = fmvj18x_setup_mfc(link);
4375346ebf6SJeff Kirsher 	if (ret != 0) goto failed;
4385346ebf6SJeff Kirsher     }
4395346ebf6SJeff Kirsher 
4405346ebf6SJeff Kirsher     ioaddr = dev->base_addr;
4415346ebf6SJeff Kirsher 
4425346ebf6SJeff Kirsher     /* Reset controller */
4435346ebf6SJeff Kirsher     if (sram_config == 0)
4445346ebf6SJeff Kirsher 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
4455346ebf6SJeff Kirsher     else
4465346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
4475346ebf6SJeff Kirsher 
4485346ebf6SJeff Kirsher     /* Power On chip and select bank 0 */
4495346ebf6SJeff Kirsher     if (cardtype == MBH10302)
4505346ebf6SJeff Kirsher 	outb(BANK_0, ioaddr + CONFIG_1);
4515346ebf6SJeff Kirsher     else
4525346ebf6SJeff Kirsher 	outb(BANK_0U, ioaddr + CONFIG_1);
4535346ebf6SJeff Kirsher 
4545346ebf6SJeff Kirsher     /* Set hardware address */
4555346ebf6SJeff Kirsher     switch (cardtype) {
4565346ebf6SJeff Kirsher     case MBH10304:
4575346ebf6SJeff Kirsher     case TDK:
4585346ebf6SJeff Kirsher     case LA501:
4595346ebf6SJeff Kirsher     case CONTEC:
4605346ebf6SJeff Kirsher     case NEC:
4615346ebf6SJeff Kirsher     case KME:
4625346ebf6SJeff Kirsher 	if (cardtype == MBH10304) {
4635346ebf6SJeff Kirsher 	    card_name = "FMV-J182";
4645346ebf6SJeff Kirsher 
4655346ebf6SJeff Kirsher 	    len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
4665346ebf6SJeff Kirsher 	    if (len < 11) {
4675346ebf6SJeff Kirsher 		    kfree(buf);
4685346ebf6SJeff Kirsher 		    goto failed;
4695346ebf6SJeff Kirsher 	    }
4705346ebf6SJeff Kirsher 	    /* Read MACID from CIS */
471*562ef98aSJakub Kicinski 	    eth_hw_addr_set(dev, &buf[5]);
4725346ebf6SJeff Kirsher 	    kfree(buf);
4735346ebf6SJeff Kirsher 	} else {
4745346ebf6SJeff Kirsher 	    if (pcmcia_get_mac_from_cis(link, dev))
4755346ebf6SJeff Kirsher 		goto failed;
4765346ebf6SJeff Kirsher 	    if( cardtype == TDK ) {
4775346ebf6SJeff Kirsher 		card_name = "TDK LAK-CD021";
4785346ebf6SJeff Kirsher 	    } else if( cardtype == LA501 ) {
4795346ebf6SJeff Kirsher 		card_name = "LA501";
4805346ebf6SJeff Kirsher 	    } else if( cardtype == NEC ) {
4815346ebf6SJeff Kirsher 		card_name = "PK-UG-J001";
4825346ebf6SJeff Kirsher 	    } else if( cardtype == KME ) {
4835346ebf6SJeff Kirsher 		card_name = "Panasonic";
4845346ebf6SJeff Kirsher 	    } else {
4855346ebf6SJeff Kirsher 		card_name = "C-NET(PC)C";
4865346ebf6SJeff Kirsher 	    }
4875346ebf6SJeff Kirsher 	}
4885346ebf6SJeff Kirsher 	break;
4895346ebf6SJeff Kirsher     case UNGERMANN:
4905346ebf6SJeff Kirsher 	/* Read MACID from register */
4915346ebf6SJeff Kirsher 	for (i = 0; i < 6; i++)
4925346ebf6SJeff Kirsher 	    dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i);
4935346ebf6SJeff Kirsher 	card_name = "Access/CARD";
4945346ebf6SJeff Kirsher 	break;
4955346ebf6SJeff Kirsher     case XXX10304:
4965346ebf6SJeff Kirsher 	/* Read MACID from Buggy CIS */
4975346ebf6SJeff Kirsher 	if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
4985346ebf6SJeff Kirsher 	    pr_notice("unable to read hardware net address\n");
4995346ebf6SJeff Kirsher 	    goto failed;
5005346ebf6SJeff Kirsher 	}
501*562ef98aSJakub Kicinski 	eth_hw_addr_set(dev, buggybuf);
5025346ebf6SJeff Kirsher 	card_name = "FMV-J182";
5035346ebf6SJeff Kirsher 	break;
5045346ebf6SJeff Kirsher     case MBH10302:
5055346ebf6SJeff Kirsher     default:
5065346ebf6SJeff Kirsher 	/* Read MACID from register */
5075346ebf6SJeff Kirsher 	for (i = 0; i < 6; i++)
5085346ebf6SJeff Kirsher 	    dev->dev_addr[i] = inb(ioaddr + MAC_ID + i);
5095346ebf6SJeff Kirsher 	card_name = "FMV-J181";
5105346ebf6SJeff Kirsher 	break;
5115346ebf6SJeff Kirsher     }
5125346ebf6SJeff Kirsher 
5135346ebf6SJeff Kirsher     lp->cardtype = cardtype;
5145346ebf6SJeff Kirsher     SET_NETDEV_DEV(dev, &link->dev);
5155346ebf6SJeff Kirsher 
5165346ebf6SJeff Kirsher     if (register_netdev(dev) != 0) {
5175346ebf6SJeff Kirsher 	pr_notice("register_netdev() failed\n");
5185346ebf6SJeff Kirsher 	goto failed;
5195346ebf6SJeff Kirsher     }
5205346ebf6SJeff Kirsher 
5215346ebf6SJeff Kirsher     /* print current configuration */
5225346ebf6SJeff Kirsher     netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
5235346ebf6SJeff Kirsher 		card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
5245346ebf6SJeff Kirsher 		dev->base_addr, dev->irq, dev->dev_addr);
5255346ebf6SJeff Kirsher 
5265346ebf6SJeff Kirsher     return 0;
5275346ebf6SJeff Kirsher 
5285346ebf6SJeff Kirsher failed:
5295346ebf6SJeff Kirsher     fmvj18x_release(link);
5305346ebf6SJeff Kirsher     return -ENODEV;
5315346ebf6SJeff Kirsher } /* fmvj18x_config */
5325346ebf6SJeff Kirsher /*====================================================================*/
5335346ebf6SJeff Kirsher 
5345346ebf6SJeff Kirsher static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
5355346ebf6SJeff Kirsher {
5365346ebf6SJeff Kirsher     u_char __iomem *base;
5375346ebf6SJeff Kirsher     int i, j;
5385346ebf6SJeff Kirsher 
5395346ebf6SJeff Kirsher     /* Allocate a small memory window */
5405346ebf6SJeff Kirsher     link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
5415346ebf6SJeff Kirsher     link->resource[2]->start = 0; link->resource[2]->end = 0;
5425346ebf6SJeff Kirsher     i = pcmcia_request_window(link, link->resource[2], 0);
5435346ebf6SJeff Kirsher     if (i != 0)
5445346ebf6SJeff Kirsher 	return -1;
5455346ebf6SJeff Kirsher 
5465346ebf6SJeff Kirsher     base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
5479f4d6358SKangjie Lu     if (!base) {
5489f4d6358SKangjie Lu 	pcmcia_release_window(link, link->resource[2]);
54952202be1SAnirudh Rayabharam 	return -1;
5509f4d6358SKangjie Lu     }
5519f4d6358SKangjie Lu 
5525346ebf6SJeff Kirsher     pcmcia_map_mem_page(link, link->resource[2], 0);
5535346ebf6SJeff Kirsher 
5545346ebf6SJeff Kirsher     /*
5555346ebf6SJeff Kirsher      *  MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
5565346ebf6SJeff Kirsher      *  22 0d xx xx xx 04 06 yy yy yy yy yy yy ff
5575346ebf6SJeff Kirsher      *  'xx' is garbage.
5585346ebf6SJeff Kirsher      *  'yy' is MAC address.
5595346ebf6SJeff Kirsher     */
5605346ebf6SJeff Kirsher     for (i = 0; i < 0x200; i++) {
5615346ebf6SJeff Kirsher 	if (readb(base+i*2) == 0x22) {
5625346ebf6SJeff Kirsher 		if (readb(base+(i-1)*2) == 0xff &&
5635346ebf6SJeff Kirsher 		    readb(base+(i+5)*2) == 0x04 &&
5645346ebf6SJeff Kirsher 		    readb(base+(i+6)*2) == 0x06 &&
5655346ebf6SJeff Kirsher 		    readb(base+(i+13)*2) == 0xff)
5665346ebf6SJeff Kirsher 			break;
5675346ebf6SJeff Kirsher 	}
5685346ebf6SJeff Kirsher     }
5695346ebf6SJeff Kirsher 
5705346ebf6SJeff Kirsher     if (i != 0x200) {
5715346ebf6SJeff Kirsher 	for (j = 0 ; j < 6; j++,i++) {
5725346ebf6SJeff Kirsher 	    node_id[j] = readb(base+(i+7)*2);
5735346ebf6SJeff Kirsher 	}
5745346ebf6SJeff Kirsher     }
5755346ebf6SJeff Kirsher 
5765346ebf6SJeff Kirsher     iounmap(base);
5775346ebf6SJeff Kirsher     j = pcmcia_release_window(link, link->resource[2]);
5785346ebf6SJeff Kirsher     return (i != 0x200) ? 0 : -1;
5795346ebf6SJeff Kirsher 
5805346ebf6SJeff Kirsher } /* fmvj18x_get_hwinfo */
5815346ebf6SJeff Kirsher /*====================================================================*/
5825346ebf6SJeff Kirsher 
5835346ebf6SJeff Kirsher static int fmvj18x_setup_mfc(struct pcmcia_device *link)
5845346ebf6SJeff Kirsher {
5855346ebf6SJeff Kirsher     int i;
5865346ebf6SJeff Kirsher     struct net_device *dev = link->priv;
5875346ebf6SJeff Kirsher     unsigned int ioaddr;
588f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
5895346ebf6SJeff Kirsher 
5905346ebf6SJeff Kirsher     /* Allocate a small memory window */
5915346ebf6SJeff Kirsher     link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
5925346ebf6SJeff Kirsher     link->resource[3]->start = link->resource[3]->end = 0;
5935346ebf6SJeff Kirsher     i = pcmcia_request_window(link, link->resource[3], 0);
5945346ebf6SJeff Kirsher     if (i != 0)
5955346ebf6SJeff Kirsher 	return -1;
5965346ebf6SJeff Kirsher 
5975346ebf6SJeff Kirsher     lp->base = ioremap(link->resource[3]->start,
5985346ebf6SJeff Kirsher 		       resource_size(link->resource[3]));
5995346ebf6SJeff Kirsher     if (lp->base == NULL) {
6005346ebf6SJeff Kirsher 	netdev_notice(dev, "ioremap failed\n");
6015346ebf6SJeff Kirsher 	return -1;
6025346ebf6SJeff Kirsher     }
6035346ebf6SJeff Kirsher 
6045346ebf6SJeff Kirsher     i = pcmcia_map_mem_page(link, link->resource[3], 0);
6055346ebf6SJeff Kirsher     if (i != 0) {
6065346ebf6SJeff Kirsher 	iounmap(lp->base);
6075346ebf6SJeff Kirsher 	lp->base = NULL;
6085346ebf6SJeff Kirsher 	return -1;
6095346ebf6SJeff Kirsher     }
6105346ebf6SJeff Kirsher 
6115346ebf6SJeff Kirsher     ioaddr = dev->base_addr;
6125346ebf6SJeff Kirsher     writeb(0x47, lp->base+0x800);	/* Config Option Register of LAN */
6135346ebf6SJeff Kirsher     writeb(0x0,  lp->base+0x802);	/* Config and Status Register */
6145346ebf6SJeff Kirsher 
6155346ebf6SJeff Kirsher     writeb(ioaddr & 0xff, lp->base+0x80a);	  /* I/O Base(Low) of LAN */
6165346ebf6SJeff Kirsher     writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */
6175346ebf6SJeff Kirsher 
6185346ebf6SJeff Kirsher     writeb(0x45, lp->base+0x820);	/* Config Option Register of Modem */
6195346ebf6SJeff Kirsher     writeb(0x8,  lp->base+0x822);	/* Config and Status Register */
6205346ebf6SJeff Kirsher 
6215346ebf6SJeff Kirsher     return 0;
6225346ebf6SJeff Kirsher 
6235346ebf6SJeff Kirsher }
6245346ebf6SJeff Kirsher /*====================================================================*/
6255346ebf6SJeff Kirsher 
6265346ebf6SJeff Kirsher static void fmvj18x_release(struct pcmcia_device *link)
6275346ebf6SJeff Kirsher {
6285346ebf6SJeff Kirsher 
6295346ebf6SJeff Kirsher     struct net_device *dev = link->priv;
630f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
6315346ebf6SJeff Kirsher     u_char __iomem *tmp;
6325346ebf6SJeff Kirsher 
6335346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_release\n");
6345346ebf6SJeff Kirsher 
6355346ebf6SJeff Kirsher     if (lp->base != NULL) {
6365346ebf6SJeff Kirsher 	tmp = lp->base;
6375346ebf6SJeff Kirsher 	lp->base = NULL;    /* set NULL before iounmap */
6385346ebf6SJeff Kirsher 	iounmap(tmp);
6395346ebf6SJeff Kirsher     }
6405346ebf6SJeff Kirsher 
6415346ebf6SJeff Kirsher     pcmcia_disable_device(link);
6425346ebf6SJeff Kirsher 
6435346ebf6SJeff Kirsher }
6445346ebf6SJeff Kirsher 
6455346ebf6SJeff Kirsher static int fmvj18x_suspend(struct pcmcia_device *link)
6465346ebf6SJeff Kirsher {
6475346ebf6SJeff Kirsher 	struct net_device *dev = link->priv;
6485346ebf6SJeff Kirsher 
6495346ebf6SJeff Kirsher 	if (link->open)
6505346ebf6SJeff Kirsher 		netif_device_detach(dev);
6515346ebf6SJeff Kirsher 
6525346ebf6SJeff Kirsher 	return 0;
6535346ebf6SJeff Kirsher }
6545346ebf6SJeff Kirsher 
6555346ebf6SJeff Kirsher static int fmvj18x_resume(struct pcmcia_device *link)
6565346ebf6SJeff Kirsher {
6575346ebf6SJeff Kirsher 	struct net_device *dev = link->priv;
6585346ebf6SJeff Kirsher 
6595346ebf6SJeff Kirsher 	if (link->open) {
6605346ebf6SJeff Kirsher 		fjn_reset(dev);
6615346ebf6SJeff Kirsher 		netif_device_attach(dev);
6625346ebf6SJeff Kirsher 	}
6635346ebf6SJeff Kirsher 
6645346ebf6SJeff Kirsher 	return 0;
6655346ebf6SJeff Kirsher }
6665346ebf6SJeff Kirsher 
6675346ebf6SJeff Kirsher /*====================================================================*/
6685346ebf6SJeff Kirsher 
6695346ebf6SJeff Kirsher static const struct pcmcia_device_id fmvj18x_ids[] = {
6705346ebf6SJeff Kirsher 	PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
6715346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
6725346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
6735346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
6745346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
6755346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
6765346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
6775346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
6785346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0       ", 0x8cef4d3a, 0x075fc7b6),
6795346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0        ", 0x8cef4d3a, 0xbccf43e6),
6805346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
6815346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
6825346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
6835346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
6845346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304  ES", 0x2599f454),
6855346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
6865346ebf6SJeff Kirsher 	PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
6875346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
6885346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
6895346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
6905346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
6915346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
6925346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
6935346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05),
6945346ebf6SJeff Kirsher 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
6955346ebf6SJeff Kirsher 	PCMCIA_DEVICE_NULL,
6965346ebf6SJeff Kirsher };
6975346ebf6SJeff Kirsher MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
6985346ebf6SJeff Kirsher 
6995346ebf6SJeff Kirsher static struct pcmcia_driver fmvj18x_cs_driver = {
7005346ebf6SJeff Kirsher 	.owner		= THIS_MODULE,
7015346ebf6SJeff Kirsher 	.name		= "fmvj18x_cs",
7025346ebf6SJeff Kirsher 	.probe		= fmvj18x_probe,
7035346ebf6SJeff Kirsher 	.remove		= fmvj18x_detach,
7045346ebf6SJeff Kirsher 	.id_table       = fmvj18x_ids,
7055346ebf6SJeff Kirsher 	.suspend	= fmvj18x_suspend,
7065346ebf6SJeff Kirsher 	.resume		= fmvj18x_resume,
7075346ebf6SJeff Kirsher };
708fdd3f29eSH Hartley Sweeten module_pcmcia_driver(fmvj18x_cs_driver);
7095346ebf6SJeff Kirsher 
7105346ebf6SJeff Kirsher /*====================================================================*/
7115346ebf6SJeff Kirsher 
7125346ebf6SJeff Kirsher static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
7135346ebf6SJeff Kirsher {
7145346ebf6SJeff Kirsher     struct net_device *dev = dev_id;
715f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
7165346ebf6SJeff Kirsher     unsigned int ioaddr;
7175346ebf6SJeff Kirsher     unsigned short tx_stat, rx_stat;
7185346ebf6SJeff Kirsher 
7195346ebf6SJeff Kirsher     ioaddr = dev->base_addr;
7205346ebf6SJeff Kirsher 
7215346ebf6SJeff Kirsher     /* avoid multiple interrupts */
7225346ebf6SJeff Kirsher     outw(0x0000, ioaddr + TX_INTR);
7235346ebf6SJeff Kirsher 
7245346ebf6SJeff Kirsher     /* wait for a while */
7255346ebf6SJeff Kirsher     udelay(1);
7265346ebf6SJeff Kirsher 
7275346ebf6SJeff Kirsher     /* get status */
7285346ebf6SJeff Kirsher     tx_stat = inb(ioaddr + TX_STATUS);
7295346ebf6SJeff Kirsher     rx_stat = inb(ioaddr + RX_STATUS);
7305346ebf6SJeff Kirsher 
7315346ebf6SJeff Kirsher     /* clear status */
7325346ebf6SJeff Kirsher     outb(tx_stat, ioaddr + TX_STATUS);
7335346ebf6SJeff Kirsher     outb(rx_stat, ioaddr + RX_STATUS);
7345346ebf6SJeff Kirsher 
7355346ebf6SJeff Kirsher     pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat);
7365346ebf6SJeff Kirsher     pr_debug("               tx_status %02x.\n", tx_stat);
7375346ebf6SJeff Kirsher 
7385346ebf6SJeff Kirsher     if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
7395346ebf6SJeff Kirsher 	/* there is packet(s) in rx buffer */
7405346ebf6SJeff Kirsher 	fjn_rx(dev);
7415346ebf6SJeff Kirsher     }
7425346ebf6SJeff Kirsher     if (tx_stat & F_TMT_RDY) {
7435346ebf6SJeff Kirsher 	dev->stats.tx_packets += lp->sent ;
7445346ebf6SJeff Kirsher         lp->sent = 0 ;
7455346ebf6SJeff Kirsher 	if (lp->tx_queue) {
7465346ebf6SJeff Kirsher 	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
7475346ebf6SJeff Kirsher 	    lp->sent = lp->tx_queue ;
7485346ebf6SJeff Kirsher 	    lp->tx_queue = 0;
7495346ebf6SJeff Kirsher 	    lp->tx_queue_len = 0;
750860e9538SFlorian Westphal 	    netif_trans_update(dev);
7515346ebf6SJeff Kirsher 	} else {
7525346ebf6SJeff Kirsher 	    lp->tx_started = 0;
7535346ebf6SJeff Kirsher 	}
7545346ebf6SJeff Kirsher 	netif_wake_queue(dev);
7555346ebf6SJeff Kirsher     }
7565346ebf6SJeff Kirsher     pr_debug("%s: exiting interrupt,\n", dev->name);
7575346ebf6SJeff Kirsher     pr_debug("    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
7585346ebf6SJeff Kirsher 
7595346ebf6SJeff Kirsher     outb(D_TX_INTR, ioaddr + TX_INTR);
7605346ebf6SJeff Kirsher     outb(D_RX_INTR, ioaddr + RX_INTR);
7615346ebf6SJeff Kirsher 
7625346ebf6SJeff Kirsher     if (lp->base != NULL) {
7635346ebf6SJeff Kirsher 	/* Ack interrupt for multifunction card */
7645346ebf6SJeff Kirsher 	writeb(0x01, lp->base+0x802);
7655346ebf6SJeff Kirsher 	writeb(0x09, lp->base+0x822);
7665346ebf6SJeff Kirsher     }
7675346ebf6SJeff Kirsher 
7685346ebf6SJeff Kirsher     return IRQ_HANDLED;
7695346ebf6SJeff Kirsher 
7705346ebf6SJeff Kirsher } /* fjn_interrupt */
7715346ebf6SJeff Kirsher 
7725346ebf6SJeff Kirsher /*====================================================================*/
7735346ebf6SJeff Kirsher 
7740290bd29SMichael S. Tsirkin static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue)
7755346ebf6SJeff Kirsher {
776f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
7775346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
7785346ebf6SJeff Kirsher 
7795346ebf6SJeff Kirsher     netdev_notice(dev, "transmit timed out with status %04x, %s?\n",
7805346ebf6SJeff Kirsher 		  htons(inw(ioaddr + TX_STATUS)),
7815346ebf6SJeff Kirsher 		  inb(ioaddr + TX_STATUS) & F_TMT_RDY
7825346ebf6SJeff Kirsher 		  ? "IRQ conflict" : "network cable problem");
7835346ebf6SJeff Kirsher     netdev_notice(dev, "timeout registers: %04x %04x %04x "
7845346ebf6SJeff Kirsher 		  "%04x %04x %04x %04x %04x.\n",
7855346ebf6SJeff Kirsher 		  htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)),
7865346ebf6SJeff Kirsher 		  htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)),
7875346ebf6SJeff Kirsher 		  htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)),
7885346ebf6SJeff Kirsher 		  htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14)));
7895346ebf6SJeff Kirsher     dev->stats.tx_errors++;
7905346ebf6SJeff Kirsher     /* ToDo: We should try to restart the adaptor... */
7915346ebf6SJeff Kirsher     local_irq_disable();
7925346ebf6SJeff Kirsher     fjn_reset(dev);
7935346ebf6SJeff Kirsher 
7945346ebf6SJeff Kirsher     lp->tx_started = 0;
7955346ebf6SJeff Kirsher     lp->tx_queue = 0;
7965346ebf6SJeff Kirsher     lp->tx_queue_len = 0;
7975346ebf6SJeff Kirsher     lp->sent = 0;
7985346ebf6SJeff Kirsher     lp->open_time = jiffies;
7995346ebf6SJeff Kirsher     local_irq_enable();
8005346ebf6SJeff Kirsher     netif_wake_queue(dev);
8015346ebf6SJeff Kirsher }
8025346ebf6SJeff Kirsher 
8035346ebf6SJeff Kirsher static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
8045346ebf6SJeff Kirsher 					struct net_device *dev)
8055346ebf6SJeff Kirsher {
806f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
8075346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
8085346ebf6SJeff Kirsher     short length = skb->len;
8095346ebf6SJeff Kirsher 
8105346ebf6SJeff Kirsher     if (length < ETH_ZLEN)
8115346ebf6SJeff Kirsher     {
8125346ebf6SJeff Kirsher 	if (skb_padto(skb, ETH_ZLEN))
8135346ebf6SJeff Kirsher 		return NETDEV_TX_OK;
8145346ebf6SJeff Kirsher 	length = ETH_ZLEN;
8155346ebf6SJeff Kirsher     }
8165346ebf6SJeff Kirsher 
8175346ebf6SJeff Kirsher     netif_stop_queue(dev);
8185346ebf6SJeff Kirsher 
8195346ebf6SJeff Kirsher     {
8205346ebf6SJeff Kirsher 	unsigned char *buf = skb->data;
8215346ebf6SJeff Kirsher 
8225346ebf6SJeff Kirsher 	if (length > ETH_FRAME_LEN) {
8235346ebf6SJeff Kirsher 	    netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n",
8245346ebf6SJeff Kirsher 			  length);
8255346ebf6SJeff Kirsher 	    return NETDEV_TX_BUSY;
8265346ebf6SJeff Kirsher 	}
8275346ebf6SJeff Kirsher 
8285346ebf6SJeff Kirsher 	netdev_dbg(dev, "Transmitting a packet of length %lu\n",
8295346ebf6SJeff Kirsher 		   (unsigned long)skb->len);
8305346ebf6SJeff Kirsher 	dev->stats.tx_bytes += skb->len;
8315346ebf6SJeff Kirsher 
8325346ebf6SJeff Kirsher 	/* Disable both interrupts. */
8335346ebf6SJeff Kirsher 	outw(0x0000, ioaddr + TX_INTR);
8345346ebf6SJeff Kirsher 
8355346ebf6SJeff Kirsher 	/* wait for a while */
8365346ebf6SJeff Kirsher 	udelay(1);
8375346ebf6SJeff Kirsher 
8385346ebf6SJeff Kirsher 	outw(length, ioaddr + DATAPORT);
8395346ebf6SJeff Kirsher 	outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
8405346ebf6SJeff Kirsher 
8415346ebf6SJeff Kirsher 	lp->tx_queue++;
8425346ebf6SJeff Kirsher 	lp->tx_queue_len += ((length+3) & ~1);
8435346ebf6SJeff Kirsher 
8445346ebf6SJeff Kirsher 	if (lp->tx_started == 0) {
8455346ebf6SJeff Kirsher 	    /* If the Tx is idle, always trigger a transmit. */
8465346ebf6SJeff Kirsher 	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
8475346ebf6SJeff Kirsher 	    lp->sent = lp->tx_queue ;
8485346ebf6SJeff Kirsher 	    lp->tx_queue = 0;
8495346ebf6SJeff Kirsher 	    lp->tx_queue_len = 0;
8505346ebf6SJeff Kirsher 	    lp->tx_started = 1;
8515346ebf6SJeff Kirsher 	    netif_start_queue(dev);
8525346ebf6SJeff Kirsher 	} else {
8535346ebf6SJeff Kirsher 	    if( sram_config == 0 ) {
8545346ebf6SJeff Kirsher 		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
8555346ebf6SJeff Kirsher 		    /* Yes, there is room for one more packet. */
8565346ebf6SJeff Kirsher 		    netif_start_queue(dev);
8575346ebf6SJeff Kirsher 	    } else {
8585346ebf6SJeff Kirsher 		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) &&
8595346ebf6SJeff Kirsher 						lp->tx_queue < 127 )
8605346ebf6SJeff Kirsher 		    /* Yes, there is room for one more packet. */
8615346ebf6SJeff Kirsher 		    netif_start_queue(dev);
8625346ebf6SJeff Kirsher 	    }
8635346ebf6SJeff Kirsher 	}
8645346ebf6SJeff Kirsher 
8655346ebf6SJeff Kirsher 	/* Re-enable interrupts */
8665346ebf6SJeff Kirsher 	outb(D_TX_INTR, ioaddr + TX_INTR);
8675346ebf6SJeff Kirsher 	outb(D_RX_INTR, ioaddr + RX_INTR);
8685346ebf6SJeff Kirsher     }
8695346ebf6SJeff Kirsher     dev_kfree_skb (skb);
8705346ebf6SJeff Kirsher 
8715346ebf6SJeff Kirsher     return NETDEV_TX_OK;
8725346ebf6SJeff Kirsher } /* fjn_start_xmit */
8735346ebf6SJeff Kirsher 
8745346ebf6SJeff Kirsher /*====================================================================*/
8755346ebf6SJeff Kirsher 
8765346ebf6SJeff Kirsher static void fjn_reset(struct net_device *dev)
8775346ebf6SJeff Kirsher {
878f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
8795346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
8805346ebf6SJeff Kirsher     int i;
8815346ebf6SJeff Kirsher 
8825346ebf6SJeff Kirsher     netdev_dbg(dev, "fjn_reset() called\n");
8835346ebf6SJeff Kirsher 
8845346ebf6SJeff Kirsher     /* Reset controller */
8855346ebf6SJeff Kirsher     if( sram_config == 0 )
8865346ebf6SJeff Kirsher 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
8875346ebf6SJeff Kirsher     else
8885346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
8895346ebf6SJeff Kirsher 
8905346ebf6SJeff Kirsher     /* Power On chip and select bank 0 */
8915346ebf6SJeff Kirsher     if (lp->cardtype == MBH10302)
8925346ebf6SJeff Kirsher 	outb(BANK_0, ioaddr + CONFIG_1);
8935346ebf6SJeff Kirsher     else
8945346ebf6SJeff Kirsher 	outb(BANK_0U, ioaddr + CONFIG_1);
8955346ebf6SJeff Kirsher 
8965346ebf6SJeff Kirsher     /* Set Tx modes */
8975346ebf6SJeff Kirsher     outb(D_TX_MODE, ioaddr + TX_MODE);
8985346ebf6SJeff Kirsher     /* set Rx modes */
8995346ebf6SJeff Kirsher     outb(ID_MATCHED, ioaddr + RX_MODE);
9005346ebf6SJeff Kirsher 
9015346ebf6SJeff Kirsher     /* Set hardware address */
9025346ebf6SJeff Kirsher     for (i = 0; i < 6; i++)
9035346ebf6SJeff Kirsher         outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
9045346ebf6SJeff Kirsher 
9055346ebf6SJeff Kirsher     /* (re)initialize the multicast table */
9065346ebf6SJeff Kirsher     set_rx_mode(dev);
9075346ebf6SJeff Kirsher 
9085346ebf6SJeff Kirsher     /* Switch to bank 2 (runtime mode) */
9095346ebf6SJeff Kirsher     if (lp->cardtype == MBH10302)
9105346ebf6SJeff Kirsher 	outb(BANK_2, ioaddr + CONFIG_1);
9115346ebf6SJeff Kirsher     else
9125346ebf6SJeff Kirsher 	outb(BANK_2U, ioaddr + CONFIG_1);
9135346ebf6SJeff Kirsher 
9145346ebf6SJeff Kirsher     /* set 16col ctrl bits */
9155346ebf6SJeff Kirsher     if( lp->cardtype == TDK || lp->cardtype == CONTEC)
9165346ebf6SJeff Kirsher         outb(TDK_AUTO_MODE, ioaddr + COL_CTRL);
9175346ebf6SJeff Kirsher     else
9185346ebf6SJeff Kirsher         outb(AUTO_MODE, ioaddr + COL_CTRL);
9195346ebf6SJeff Kirsher 
9205346ebf6SJeff Kirsher     /* clear Reserved Regs */
9215346ebf6SJeff Kirsher     outb(0x00, ioaddr + BMPR12);
9225346ebf6SJeff Kirsher     outb(0x00, ioaddr + BMPR13);
9235346ebf6SJeff Kirsher 
9245346ebf6SJeff Kirsher     /* reset Skip packet reg. */
9255346ebf6SJeff Kirsher     outb(0x01, ioaddr + RX_SKIP);
9265346ebf6SJeff Kirsher 
9275346ebf6SJeff Kirsher     /* Enable Tx and Rx */
9285346ebf6SJeff Kirsher     if( sram_config == 0 )
9295346ebf6SJeff Kirsher 	outb(CONFIG0_DFL, ioaddr + CONFIG_0);
9305346ebf6SJeff Kirsher     else
9315346ebf6SJeff Kirsher 	outb(CONFIG0_DFL_1, ioaddr + CONFIG_0);
9325346ebf6SJeff Kirsher 
9335346ebf6SJeff Kirsher     /* Init receive pointer ? */
9345346ebf6SJeff Kirsher     inw(ioaddr + DATAPORT);
9355346ebf6SJeff Kirsher     inw(ioaddr + DATAPORT);
9365346ebf6SJeff Kirsher 
9375346ebf6SJeff Kirsher     /* Clear all status */
9385346ebf6SJeff Kirsher     outb(0xff, ioaddr + TX_STATUS);
9395346ebf6SJeff Kirsher     outb(0xff, ioaddr + RX_STATUS);
9405346ebf6SJeff Kirsher 
9415346ebf6SJeff Kirsher     if (lp->cardtype == MBH10302)
9425346ebf6SJeff Kirsher 	outb(INTR_OFF, ioaddr + LAN_CTRL);
9435346ebf6SJeff Kirsher 
9445346ebf6SJeff Kirsher     /* Turn on Rx interrupts */
9455346ebf6SJeff Kirsher     outb(D_TX_INTR, ioaddr + TX_INTR);
9465346ebf6SJeff Kirsher     outb(D_RX_INTR, ioaddr + RX_INTR);
9475346ebf6SJeff Kirsher 
9485346ebf6SJeff Kirsher     /* Turn on interrupts from LAN card controller */
9495346ebf6SJeff Kirsher     if (lp->cardtype == MBH10302)
9505346ebf6SJeff Kirsher 	outb(INTR_ON, ioaddr + LAN_CTRL);
9515346ebf6SJeff Kirsher } /* fjn_reset */
9525346ebf6SJeff Kirsher 
9535346ebf6SJeff Kirsher /*====================================================================*/
9545346ebf6SJeff Kirsher 
9555346ebf6SJeff Kirsher static void fjn_rx(struct net_device *dev)
9565346ebf6SJeff Kirsher {
9575346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
9585346ebf6SJeff Kirsher     int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
9595346ebf6SJeff Kirsher 
9605346ebf6SJeff Kirsher     pr_debug("%s: in rx_packet(), rx_status %02x.\n",
9615346ebf6SJeff Kirsher 	  dev->name, inb(ioaddr + RX_STATUS));
9625346ebf6SJeff Kirsher 
9635346ebf6SJeff Kirsher     while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
9645346ebf6SJeff Kirsher 	u_short status = inw(ioaddr + DATAPORT);
9655346ebf6SJeff Kirsher 
9665346ebf6SJeff Kirsher 	netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n",
9675346ebf6SJeff Kirsher 		   inb(ioaddr + RX_MODE), status);
9685346ebf6SJeff Kirsher #ifndef final_version
9695346ebf6SJeff Kirsher 	if (status == 0) {
9705346ebf6SJeff Kirsher 	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
9715346ebf6SJeff Kirsher 	    break;
9725346ebf6SJeff Kirsher 	}
9735346ebf6SJeff Kirsher #endif
9745346ebf6SJeff Kirsher 	if ((status & 0xF0) != 0x20) {	/* There was an error. */
9755346ebf6SJeff Kirsher 	    dev->stats.rx_errors++;
9765346ebf6SJeff Kirsher 	    if (status & F_LEN_ERR) dev->stats.rx_length_errors++;
9775346ebf6SJeff Kirsher 	    if (status & F_ALG_ERR) dev->stats.rx_frame_errors++;
9785346ebf6SJeff Kirsher 	    if (status & F_CRC_ERR) dev->stats.rx_crc_errors++;
9795346ebf6SJeff Kirsher 	    if (status & F_OVR_FLO) dev->stats.rx_over_errors++;
9805346ebf6SJeff Kirsher 	} else {
9815346ebf6SJeff Kirsher 	    u_short pkt_len = inw(ioaddr + DATAPORT);
9825346ebf6SJeff Kirsher 	    /* Malloc up new buffer. */
9835346ebf6SJeff Kirsher 	    struct sk_buff *skb;
9845346ebf6SJeff Kirsher 
9855346ebf6SJeff Kirsher 	    if (pkt_len > 1550) {
9865346ebf6SJeff Kirsher 		netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n",
9875346ebf6SJeff Kirsher 			      pkt_len);
9885346ebf6SJeff Kirsher 		outb(F_SKP_PKT, ioaddr + RX_SKIP);
9895346ebf6SJeff Kirsher 		dev->stats.rx_errors++;
9905346ebf6SJeff Kirsher 		break;
9915346ebf6SJeff Kirsher 	    }
992c056b734SPradeep A Dalvi 	    skb = netdev_alloc_skb(dev, pkt_len + 2);
9935346ebf6SJeff Kirsher 	    if (skb == NULL) {
9945346ebf6SJeff Kirsher 		outb(F_SKP_PKT, ioaddr + RX_SKIP);
9955346ebf6SJeff Kirsher 		dev->stats.rx_dropped++;
9965346ebf6SJeff Kirsher 		break;
9975346ebf6SJeff Kirsher 	    }
9985346ebf6SJeff Kirsher 
9995346ebf6SJeff Kirsher 	    skb_reserve(skb, 2);
10005346ebf6SJeff Kirsher 	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
10015346ebf6SJeff Kirsher 		 (pkt_len + 1) >> 1);
10025346ebf6SJeff Kirsher 	    skb->protocol = eth_type_trans(skb, dev);
10035346ebf6SJeff Kirsher 
10045346ebf6SJeff Kirsher 	    {
10055346ebf6SJeff Kirsher 		int i;
10065346ebf6SJeff Kirsher 		pr_debug("%s: Rxed packet of length %d: ",
10075346ebf6SJeff Kirsher 			dev->name, pkt_len);
10085346ebf6SJeff Kirsher 		for (i = 0; i < 14; i++)
10095346ebf6SJeff Kirsher 			pr_debug(" %02x", skb->data[i]);
10105346ebf6SJeff Kirsher 		pr_debug(".\n");
10115346ebf6SJeff Kirsher 	    }
10125346ebf6SJeff Kirsher 
10135346ebf6SJeff Kirsher 	    netif_rx(skb);
10145346ebf6SJeff Kirsher 	    dev->stats.rx_packets++;
10155346ebf6SJeff Kirsher 	    dev->stats.rx_bytes += pkt_len;
10165346ebf6SJeff Kirsher 	}
10175346ebf6SJeff Kirsher 	if (--boguscount <= 0)
10185346ebf6SJeff Kirsher 	    break;
10195346ebf6SJeff Kirsher     }
10205346ebf6SJeff Kirsher 
10215346ebf6SJeff Kirsher     /* If any worth-while packets have been received, dev_rint()
10225346ebf6SJeff Kirsher 	   has done a netif_wake_queue() for us and will work on them
10235346ebf6SJeff Kirsher 	   when we get to the bottom-half routine. */
10245346ebf6SJeff Kirsher /*
10255346ebf6SJeff Kirsher     if (lp->cardtype != TDK) {
10265346ebf6SJeff Kirsher 	int i;
10275346ebf6SJeff Kirsher 	for (i = 0; i < 20; i++) {
10285346ebf6SJeff Kirsher 	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
10295346ebf6SJeff Kirsher 		break;
10305346ebf6SJeff Kirsher 	    (void)inw(ioaddr + DATAPORT);  /+ dummy status read +/
10315346ebf6SJeff Kirsher 	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
10325346ebf6SJeff Kirsher 	}
10335346ebf6SJeff Kirsher 
10345346ebf6SJeff Kirsher 	if (i > 0)
10355346ebf6SJeff Kirsher 	    pr_debug("%s: Exint Rx packet with mode %02x after "
10365346ebf6SJeff Kirsher 		  "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
10375346ebf6SJeff Kirsher     }
10385346ebf6SJeff Kirsher */
10395346ebf6SJeff Kirsher } /* fjn_rx */
10405346ebf6SJeff Kirsher 
10415346ebf6SJeff Kirsher /*====================================================================*/
10425346ebf6SJeff Kirsher 
10435346ebf6SJeff Kirsher static void netdev_get_drvinfo(struct net_device *dev,
10445346ebf6SJeff Kirsher 			       struct ethtool_drvinfo *info)
10455346ebf6SJeff Kirsher {
104633a5ba14SRick Jones 	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
104733a5ba14SRick Jones 	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
104833a5ba14SRick Jones 	snprintf(info->bus_info, sizeof(info->bus_info),
104933a5ba14SRick Jones 		"PCMCIA 0x%lx", dev->base_addr);
10505346ebf6SJeff Kirsher }
10515346ebf6SJeff Kirsher 
10525346ebf6SJeff Kirsher static const struct ethtool_ops netdev_ethtool_ops = {
10535346ebf6SJeff Kirsher 	.get_drvinfo		= netdev_get_drvinfo,
10545346ebf6SJeff Kirsher };
10555346ebf6SJeff Kirsher 
10565346ebf6SJeff Kirsher static int fjn_config(struct net_device *dev, struct ifmap *map){
10575346ebf6SJeff Kirsher     return 0;
10585346ebf6SJeff Kirsher }
10595346ebf6SJeff Kirsher 
10605346ebf6SJeff Kirsher static int fjn_open(struct net_device *dev)
10615346ebf6SJeff Kirsher {
1062f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
10635346ebf6SJeff Kirsher     struct pcmcia_device *link = lp->p_dev;
10645346ebf6SJeff Kirsher 
10655346ebf6SJeff Kirsher     pr_debug("fjn_open('%s').\n", dev->name);
10665346ebf6SJeff Kirsher 
10675346ebf6SJeff Kirsher     if (!pcmcia_dev_present(link))
10685346ebf6SJeff Kirsher 	return -ENODEV;
10695346ebf6SJeff Kirsher 
10705346ebf6SJeff Kirsher     link->open++;
10715346ebf6SJeff Kirsher 
10725346ebf6SJeff Kirsher     fjn_reset(dev);
10735346ebf6SJeff Kirsher 
10745346ebf6SJeff Kirsher     lp->tx_started = 0;
10755346ebf6SJeff Kirsher     lp->tx_queue = 0;
10765346ebf6SJeff Kirsher     lp->tx_queue_len = 0;
10775346ebf6SJeff Kirsher     lp->open_time = jiffies;
10785346ebf6SJeff Kirsher     netif_start_queue(dev);
10795346ebf6SJeff Kirsher 
10805346ebf6SJeff Kirsher     return 0;
10815346ebf6SJeff Kirsher } /* fjn_open */
10825346ebf6SJeff Kirsher 
10835346ebf6SJeff Kirsher /*====================================================================*/
10845346ebf6SJeff Kirsher 
10855346ebf6SJeff Kirsher static int fjn_close(struct net_device *dev)
10865346ebf6SJeff Kirsher {
1087f073d52dSHimangi Saraogi     struct local_info *lp = netdev_priv(dev);
10885346ebf6SJeff Kirsher     struct pcmcia_device *link = lp->p_dev;
10895346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
10905346ebf6SJeff Kirsher 
10915346ebf6SJeff Kirsher     pr_debug("fjn_close('%s').\n", dev->name);
10925346ebf6SJeff Kirsher 
10935346ebf6SJeff Kirsher     lp->open_time = 0;
10945346ebf6SJeff Kirsher     netif_stop_queue(dev);
10955346ebf6SJeff Kirsher 
10965346ebf6SJeff Kirsher     /* Set configuration register 0 to disable Tx and Rx. */
10975346ebf6SJeff Kirsher     if( sram_config == 0 )
10985346ebf6SJeff Kirsher 	outb(CONFIG0_RST ,ioaddr + CONFIG_0);
10995346ebf6SJeff Kirsher     else
11005346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
11015346ebf6SJeff Kirsher 
11025346ebf6SJeff Kirsher     /* Update the statistics -- ToDo. */
11035346ebf6SJeff Kirsher 
11045346ebf6SJeff Kirsher     /* Power-down the chip.  Green, green, green! */
11055346ebf6SJeff Kirsher     outb(CHIP_OFF ,ioaddr + CONFIG_1);
11065346ebf6SJeff Kirsher 
11075346ebf6SJeff Kirsher     /* Set the ethernet adaptor disable IRQ */
11085346ebf6SJeff Kirsher     if (lp->cardtype == MBH10302)
11095346ebf6SJeff Kirsher 	outb(INTR_OFF, ioaddr + LAN_CTRL);
11105346ebf6SJeff Kirsher 
11115346ebf6SJeff Kirsher     link->open--;
11125346ebf6SJeff Kirsher 
11135346ebf6SJeff Kirsher     return 0;
11145346ebf6SJeff Kirsher } /* fjn_close */
11155346ebf6SJeff Kirsher 
11165346ebf6SJeff Kirsher /*====================================================================*/
11175346ebf6SJeff Kirsher 
11185346ebf6SJeff Kirsher /*
11195346ebf6SJeff Kirsher   Set the multicast/promiscuous mode for this adaptor.
11205346ebf6SJeff Kirsher */
11215346ebf6SJeff Kirsher 
11225346ebf6SJeff Kirsher static void set_rx_mode(struct net_device *dev)
11235346ebf6SJeff Kirsher {
11245346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
11255346ebf6SJeff Kirsher     u_char mc_filter[8];		 /* Multicast hash filter */
11265346ebf6SJeff Kirsher     u_long flags;
11275346ebf6SJeff Kirsher     int i;
11285346ebf6SJeff Kirsher 
11295346ebf6SJeff Kirsher     int saved_bank;
11305346ebf6SJeff Kirsher     int saved_config_0 = inb(ioaddr + CONFIG_0);
11315346ebf6SJeff Kirsher 
11325346ebf6SJeff Kirsher     local_irq_save(flags);
11335346ebf6SJeff Kirsher 
11345346ebf6SJeff Kirsher     /* Disable Tx and Rx */
11355346ebf6SJeff Kirsher     if (sram_config == 0)
11365346ebf6SJeff Kirsher 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
11375346ebf6SJeff Kirsher     else
11385346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
11395346ebf6SJeff Kirsher 
11405346ebf6SJeff Kirsher     if (dev->flags & IFF_PROMISC) {
11415346ebf6SJeff Kirsher 	memset(mc_filter, 0xff, sizeof(mc_filter));
11425346ebf6SJeff Kirsher 	outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
11435346ebf6SJeff Kirsher     } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
11445346ebf6SJeff Kirsher 	       (dev->flags & IFF_ALLMULTI)) {
11455346ebf6SJeff Kirsher 	/* Too many to filter perfectly -- accept all multicasts. */
11465346ebf6SJeff Kirsher 	memset(mc_filter, 0xff, sizeof(mc_filter));
11475346ebf6SJeff Kirsher 	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
11485346ebf6SJeff Kirsher     } else if (netdev_mc_empty(dev)) {
11495346ebf6SJeff Kirsher 	memset(mc_filter, 0x00, sizeof(mc_filter));
11505346ebf6SJeff Kirsher 	outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
11515346ebf6SJeff Kirsher     } else {
11525346ebf6SJeff Kirsher 	struct netdev_hw_addr *ha;
11535346ebf6SJeff Kirsher 
11545346ebf6SJeff Kirsher 	memset(mc_filter, 0, sizeof(mc_filter));
11555346ebf6SJeff Kirsher 	netdev_for_each_mc_addr(ha, dev) {
11565346ebf6SJeff Kirsher 	    unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
11575346ebf6SJeff Kirsher 	    mc_filter[bit >> 3] |= (1 << (bit & 7));
11585346ebf6SJeff Kirsher 	}
11595346ebf6SJeff Kirsher 	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
11605346ebf6SJeff Kirsher     }
11615346ebf6SJeff Kirsher 
11625346ebf6SJeff Kirsher     /* Switch to bank 1 and set the multicast table. */
11635346ebf6SJeff Kirsher     saved_bank = inb(ioaddr + CONFIG_1);
11645346ebf6SJeff Kirsher     outb(0xe4, ioaddr + CONFIG_1);
11655346ebf6SJeff Kirsher 
11665346ebf6SJeff Kirsher     for (i = 0; i < 8; i++)
11675346ebf6SJeff Kirsher 	outb(mc_filter[i], ioaddr + MAR_ADR + i);
11685346ebf6SJeff Kirsher     outb(saved_bank, ioaddr + CONFIG_1);
11695346ebf6SJeff Kirsher 
11705346ebf6SJeff Kirsher     outb(saved_config_0, ioaddr + CONFIG_0);
11715346ebf6SJeff Kirsher 
11725346ebf6SJeff Kirsher     local_irq_restore(flags);
11735346ebf6SJeff Kirsher }
1174