xref: /linux/drivers/net/ethernet/fujitsu/fmvj18x_cs.c (revision fdd3f29eddd1b7c26b3b42e3633afcb22a28fcb3)
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/init.h>
395346ebf6SJeff Kirsher #include <linux/ptrace.h>
405346ebf6SJeff Kirsher #include <linux/slab.h>
415346ebf6SJeff Kirsher #include <linux/string.h>
425346ebf6SJeff Kirsher #include <linux/timer.h>
435346ebf6SJeff Kirsher #include <linux/interrupt.h>
445346ebf6SJeff Kirsher #include <linux/in.h>
455346ebf6SJeff Kirsher #include <linux/delay.h>
465346ebf6SJeff Kirsher #include <linux/ethtool.h>
475346ebf6SJeff Kirsher #include <linux/netdevice.h>
485346ebf6SJeff Kirsher #include <linux/etherdevice.h>
495346ebf6SJeff Kirsher #include <linux/skbuff.h>
505346ebf6SJeff Kirsher #include <linux/if_arp.h>
515346ebf6SJeff Kirsher #include <linux/ioport.h>
525346ebf6SJeff Kirsher #include <linux/crc32.h>
535346ebf6SJeff Kirsher 
545346ebf6SJeff Kirsher #include <pcmcia/cistpl.h>
555346ebf6SJeff Kirsher #include <pcmcia/ciscode.h>
565346ebf6SJeff Kirsher #include <pcmcia/ds.h>
575346ebf6SJeff Kirsher 
585346ebf6SJeff Kirsher #include <asm/uaccess.h>
595346ebf6SJeff Kirsher #include <asm/io.h>
605346ebf6SJeff Kirsher 
615346ebf6SJeff Kirsher /*====================================================================*/
625346ebf6SJeff Kirsher 
635346ebf6SJeff Kirsher /* Module parameters */
645346ebf6SJeff Kirsher 
655346ebf6SJeff Kirsher MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
665346ebf6SJeff Kirsher MODULE_LICENSE("GPL");
675346ebf6SJeff Kirsher 
685346ebf6SJeff Kirsher #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
695346ebf6SJeff Kirsher 
705346ebf6SJeff Kirsher /* SRAM configuration */
715346ebf6SJeff Kirsher /* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
725346ebf6SJeff Kirsher INT_MODULE_PARM(sram_config, 0);
735346ebf6SJeff Kirsher 
745346ebf6SJeff Kirsher 
755346ebf6SJeff Kirsher /*====================================================================*/
765346ebf6SJeff Kirsher /*
775346ebf6SJeff Kirsher     PCMCIA event handlers
785346ebf6SJeff Kirsher  */
795346ebf6SJeff Kirsher static int fmvj18x_config(struct pcmcia_device *link);
805346ebf6SJeff Kirsher static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id);
815346ebf6SJeff Kirsher static int fmvj18x_setup_mfc(struct pcmcia_device *link);
825346ebf6SJeff Kirsher static void fmvj18x_release(struct pcmcia_device *link);
835346ebf6SJeff Kirsher static void fmvj18x_detach(struct pcmcia_device *p_dev);
845346ebf6SJeff Kirsher 
855346ebf6SJeff Kirsher /*
865346ebf6SJeff Kirsher     LAN controller(MBH86960A) specific routines
875346ebf6SJeff Kirsher  */
885346ebf6SJeff Kirsher static int fjn_config(struct net_device *dev, struct ifmap *map);
895346ebf6SJeff Kirsher static int fjn_open(struct net_device *dev);
905346ebf6SJeff Kirsher static int fjn_close(struct net_device *dev);
915346ebf6SJeff Kirsher static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
925346ebf6SJeff Kirsher 					struct net_device *dev);
935346ebf6SJeff Kirsher static irqreturn_t fjn_interrupt(int irq, void *dev_id);
945346ebf6SJeff Kirsher static void fjn_rx(struct net_device *dev);
955346ebf6SJeff Kirsher static void fjn_reset(struct net_device *dev);
965346ebf6SJeff Kirsher static void set_rx_mode(struct net_device *dev);
975346ebf6SJeff Kirsher static void fjn_tx_timeout(struct net_device *dev);
985346ebf6SJeff Kirsher static const struct ethtool_ops netdev_ethtool_ops;
995346ebf6SJeff Kirsher 
1005346ebf6SJeff Kirsher /*
1015346ebf6SJeff Kirsher     card type
1025346ebf6SJeff Kirsher  */
1035346ebf6SJeff Kirsher typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
1045346ebf6SJeff Kirsher 	       XXX10304, NEC, KME
1055346ebf6SJeff Kirsher } cardtype_t;
1065346ebf6SJeff Kirsher 
1075346ebf6SJeff Kirsher /*
1085346ebf6SJeff Kirsher     driver specific data structure
1095346ebf6SJeff Kirsher */
1105346ebf6SJeff Kirsher typedef struct local_info_t {
1115346ebf6SJeff Kirsher 	struct pcmcia_device	*p_dev;
1125346ebf6SJeff Kirsher     long open_time;
1135346ebf6SJeff Kirsher     uint tx_started:1;
1145346ebf6SJeff Kirsher     uint tx_queue;
1155346ebf6SJeff Kirsher     u_short tx_queue_len;
1165346ebf6SJeff Kirsher     cardtype_t cardtype;
1175346ebf6SJeff Kirsher     u_short sent;
1185346ebf6SJeff Kirsher     u_char __iomem *base;
1195346ebf6SJeff Kirsher } local_info_t;
1205346ebf6SJeff Kirsher 
1215346ebf6SJeff Kirsher #define MC_FILTERBREAK 64
1225346ebf6SJeff Kirsher 
1235346ebf6SJeff Kirsher /*====================================================================*/
1245346ebf6SJeff Kirsher /*
1255346ebf6SJeff Kirsher     ioport offset from the base address
1265346ebf6SJeff Kirsher  */
1275346ebf6SJeff Kirsher #define TX_STATUS               0 /* transmit status register */
1285346ebf6SJeff Kirsher #define RX_STATUS               1 /* receive status register */
1295346ebf6SJeff Kirsher #define TX_INTR                 2 /* transmit interrupt mask register */
1305346ebf6SJeff Kirsher #define RX_INTR                 3 /* receive interrupt mask register */
1315346ebf6SJeff Kirsher #define TX_MODE                 4 /* transmit mode register */
1325346ebf6SJeff Kirsher #define RX_MODE                 5 /* receive mode register */
1335346ebf6SJeff Kirsher #define CONFIG_0                6 /* configuration register 0 */
1345346ebf6SJeff Kirsher #define CONFIG_1                7 /* configuration register 1 */
1355346ebf6SJeff Kirsher 
1365346ebf6SJeff Kirsher #define NODE_ID                 8 /* node ID register            (bank 0) */
1375346ebf6SJeff Kirsher #define MAR_ADR                 8 /* multicast address registers (bank 1) */
1385346ebf6SJeff Kirsher 
1395346ebf6SJeff Kirsher #define DATAPORT                8 /* buffer mem port registers   (bank 2) */
1405346ebf6SJeff Kirsher #define TX_START               10 /* transmit start register */
1415346ebf6SJeff Kirsher #define COL_CTRL               11 /* 16 collision control register */
1425346ebf6SJeff Kirsher #define BMPR12                 12 /* reserved */
1435346ebf6SJeff Kirsher #define BMPR13                 13 /* reserved */
1445346ebf6SJeff Kirsher #define RX_SKIP                14 /* skip received packet register */
1455346ebf6SJeff Kirsher 
1465346ebf6SJeff Kirsher #define LAN_CTRL               16 /* LAN card control register */
1475346ebf6SJeff Kirsher 
1485346ebf6SJeff Kirsher #define MAC_ID               0x1a /* hardware address */
1495346ebf6SJeff Kirsher #define UNGERMANN_MAC_ID     0x18 /* UNGERMANN-BASS hardware address */
1505346ebf6SJeff Kirsher 
1515346ebf6SJeff Kirsher /*
1525346ebf6SJeff Kirsher     control bits
1535346ebf6SJeff Kirsher  */
1545346ebf6SJeff Kirsher #define ENA_TMT_OK           0x80
1555346ebf6SJeff Kirsher #define ENA_TMT_REC          0x20
1565346ebf6SJeff Kirsher #define ENA_COL              0x04
1575346ebf6SJeff Kirsher #define ENA_16_COL           0x02
1585346ebf6SJeff Kirsher #define ENA_TBUS_ERR         0x01
1595346ebf6SJeff Kirsher 
1605346ebf6SJeff Kirsher #define ENA_PKT_RDY          0x80
1615346ebf6SJeff Kirsher #define ENA_BUS_ERR          0x40
1625346ebf6SJeff Kirsher #define ENA_LEN_ERR          0x08
1635346ebf6SJeff Kirsher #define ENA_ALG_ERR          0x04
1645346ebf6SJeff Kirsher #define ENA_CRC_ERR          0x02
1655346ebf6SJeff Kirsher #define ENA_OVR_FLO          0x01
1665346ebf6SJeff Kirsher 
1675346ebf6SJeff Kirsher /* flags */
1685346ebf6SJeff Kirsher #define F_TMT_RDY            0x80 /* can accept new packet */
1695346ebf6SJeff Kirsher #define F_NET_BSY            0x40 /* carrier is detected */
1705346ebf6SJeff Kirsher #define F_TMT_OK             0x20 /* send packet successfully */
1715346ebf6SJeff Kirsher #define F_SRT_PKT            0x10 /* short packet error */
1725346ebf6SJeff Kirsher #define F_COL_ERR            0x04 /* collision error */
1735346ebf6SJeff Kirsher #define F_16_COL             0x02 /* 16 collision error */
1745346ebf6SJeff Kirsher #define F_TBUS_ERR           0x01 /* bus read error */
1755346ebf6SJeff Kirsher 
1765346ebf6SJeff Kirsher #define F_PKT_RDY            0x80 /* packet(s) in buffer */
1775346ebf6SJeff Kirsher #define F_BUS_ERR            0x40 /* bus read error */
1785346ebf6SJeff Kirsher #define F_LEN_ERR            0x08 /* short packet */
1795346ebf6SJeff Kirsher #define F_ALG_ERR            0x04 /* frame error */
1805346ebf6SJeff Kirsher #define F_CRC_ERR            0x02 /* CRC error */
1815346ebf6SJeff Kirsher #define F_OVR_FLO            0x01 /* overflow error */
1825346ebf6SJeff Kirsher 
1835346ebf6SJeff Kirsher #define F_BUF_EMP            0x40 /* receive buffer is empty */
1845346ebf6SJeff Kirsher 
1855346ebf6SJeff Kirsher #define F_SKP_PKT            0x05 /* drop packet in buffer */
1865346ebf6SJeff Kirsher 
1875346ebf6SJeff Kirsher /* default bitmaps */
1885346ebf6SJeff Kirsher #define D_TX_INTR  ( ENA_TMT_OK )
1895346ebf6SJeff Kirsher #define D_RX_INTR  ( ENA_PKT_RDY | ENA_LEN_ERR \
1905346ebf6SJeff Kirsher 		   | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
1915346ebf6SJeff Kirsher #define TX_STAT_M  ( F_TMT_RDY )
1925346ebf6SJeff Kirsher #define RX_STAT_M  ( F_PKT_RDY | F_LEN_ERR \
1935346ebf6SJeff Kirsher                    | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
1945346ebf6SJeff Kirsher 
1955346ebf6SJeff Kirsher /* commands */
1965346ebf6SJeff Kirsher #define D_TX_MODE            0x06 /* no tests, detect carrier */
1975346ebf6SJeff Kirsher #define ID_MATCHED           0x02 /* (RX_MODE) */
1985346ebf6SJeff Kirsher #define RECV_ALL             0x03 /* (RX_MODE) */
1995346ebf6SJeff Kirsher #define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
2005346ebf6SJeff Kirsher #define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
2015346ebf6SJeff Kirsher #define CONFIG0_RST          0xda /* Data Link Controller off (CONFIG_0) */
2025346ebf6SJeff Kirsher #define CONFIG0_RST_1        0xde /* Data Link Controller off (CONFIG_0) */
2035346ebf6SJeff Kirsher #define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
2045346ebf6SJeff Kirsher #define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
2055346ebf6SJeff Kirsher #define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
2065346ebf6SJeff Kirsher #define CHIP_OFF             0x80 /* contrl chip power off (CONFIG_1) */
2075346ebf6SJeff Kirsher #define DO_TX                0x80 /* do transmit packet */
2085346ebf6SJeff Kirsher #define SEND_PKT             0x81 /* send a packet */
2095346ebf6SJeff Kirsher #define AUTO_MODE            0x07 /* Auto skip packet on 16 col detected */
2105346ebf6SJeff Kirsher #define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
2115346ebf6SJeff Kirsher #define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
2125346ebf6SJeff Kirsher #define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
2135346ebf6SJeff Kirsher #define INTR_OFF             0x0d /* LAN controller ignores interrupts */
2145346ebf6SJeff Kirsher #define INTR_ON              0x1d /* LAN controller will catch interrupts */
2155346ebf6SJeff Kirsher 
2165346ebf6SJeff Kirsher #define TX_TIMEOUT		((400*HZ)/1000)
2175346ebf6SJeff Kirsher 
2185346ebf6SJeff Kirsher #define BANK_0U              0x20 /* bank 0 (CONFIG_1) */
2195346ebf6SJeff Kirsher #define BANK_1U              0x24 /* bank 1 (CONFIG_1) */
2205346ebf6SJeff Kirsher #define BANK_2U              0x28 /* bank 2 (CONFIG_1) */
2215346ebf6SJeff Kirsher 
2225346ebf6SJeff Kirsher static const struct net_device_ops fjn_netdev_ops = {
2235346ebf6SJeff Kirsher 	.ndo_open 		= fjn_open,
2245346ebf6SJeff Kirsher 	.ndo_stop		= fjn_close,
2255346ebf6SJeff Kirsher 	.ndo_start_xmit 	= fjn_start_xmit,
2265346ebf6SJeff Kirsher 	.ndo_tx_timeout 	= fjn_tx_timeout,
2275346ebf6SJeff Kirsher 	.ndo_set_config 	= fjn_config,
228afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= set_rx_mode,
2295346ebf6SJeff Kirsher 	.ndo_change_mtu		= eth_change_mtu,
2305346ebf6SJeff Kirsher 	.ndo_set_mac_address 	= eth_mac_addr,
2315346ebf6SJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
2325346ebf6SJeff Kirsher };
2335346ebf6SJeff Kirsher 
2345346ebf6SJeff Kirsher static int fmvj18x_probe(struct pcmcia_device *link)
2355346ebf6SJeff Kirsher {
2365346ebf6SJeff Kirsher     local_info_t *lp;
2375346ebf6SJeff Kirsher     struct net_device *dev;
2385346ebf6SJeff Kirsher 
2395346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_attach()\n");
2405346ebf6SJeff Kirsher 
2415346ebf6SJeff Kirsher     /* Make up a FMVJ18x specific data structure */
2425346ebf6SJeff Kirsher     dev = alloc_etherdev(sizeof(local_info_t));
2435346ebf6SJeff Kirsher     if (!dev)
2445346ebf6SJeff Kirsher 	return -ENOMEM;
2455346ebf6SJeff Kirsher     lp = netdev_priv(dev);
2465346ebf6SJeff Kirsher     link->priv = dev;
2475346ebf6SJeff Kirsher     lp->p_dev = link;
2485346ebf6SJeff Kirsher     lp->base = NULL;
2495346ebf6SJeff Kirsher 
2505346ebf6SJeff Kirsher     /* The io structure describes IO port mapping */
2515346ebf6SJeff Kirsher     link->resource[0]->end = 32;
2525346ebf6SJeff Kirsher     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
2535346ebf6SJeff Kirsher 
2545346ebf6SJeff Kirsher     /* General socket configuration */
2555346ebf6SJeff Kirsher     link->config_flags |= CONF_ENABLE_IRQ;
2565346ebf6SJeff Kirsher 
2575346ebf6SJeff Kirsher     dev->netdev_ops = &fjn_netdev_ops;
2585346ebf6SJeff Kirsher     dev->watchdog_timeo = TX_TIMEOUT;
2595346ebf6SJeff Kirsher 
2605346ebf6SJeff Kirsher     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
2615346ebf6SJeff Kirsher 
2625346ebf6SJeff Kirsher     return fmvj18x_config(link);
2635346ebf6SJeff Kirsher } /* fmvj18x_attach */
2645346ebf6SJeff Kirsher 
2655346ebf6SJeff Kirsher /*====================================================================*/
2665346ebf6SJeff Kirsher 
2675346ebf6SJeff Kirsher static void fmvj18x_detach(struct pcmcia_device *link)
2685346ebf6SJeff Kirsher {
2695346ebf6SJeff Kirsher     struct net_device *dev = link->priv;
2705346ebf6SJeff Kirsher 
2715346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_detach\n");
2725346ebf6SJeff Kirsher 
2735346ebf6SJeff Kirsher     unregister_netdev(dev);
2745346ebf6SJeff Kirsher 
2755346ebf6SJeff Kirsher     fmvj18x_release(link);
2765346ebf6SJeff Kirsher 
2775346ebf6SJeff Kirsher     free_netdev(dev);
2785346ebf6SJeff Kirsher } /* fmvj18x_detach */
2795346ebf6SJeff Kirsher 
2805346ebf6SJeff Kirsher /*====================================================================*/
2815346ebf6SJeff Kirsher 
2825346ebf6SJeff Kirsher static int mfc_try_io_port(struct pcmcia_device *link)
2835346ebf6SJeff Kirsher {
2845346ebf6SJeff Kirsher     int i, ret;
2855346ebf6SJeff Kirsher     static const unsigned int serial_base[5] =
2865346ebf6SJeff Kirsher 	{ 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
2875346ebf6SJeff Kirsher 
2885346ebf6SJeff Kirsher     for (i = 0; i < 5; i++) {
2895346ebf6SJeff Kirsher 	link->resource[1]->start = serial_base[i];
2905346ebf6SJeff Kirsher 	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
2915346ebf6SJeff Kirsher 	if (link->resource[1]->start == 0) {
2925346ebf6SJeff Kirsher 	    link->resource[1]->end = 0;
2935346ebf6SJeff Kirsher 	    pr_notice("out of resource for serial\n");
2945346ebf6SJeff Kirsher 	}
2955346ebf6SJeff Kirsher 	ret = pcmcia_request_io(link);
2965346ebf6SJeff Kirsher 	if (ret == 0)
2975346ebf6SJeff Kirsher 		return ret;
2985346ebf6SJeff Kirsher     }
2995346ebf6SJeff Kirsher     return ret;
3005346ebf6SJeff Kirsher }
3015346ebf6SJeff Kirsher 
3025346ebf6SJeff Kirsher static int ungermann_try_io_port(struct pcmcia_device *link)
3035346ebf6SJeff Kirsher {
3045346ebf6SJeff Kirsher     int ret;
3055346ebf6SJeff Kirsher     unsigned int ioaddr;
3065346ebf6SJeff Kirsher     /*
3075346ebf6SJeff Kirsher 	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
3085346ebf6SJeff Kirsher 	0x380,0x3c0 only for ioport.
3095346ebf6SJeff Kirsher     */
3105346ebf6SJeff Kirsher     for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
3115346ebf6SJeff Kirsher 	link->resource[0]->start = ioaddr;
3125346ebf6SJeff Kirsher 	ret = pcmcia_request_io(link);
3135346ebf6SJeff Kirsher 	if (ret == 0) {
3145346ebf6SJeff Kirsher 	    /* calculate ConfigIndex value */
3155346ebf6SJeff Kirsher 	    link->config_index =
3165346ebf6SJeff Kirsher 		((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
3175346ebf6SJeff Kirsher 	    return ret;
3185346ebf6SJeff Kirsher 	}
3195346ebf6SJeff Kirsher     }
3205346ebf6SJeff Kirsher     return ret;	/* RequestIO failed */
3215346ebf6SJeff Kirsher }
3225346ebf6SJeff Kirsher 
3235346ebf6SJeff Kirsher static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
3245346ebf6SJeff Kirsher {
3255346ebf6SJeff Kirsher 	return 0; /* strange, but that's what the code did already before... */
3265346ebf6SJeff Kirsher }
3275346ebf6SJeff Kirsher 
3285346ebf6SJeff Kirsher static int fmvj18x_config(struct pcmcia_device *link)
3295346ebf6SJeff Kirsher {
3305346ebf6SJeff Kirsher     struct net_device *dev = link->priv;
3315346ebf6SJeff Kirsher     local_info_t *lp = netdev_priv(dev);
3325346ebf6SJeff Kirsher     int i, ret;
3335346ebf6SJeff Kirsher     unsigned int ioaddr;
3345346ebf6SJeff Kirsher     cardtype_t cardtype;
3355346ebf6SJeff Kirsher     char *card_name = "unknown";
3365346ebf6SJeff Kirsher     u8 *buf;
3375346ebf6SJeff Kirsher     size_t len;
3385346ebf6SJeff Kirsher     u_char buggybuf[32];
3395346ebf6SJeff Kirsher 
3405346ebf6SJeff Kirsher     dev_dbg(&link->dev, "fmvj18x_config\n");
3415346ebf6SJeff Kirsher 
3425346ebf6SJeff Kirsher     link->io_lines = 5;
3435346ebf6SJeff Kirsher 
3445346ebf6SJeff Kirsher     len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
3455346ebf6SJeff Kirsher     kfree(buf);
3465346ebf6SJeff Kirsher 
3475346ebf6SJeff Kirsher     if (len) {
3485346ebf6SJeff Kirsher 	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
3495346ebf6SJeff Kirsher 	ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL);
3505346ebf6SJeff Kirsher 	if (ret != 0)
3515346ebf6SJeff Kirsher 		goto failed;
3525346ebf6SJeff Kirsher 
3535346ebf6SJeff Kirsher 	switch (link->manf_id) {
3545346ebf6SJeff Kirsher 	case MANFID_TDK:
3555346ebf6SJeff Kirsher 	    cardtype = TDK;
3565346ebf6SJeff Kirsher 	    if (link->card_id == PRODID_TDK_GN3410 ||
3575346ebf6SJeff Kirsher 		link->card_id == PRODID_TDK_NP9610 ||
3585346ebf6SJeff Kirsher 		link->card_id == PRODID_TDK_MN3200) {
3595346ebf6SJeff Kirsher 		/* MultiFunction Card */
3605346ebf6SJeff Kirsher 		link->config_base = 0x800;
3615346ebf6SJeff Kirsher 		link->config_index = 0x47;
3625346ebf6SJeff Kirsher 		link->resource[1]->end = 8;
3635346ebf6SJeff Kirsher 	    }
3645346ebf6SJeff Kirsher 	    break;
3655346ebf6SJeff Kirsher 	case MANFID_NEC:
3665346ebf6SJeff Kirsher 	    cardtype = NEC; /* MultiFunction Card */
3675346ebf6SJeff Kirsher 	    link->config_base = 0x800;
3685346ebf6SJeff Kirsher 	    link->config_index = 0x47;
3695346ebf6SJeff Kirsher 	    link->resource[1]->end = 8;
3705346ebf6SJeff Kirsher 	    break;
3715346ebf6SJeff Kirsher 	case MANFID_KME:
3725346ebf6SJeff Kirsher 	    cardtype = KME; /* MultiFunction Card */
3735346ebf6SJeff Kirsher 	    link->config_base = 0x800;
3745346ebf6SJeff Kirsher 	    link->config_index = 0x47;
3755346ebf6SJeff Kirsher 	    link->resource[1]->end = 8;
3765346ebf6SJeff Kirsher 	    break;
3775346ebf6SJeff Kirsher 	case MANFID_CONTEC:
3785346ebf6SJeff Kirsher 	    cardtype = CONTEC;
3795346ebf6SJeff Kirsher 	    break;
3805346ebf6SJeff Kirsher 	case MANFID_FUJITSU:
3815346ebf6SJeff Kirsher 	    if (link->config_base == 0x0fe0)
3825346ebf6SJeff Kirsher 		cardtype = MBH10302;
3835346ebf6SJeff Kirsher 	    else if (link->card_id == PRODID_FUJITSU_MBH10302)
3845346ebf6SJeff Kirsher                 /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
3855346ebf6SJeff Kirsher                    but these are MBH10304 based card. */
3865346ebf6SJeff Kirsher 		cardtype = MBH10304;
3875346ebf6SJeff Kirsher 	    else if (link->card_id == PRODID_FUJITSU_MBH10304)
3885346ebf6SJeff Kirsher 		cardtype = MBH10304;
3895346ebf6SJeff Kirsher 	    else
3905346ebf6SJeff Kirsher 		cardtype = LA501;
3915346ebf6SJeff Kirsher 	    break;
3925346ebf6SJeff Kirsher 	default:
3935346ebf6SJeff Kirsher 	    cardtype = MBH10304;
3945346ebf6SJeff Kirsher 	}
3955346ebf6SJeff Kirsher     } else {
3965346ebf6SJeff Kirsher 	/* old type card */
3975346ebf6SJeff Kirsher 	switch (link->manf_id) {
3985346ebf6SJeff Kirsher 	case MANFID_FUJITSU:
3995346ebf6SJeff Kirsher 	    if (link->card_id == PRODID_FUJITSU_MBH10304) {
4005346ebf6SJeff Kirsher 		cardtype = XXX10304;    /* MBH10304 with buggy CIS */
4015346ebf6SJeff Kirsher 		link->config_index = 0x20;
4025346ebf6SJeff Kirsher 	    } else {
4035346ebf6SJeff Kirsher 		cardtype = MBH10302;    /* NextCom NC5310, etc. */
4045346ebf6SJeff Kirsher 		link->config_index = 1;
4055346ebf6SJeff Kirsher 	    }
4065346ebf6SJeff Kirsher 	    break;
4075346ebf6SJeff Kirsher 	case MANFID_UNGERMANN:
4085346ebf6SJeff Kirsher 	    cardtype = UNGERMANN;
4095346ebf6SJeff Kirsher 	    break;
4105346ebf6SJeff Kirsher 	default:
4115346ebf6SJeff Kirsher 	    cardtype = MBH10302;
4125346ebf6SJeff Kirsher 	    link->config_index = 1;
4135346ebf6SJeff Kirsher 	}
4145346ebf6SJeff Kirsher     }
4155346ebf6SJeff Kirsher 
4165346ebf6SJeff Kirsher     if (link->resource[1]->end != 0) {
4175346ebf6SJeff Kirsher 	ret = mfc_try_io_port(link);
4185346ebf6SJeff Kirsher 	if (ret != 0) goto failed;
4195346ebf6SJeff Kirsher     } else if (cardtype == UNGERMANN) {
4205346ebf6SJeff Kirsher 	ret = ungermann_try_io_port(link);
4215346ebf6SJeff Kirsher 	if (ret != 0) goto failed;
4225346ebf6SJeff Kirsher     } else {
4235346ebf6SJeff Kirsher 	    ret = pcmcia_request_io(link);
4245346ebf6SJeff Kirsher 	    if (ret)
4255346ebf6SJeff Kirsher 		    goto failed;
4265346ebf6SJeff Kirsher     }
4275346ebf6SJeff Kirsher     ret = pcmcia_request_irq(link, fjn_interrupt);
4285346ebf6SJeff Kirsher     if (ret)
4295346ebf6SJeff Kirsher 	    goto failed;
4305346ebf6SJeff Kirsher     ret = pcmcia_enable_device(link);
4315346ebf6SJeff Kirsher     if (ret)
4325346ebf6SJeff Kirsher 	    goto failed;
4335346ebf6SJeff Kirsher 
4345346ebf6SJeff Kirsher     dev->irq = link->irq;
4355346ebf6SJeff Kirsher     dev->base_addr = link->resource[0]->start;
4365346ebf6SJeff Kirsher 
4375346ebf6SJeff Kirsher     if (resource_size(link->resource[1]) != 0) {
4385346ebf6SJeff Kirsher 	ret = fmvj18x_setup_mfc(link);
4395346ebf6SJeff Kirsher 	if (ret != 0) goto failed;
4405346ebf6SJeff Kirsher     }
4415346ebf6SJeff Kirsher 
4425346ebf6SJeff Kirsher     ioaddr = dev->base_addr;
4435346ebf6SJeff Kirsher 
4445346ebf6SJeff Kirsher     /* Reset controller */
4455346ebf6SJeff Kirsher     if (sram_config == 0)
4465346ebf6SJeff Kirsher 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
4475346ebf6SJeff Kirsher     else
4485346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
4495346ebf6SJeff Kirsher 
4505346ebf6SJeff Kirsher     /* Power On chip and select bank 0 */
4515346ebf6SJeff Kirsher     if (cardtype == MBH10302)
4525346ebf6SJeff Kirsher 	outb(BANK_0, ioaddr + CONFIG_1);
4535346ebf6SJeff Kirsher     else
4545346ebf6SJeff Kirsher 	outb(BANK_0U, ioaddr + CONFIG_1);
4555346ebf6SJeff Kirsher 
4565346ebf6SJeff Kirsher     /* Set hardware address */
4575346ebf6SJeff Kirsher     switch (cardtype) {
4585346ebf6SJeff Kirsher     case MBH10304:
4595346ebf6SJeff Kirsher     case TDK:
4605346ebf6SJeff Kirsher     case LA501:
4615346ebf6SJeff Kirsher     case CONTEC:
4625346ebf6SJeff Kirsher     case NEC:
4635346ebf6SJeff Kirsher     case KME:
4645346ebf6SJeff Kirsher 	if (cardtype == MBH10304) {
4655346ebf6SJeff Kirsher 	    card_name = "FMV-J182";
4665346ebf6SJeff Kirsher 
4675346ebf6SJeff Kirsher 	    len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
4685346ebf6SJeff Kirsher 	    if (len < 11) {
4695346ebf6SJeff Kirsher 		    kfree(buf);
4705346ebf6SJeff Kirsher 		    goto failed;
4715346ebf6SJeff Kirsher 	    }
4725346ebf6SJeff Kirsher 	    /* Read MACID from CIS */
4735346ebf6SJeff Kirsher 	    for (i = 5; i < 11; i++)
4745346ebf6SJeff Kirsher 		    dev->dev_addr[i] = buf[i];
4755346ebf6SJeff Kirsher 	    kfree(buf);
4765346ebf6SJeff Kirsher 	} else {
4775346ebf6SJeff Kirsher 	    if (pcmcia_get_mac_from_cis(link, dev))
4785346ebf6SJeff Kirsher 		goto failed;
4795346ebf6SJeff Kirsher 	    if( cardtype == TDK ) {
4805346ebf6SJeff Kirsher 		card_name = "TDK LAK-CD021";
4815346ebf6SJeff Kirsher 	    } else if( cardtype == LA501 ) {
4825346ebf6SJeff Kirsher 		card_name = "LA501";
4835346ebf6SJeff Kirsher 	    } else if( cardtype == NEC ) {
4845346ebf6SJeff Kirsher 		card_name = "PK-UG-J001";
4855346ebf6SJeff Kirsher 	    } else if( cardtype == KME ) {
4865346ebf6SJeff Kirsher 		card_name = "Panasonic";
4875346ebf6SJeff Kirsher 	    } else {
4885346ebf6SJeff Kirsher 		card_name = "C-NET(PC)C";
4895346ebf6SJeff Kirsher 	    }
4905346ebf6SJeff Kirsher 	}
4915346ebf6SJeff Kirsher 	break;
4925346ebf6SJeff Kirsher     case UNGERMANN:
4935346ebf6SJeff Kirsher 	/* Read MACID from register */
4945346ebf6SJeff Kirsher 	for (i = 0; i < 6; i++)
4955346ebf6SJeff Kirsher 	    dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i);
4965346ebf6SJeff Kirsher 	card_name = "Access/CARD";
4975346ebf6SJeff Kirsher 	break;
4985346ebf6SJeff Kirsher     case XXX10304:
4995346ebf6SJeff Kirsher 	/* Read MACID from Buggy CIS */
5005346ebf6SJeff Kirsher 	if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
5015346ebf6SJeff Kirsher 	    pr_notice("unable to read hardware net address\n");
5025346ebf6SJeff Kirsher 	    goto failed;
5035346ebf6SJeff Kirsher 	}
5045346ebf6SJeff Kirsher 	for (i = 0 ; i < 6; i++) {
5055346ebf6SJeff Kirsher 	    dev->dev_addr[i] = buggybuf[i];
5065346ebf6SJeff Kirsher 	}
5075346ebf6SJeff Kirsher 	card_name = "FMV-J182";
5085346ebf6SJeff Kirsher 	break;
5095346ebf6SJeff Kirsher     case MBH10302:
5105346ebf6SJeff Kirsher     default:
5115346ebf6SJeff Kirsher 	/* Read MACID from register */
5125346ebf6SJeff Kirsher 	for (i = 0; i < 6; i++)
5135346ebf6SJeff Kirsher 	    dev->dev_addr[i] = inb(ioaddr + MAC_ID + i);
5145346ebf6SJeff Kirsher 	card_name = "FMV-J181";
5155346ebf6SJeff Kirsher 	break;
5165346ebf6SJeff Kirsher     }
5175346ebf6SJeff Kirsher 
5185346ebf6SJeff Kirsher     lp->cardtype = cardtype;
5195346ebf6SJeff Kirsher     SET_NETDEV_DEV(dev, &link->dev);
5205346ebf6SJeff Kirsher 
5215346ebf6SJeff Kirsher     if (register_netdev(dev) != 0) {
5225346ebf6SJeff Kirsher 	pr_notice("register_netdev() failed\n");
5235346ebf6SJeff Kirsher 	goto failed;
5245346ebf6SJeff Kirsher     }
5255346ebf6SJeff Kirsher 
5265346ebf6SJeff Kirsher     /* print current configuration */
5275346ebf6SJeff Kirsher     netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
5285346ebf6SJeff Kirsher 		card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
5295346ebf6SJeff Kirsher 		dev->base_addr, dev->irq, dev->dev_addr);
5305346ebf6SJeff Kirsher 
5315346ebf6SJeff Kirsher     return 0;
5325346ebf6SJeff Kirsher 
5335346ebf6SJeff Kirsher failed:
5345346ebf6SJeff Kirsher     fmvj18x_release(link);
5355346ebf6SJeff Kirsher     return -ENODEV;
5365346ebf6SJeff Kirsher } /* fmvj18x_config */
5375346ebf6SJeff Kirsher /*====================================================================*/
5385346ebf6SJeff Kirsher 
5395346ebf6SJeff Kirsher static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
5405346ebf6SJeff Kirsher {
5415346ebf6SJeff Kirsher     u_char __iomem *base;
5425346ebf6SJeff Kirsher     int i, j;
5435346ebf6SJeff Kirsher 
5445346ebf6SJeff Kirsher     /* Allocate a small memory window */
5455346ebf6SJeff Kirsher     link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
5465346ebf6SJeff Kirsher     link->resource[2]->start = 0; link->resource[2]->end = 0;
5475346ebf6SJeff Kirsher     i = pcmcia_request_window(link, link->resource[2], 0);
5485346ebf6SJeff Kirsher     if (i != 0)
5495346ebf6SJeff Kirsher 	return -1;
5505346ebf6SJeff Kirsher 
5515346ebf6SJeff Kirsher     base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
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;
5885346ebf6SJeff Kirsher     local_info_t *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;
6305346ebf6SJeff Kirsher     local_info_t *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 };
708*fdd3f29eSH 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;
7155346ebf6SJeff Kirsher     local_info_t *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;
7505346ebf6SJeff Kirsher 	    dev->trans_start = jiffies;
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 
7745346ebf6SJeff Kirsher static void fjn_tx_timeout(struct net_device *dev)
7755346ebf6SJeff Kirsher {
7765346ebf6SJeff Kirsher     struct local_info_t *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 {
8065346ebf6SJeff Kirsher     struct local_info_t *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 {
8785346ebf6SJeff Kirsher     struct local_info_t *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 		netdev_notice(dev, "Memory squeeze, dropping packet (len %d)\n",
9955346ebf6SJeff Kirsher 			      pkt_len);
9965346ebf6SJeff Kirsher 		outb(F_SKP_PKT, ioaddr + RX_SKIP);
9975346ebf6SJeff Kirsher 		dev->stats.rx_dropped++;
9985346ebf6SJeff Kirsher 		break;
9995346ebf6SJeff Kirsher 	    }
10005346ebf6SJeff Kirsher 
10015346ebf6SJeff Kirsher 	    skb_reserve(skb, 2);
10025346ebf6SJeff Kirsher 	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
10035346ebf6SJeff Kirsher 		 (pkt_len + 1) >> 1);
10045346ebf6SJeff Kirsher 	    skb->protocol = eth_type_trans(skb, dev);
10055346ebf6SJeff Kirsher 
10065346ebf6SJeff Kirsher 	    {
10075346ebf6SJeff Kirsher 		int i;
10085346ebf6SJeff Kirsher 		pr_debug("%s: Rxed packet of length %d: ",
10095346ebf6SJeff Kirsher 			dev->name, pkt_len);
10105346ebf6SJeff Kirsher 		for (i = 0; i < 14; i++)
10115346ebf6SJeff Kirsher 			pr_debug(" %02x", skb->data[i]);
10125346ebf6SJeff Kirsher 		pr_debug(".\n");
10135346ebf6SJeff Kirsher 	    }
10145346ebf6SJeff Kirsher 
10155346ebf6SJeff Kirsher 	    netif_rx(skb);
10165346ebf6SJeff Kirsher 	    dev->stats.rx_packets++;
10175346ebf6SJeff Kirsher 	    dev->stats.rx_bytes += pkt_len;
10185346ebf6SJeff Kirsher 	}
10195346ebf6SJeff Kirsher 	if (--boguscount <= 0)
10205346ebf6SJeff Kirsher 	    break;
10215346ebf6SJeff Kirsher     }
10225346ebf6SJeff Kirsher 
10235346ebf6SJeff Kirsher     /* If any worth-while packets have been received, dev_rint()
10245346ebf6SJeff Kirsher 	   has done a netif_wake_queue() for us and will work on them
10255346ebf6SJeff Kirsher 	   when we get to the bottom-half routine. */
10265346ebf6SJeff Kirsher /*
10275346ebf6SJeff Kirsher     if (lp->cardtype != TDK) {
10285346ebf6SJeff Kirsher 	int i;
10295346ebf6SJeff Kirsher 	for (i = 0; i < 20; i++) {
10305346ebf6SJeff Kirsher 	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
10315346ebf6SJeff Kirsher 		break;
10325346ebf6SJeff Kirsher 	    (void)inw(ioaddr + DATAPORT);  /+ dummy status read +/
10335346ebf6SJeff Kirsher 	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
10345346ebf6SJeff Kirsher 	}
10355346ebf6SJeff Kirsher 
10365346ebf6SJeff Kirsher 	if (i > 0)
10375346ebf6SJeff Kirsher 	    pr_debug("%s: Exint Rx packet with mode %02x after "
10385346ebf6SJeff Kirsher 		  "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
10395346ebf6SJeff Kirsher     }
10405346ebf6SJeff Kirsher */
10415346ebf6SJeff Kirsher } /* fjn_rx */
10425346ebf6SJeff Kirsher 
10435346ebf6SJeff Kirsher /*====================================================================*/
10445346ebf6SJeff Kirsher 
10455346ebf6SJeff Kirsher static void netdev_get_drvinfo(struct net_device *dev,
10465346ebf6SJeff Kirsher 			       struct ethtool_drvinfo *info)
10475346ebf6SJeff Kirsher {
104833a5ba14SRick Jones 	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
104933a5ba14SRick Jones 	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
105033a5ba14SRick Jones 	snprintf(info->bus_info, sizeof(info->bus_info),
105133a5ba14SRick Jones 		"PCMCIA 0x%lx", dev->base_addr);
10525346ebf6SJeff Kirsher }
10535346ebf6SJeff Kirsher 
10545346ebf6SJeff Kirsher static const struct ethtool_ops netdev_ethtool_ops = {
10555346ebf6SJeff Kirsher 	.get_drvinfo		= netdev_get_drvinfo,
10565346ebf6SJeff Kirsher };
10575346ebf6SJeff Kirsher 
10585346ebf6SJeff Kirsher static int fjn_config(struct net_device *dev, struct ifmap *map){
10595346ebf6SJeff Kirsher     return 0;
10605346ebf6SJeff Kirsher }
10615346ebf6SJeff Kirsher 
10625346ebf6SJeff Kirsher static int fjn_open(struct net_device *dev)
10635346ebf6SJeff Kirsher {
10645346ebf6SJeff Kirsher     struct local_info_t *lp = netdev_priv(dev);
10655346ebf6SJeff Kirsher     struct pcmcia_device *link = lp->p_dev;
10665346ebf6SJeff Kirsher 
10675346ebf6SJeff Kirsher     pr_debug("fjn_open('%s').\n", dev->name);
10685346ebf6SJeff Kirsher 
10695346ebf6SJeff Kirsher     if (!pcmcia_dev_present(link))
10705346ebf6SJeff Kirsher 	return -ENODEV;
10715346ebf6SJeff Kirsher 
10725346ebf6SJeff Kirsher     link->open++;
10735346ebf6SJeff Kirsher 
10745346ebf6SJeff Kirsher     fjn_reset(dev);
10755346ebf6SJeff Kirsher 
10765346ebf6SJeff Kirsher     lp->tx_started = 0;
10775346ebf6SJeff Kirsher     lp->tx_queue = 0;
10785346ebf6SJeff Kirsher     lp->tx_queue_len = 0;
10795346ebf6SJeff Kirsher     lp->open_time = jiffies;
10805346ebf6SJeff Kirsher     netif_start_queue(dev);
10815346ebf6SJeff Kirsher 
10825346ebf6SJeff Kirsher     return 0;
10835346ebf6SJeff Kirsher } /* fjn_open */
10845346ebf6SJeff Kirsher 
10855346ebf6SJeff Kirsher /*====================================================================*/
10865346ebf6SJeff Kirsher 
10875346ebf6SJeff Kirsher static int fjn_close(struct net_device *dev)
10885346ebf6SJeff Kirsher {
10895346ebf6SJeff Kirsher     struct local_info_t *lp = netdev_priv(dev);
10905346ebf6SJeff Kirsher     struct pcmcia_device *link = lp->p_dev;
10915346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
10925346ebf6SJeff Kirsher 
10935346ebf6SJeff Kirsher     pr_debug("fjn_close('%s').\n", dev->name);
10945346ebf6SJeff Kirsher 
10955346ebf6SJeff Kirsher     lp->open_time = 0;
10965346ebf6SJeff Kirsher     netif_stop_queue(dev);
10975346ebf6SJeff Kirsher 
10985346ebf6SJeff Kirsher     /* Set configuration register 0 to disable Tx and Rx. */
10995346ebf6SJeff Kirsher     if( sram_config == 0 )
11005346ebf6SJeff Kirsher 	outb(CONFIG0_RST ,ioaddr + CONFIG_0);
11015346ebf6SJeff Kirsher     else
11025346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
11035346ebf6SJeff Kirsher 
11045346ebf6SJeff Kirsher     /* Update the statistics -- ToDo. */
11055346ebf6SJeff Kirsher 
11065346ebf6SJeff Kirsher     /* Power-down the chip.  Green, green, green! */
11075346ebf6SJeff Kirsher     outb(CHIP_OFF ,ioaddr + CONFIG_1);
11085346ebf6SJeff Kirsher 
11095346ebf6SJeff Kirsher     /* Set the ethernet adaptor disable IRQ */
11105346ebf6SJeff Kirsher     if (lp->cardtype == MBH10302)
11115346ebf6SJeff Kirsher 	outb(INTR_OFF, ioaddr + LAN_CTRL);
11125346ebf6SJeff Kirsher 
11135346ebf6SJeff Kirsher     link->open--;
11145346ebf6SJeff Kirsher 
11155346ebf6SJeff Kirsher     return 0;
11165346ebf6SJeff Kirsher } /* fjn_close */
11175346ebf6SJeff Kirsher 
11185346ebf6SJeff Kirsher /*====================================================================*/
11195346ebf6SJeff Kirsher 
11205346ebf6SJeff Kirsher /*
11215346ebf6SJeff Kirsher   Set the multicast/promiscuous mode for this adaptor.
11225346ebf6SJeff Kirsher */
11235346ebf6SJeff Kirsher 
11245346ebf6SJeff Kirsher static void set_rx_mode(struct net_device *dev)
11255346ebf6SJeff Kirsher {
11265346ebf6SJeff Kirsher     unsigned int ioaddr = dev->base_addr;
11275346ebf6SJeff Kirsher     u_char mc_filter[8];		 /* Multicast hash filter */
11285346ebf6SJeff Kirsher     u_long flags;
11295346ebf6SJeff Kirsher     int i;
11305346ebf6SJeff Kirsher 
11315346ebf6SJeff Kirsher     int saved_bank;
11325346ebf6SJeff Kirsher     int saved_config_0 = inb(ioaddr + CONFIG_0);
11335346ebf6SJeff Kirsher 
11345346ebf6SJeff Kirsher     local_irq_save(flags);
11355346ebf6SJeff Kirsher 
11365346ebf6SJeff Kirsher     /* Disable Tx and Rx */
11375346ebf6SJeff Kirsher     if (sram_config == 0)
11385346ebf6SJeff Kirsher 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
11395346ebf6SJeff Kirsher     else
11405346ebf6SJeff Kirsher 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
11415346ebf6SJeff Kirsher 
11425346ebf6SJeff Kirsher     if (dev->flags & IFF_PROMISC) {
11435346ebf6SJeff Kirsher 	memset(mc_filter, 0xff, sizeof(mc_filter));
11445346ebf6SJeff Kirsher 	outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
11455346ebf6SJeff Kirsher     } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
11465346ebf6SJeff Kirsher 	       (dev->flags & IFF_ALLMULTI)) {
11475346ebf6SJeff Kirsher 	/* Too many to filter perfectly -- accept all multicasts. */
11485346ebf6SJeff Kirsher 	memset(mc_filter, 0xff, sizeof(mc_filter));
11495346ebf6SJeff Kirsher 	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
11505346ebf6SJeff Kirsher     } else if (netdev_mc_empty(dev)) {
11515346ebf6SJeff Kirsher 	memset(mc_filter, 0x00, sizeof(mc_filter));
11525346ebf6SJeff Kirsher 	outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
11535346ebf6SJeff Kirsher     } else {
11545346ebf6SJeff Kirsher 	struct netdev_hw_addr *ha;
11555346ebf6SJeff Kirsher 
11565346ebf6SJeff Kirsher 	memset(mc_filter, 0, sizeof(mc_filter));
11575346ebf6SJeff Kirsher 	netdev_for_each_mc_addr(ha, dev) {
11585346ebf6SJeff Kirsher 	    unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
11595346ebf6SJeff Kirsher 	    mc_filter[bit >> 3] |= (1 << (bit & 7));
11605346ebf6SJeff Kirsher 	}
11615346ebf6SJeff Kirsher 	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
11625346ebf6SJeff Kirsher     }
11635346ebf6SJeff Kirsher 
11645346ebf6SJeff Kirsher     /* Switch to bank 1 and set the multicast table. */
11655346ebf6SJeff Kirsher     saved_bank = inb(ioaddr + CONFIG_1);
11665346ebf6SJeff Kirsher     outb(0xe4, ioaddr + CONFIG_1);
11675346ebf6SJeff Kirsher 
11685346ebf6SJeff Kirsher     for (i = 0; i < 8; i++)
11695346ebf6SJeff Kirsher 	outb(mc_filter[i], ioaddr + MAR_ADR + i);
11705346ebf6SJeff Kirsher     outb(saved_bank, ioaddr + CONFIG_1);
11715346ebf6SJeff Kirsher 
11725346ebf6SJeff Kirsher     outb(saved_config_0, ioaddr + CONFIG_0);
11735346ebf6SJeff Kirsher 
11745346ebf6SJeff Kirsher     local_irq_restore(flags);
11755346ebf6SJeff Kirsher }
1176