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