1*4882a593Smuzhiyun /*======================================================================
2*4882a593Smuzhiyun fmvj18x_cs.c 2.8 2002/03/23
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun A fmvj18x (and its compatibles) PCMCIA client driver
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun TDK LAK-CD021 and CONTEC C-NET(PC)C support added by
9*4882a593Smuzhiyun Nobuhiro Katayama, kata-n@po.iijnet.or.jp
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun The PCMCIA client code is based on code written by David Hinds.
12*4882a593Smuzhiyun Network code is based on the "FMV-18x driver" by Yutaka TAMIYA
13*4882a593Smuzhiyun but is actually largely Donald Becker's AT1700 driver, which
14*4882a593Smuzhiyun carries the following attribution:
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun Written 1993-94 by Donald Becker.
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun Copyright 1993 United States Government as represented by the
19*4882a593Smuzhiyun Director, National Security Agency.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun This software may be used and distributed according to the terms
22*4882a593Smuzhiyun of the GNU General Public License, incorporated herein by reference.
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun The author may be reached as becker@scyld.com, or C/O
25*4882a593Smuzhiyun Scyld Computing Corporation
26*4882a593Smuzhiyun 410 Severn Ave., Suite 210
27*4882a593Smuzhiyun Annapolis MD 21403
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun ======================================================================*/
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define DRV_NAME "fmvj18x_cs"
34*4882a593Smuzhiyun #define DRV_VERSION "2.9"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #include <linux/module.h>
37*4882a593Smuzhiyun #include <linux/kernel.h>
38*4882a593Smuzhiyun #include <linux/ptrace.h>
39*4882a593Smuzhiyun #include <linux/slab.h>
40*4882a593Smuzhiyun #include <linux/string.h>
41*4882a593Smuzhiyun #include <linux/timer.h>
42*4882a593Smuzhiyun #include <linux/interrupt.h>
43*4882a593Smuzhiyun #include <linux/in.h>
44*4882a593Smuzhiyun #include <linux/delay.h>
45*4882a593Smuzhiyun #include <linux/ethtool.h>
46*4882a593Smuzhiyun #include <linux/netdevice.h>
47*4882a593Smuzhiyun #include <linux/etherdevice.h>
48*4882a593Smuzhiyun #include <linux/skbuff.h>
49*4882a593Smuzhiyun #include <linux/if_arp.h>
50*4882a593Smuzhiyun #include <linux/ioport.h>
51*4882a593Smuzhiyun #include <linux/crc32.h>
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
54*4882a593Smuzhiyun #include <pcmcia/ciscode.h>
55*4882a593Smuzhiyun #include <pcmcia/ds.h>
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #include <linux/uaccess.h>
58*4882a593Smuzhiyun #include <asm/io.h>
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /*====================================================================*/
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* Module parameters */
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
65*4882a593Smuzhiyun MODULE_LICENSE("GPL");
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* SRAM configuration */
70*4882a593Smuzhiyun /* 0:4KB*2 TX buffer else:8KB*2 TX buffer */
71*4882a593Smuzhiyun INT_MODULE_PARM(sram_config, 0);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /*====================================================================*/
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun PCMCIA event handlers
77*4882a593Smuzhiyun */
78*4882a593Smuzhiyun static int fmvj18x_config(struct pcmcia_device *link);
79*4882a593Smuzhiyun static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id);
80*4882a593Smuzhiyun static int fmvj18x_setup_mfc(struct pcmcia_device *link);
81*4882a593Smuzhiyun static void fmvj18x_release(struct pcmcia_device *link);
82*4882a593Smuzhiyun static void fmvj18x_detach(struct pcmcia_device *p_dev);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /*
85*4882a593Smuzhiyun LAN controller(MBH86960A) specific routines
86*4882a593Smuzhiyun */
87*4882a593Smuzhiyun static int fjn_config(struct net_device *dev, struct ifmap *map);
88*4882a593Smuzhiyun static int fjn_open(struct net_device *dev);
89*4882a593Smuzhiyun static int fjn_close(struct net_device *dev);
90*4882a593Smuzhiyun static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
91*4882a593Smuzhiyun struct net_device *dev);
92*4882a593Smuzhiyun static irqreturn_t fjn_interrupt(int irq, void *dev_id);
93*4882a593Smuzhiyun static void fjn_rx(struct net_device *dev);
94*4882a593Smuzhiyun static void fjn_reset(struct net_device *dev);
95*4882a593Smuzhiyun static void set_rx_mode(struct net_device *dev);
96*4882a593Smuzhiyun static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue);
97*4882a593Smuzhiyun static const struct ethtool_ops netdev_ethtool_ops;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /*
100*4882a593Smuzhiyun card type
101*4882a593Smuzhiyun */
102*4882a593Smuzhiyun enum cardtype { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
103*4882a593Smuzhiyun XXX10304, NEC, KME
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /*
107*4882a593Smuzhiyun driver specific data structure
108*4882a593Smuzhiyun */
109*4882a593Smuzhiyun struct local_info {
110*4882a593Smuzhiyun struct pcmcia_device *p_dev;
111*4882a593Smuzhiyun long open_time;
112*4882a593Smuzhiyun uint tx_started:1;
113*4882a593Smuzhiyun uint tx_queue;
114*4882a593Smuzhiyun u_short tx_queue_len;
115*4882a593Smuzhiyun enum cardtype cardtype;
116*4882a593Smuzhiyun u_short sent;
117*4882a593Smuzhiyun u_char __iomem *base;
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun #define MC_FILTERBREAK 64
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /*====================================================================*/
123*4882a593Smuzhiyun /*
124*4882a593Smuzhiyun ioport offset from the base address
125*4882a593Smuzhiyun */
126*4882a593Smuzhiyun #define TX_STATUS 0 /* transmit status register */
127*4882a593Smuzhiyun #define RX_STATUS 1 /* receive status register */
128*4882a593Smuzhiyun #define TX_INTR 2 /* transmit interrupt mask register */
129*4882a593Smuzhiyun #define RX_INTR 3 /* receive interrupt mask register */
130*4882a593Smuzhiyun #define TX_MODE 4 /* transmit mode register */
131*4882a593Smuzhiyun #define RX_MODE 5 /* receive mode register */
132*4882a593Smuzhiyun #define CONFIG_0 6 /* configuration register 0 */
133*4882a593Smuzhiyun #define CONFIG_1 7 /* configuration register 1 */
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun #define NODE_ID 8 /* node ID register (bank 0) */
136*4882a593Smuzhiyun #define MAR_ADR 8 /* multicast address registers (bank 1) */
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun #define DATAPORT 8 /* buffer mem port registers (bank 2) */
139*4882a593Smuzhiyun #define TX_START 10 /* transmit start register */
140*4882a593Smuzhiyun #define COL_CTRL 11 /* 16 collision control register */
141*4882a593Smuzhiyun #define BMPR12 12 /* reserved */
142*4882a593Smuzhiyun #define BMPR13 13 /* reserved */
143*4882a593Smuzhiyun #define RX_SKIP 14 /* skip received packet register */
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun #define LAN_CTRL 16 /* LAN card control register */
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun #define MAC_ID 0x1a /* hardware address */
148*4882a593Smuzhiyun #define UNGERMANN_MAC_ID 0x18 /* UNGERMANN-BASS hardware address */
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun control bits
152*4882a593Smuzhiyun */
153*4882a593Smuzhiyun #define ENA_TMT_OK 0x80
154*4882a593Smuzhiyun #define ENA_TMT_REC 0x20
155*4882a593Smuzhiyun #define ENA_COL 0x04
156*4882a593Smuzhiyun #define ENA_16_COL 0x02
157*4882a593Smuzhiyun #define ENA_TBUS_ERR 0x01
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun #define ENA_PKT_RDY 0x80
160*4882a593Smuzhiyun #define ENA_BUS_ERR 0x40
161*4882a593Smuzhiyun #define ENA_LEN_ERR 0x08
162*4882a593Smuzhiyun #define ENA_ALG_ERR 0x04
163*4882a593Smuzhiyun #define ENA_CRC_ERR 0x02
164*4882a593Smuzhiyun #define ENA_OVR_FLO 0x01
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* flags */
167*4882a593Smuzhiyun #define F_TMT_RDY 0x80 /* can accept new packet */
168*4882a593Smuzhiyun #define F_NET_BSY 0x40 /* carrier is detected */
169*4882a593Smuzhiyun #define F_TMT_OK 0x20 /* send packet successfully */
170*4882a593Smuzhiyun #define F_SRT_PKT 0x10 /* short packet error */
171*4882a593Smuzhiyun #define F_COL_ERR 0x04 /* collision error */
172*4882a593Smuzhiyun #define F_16_COL 0x02 /* 16 collision error */
173*4882a593Smuzhiyun #define F_TBUS_ERR 0x01 /* bus read error */
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun #define F_PKT_RDY 0x80 /* packet(s) in buffer */
176*4882a593Smuzhiyun #define F_BUS_ERR 0x40 /* bus read error */
177*4882a593Smuzhiyun #define F_LEN_ERR 0x08 /* short packet */
178*4882a593Smuzhiyun #define F_ALG_ERR 0x04 /* frame error */
179*4882a593Smuzhiyun #define F_CRC_ERR 0x02 /* CRC error */
180*4882a593Smuzhiyun #define F_OVR_FLO 0x01 /* overflow error */
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun #define F_BUF_EMP 0x40 /* receive buffer is empty */
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun #define F_SKP_PKT 0x05 /* drop packet in buffer */
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* default bitmaps */
187*4882a593Smuzhiyun #define D_TX_INTR ( ENA_TMT_OK )
188*4882a593Smuzhiyun #define D_RX_INTR ( ENA_PKT_RDY | ENA_LEN_ERR \
189*4882a593Smuzhiyun | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
190*4882a593Smuzhiyun #define TX_STAT_M ( F_TMT_RDY )
191*4882a593Smuzhiyun #define RX_STAT_M ( F_PKT_RDY | F_LEN_ERR \
192*4882a593Smuzhiyun | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* commands */
195*4882a593Smuzhiyun #define D_TX_MODE 0x06 /* no tests, detect carrier */
196*4882a593Smuzhiyun #define ID_MATCHED 0x02 /* (RX_MODE) */
197*4882a593Smuzhiyun #define RECV_ALL 0x03 /* (RX_MODE) */
198*4882a593Smuzhiyun #define CONFIG0_DFL 0x5a /* 16bit bus, 4K x 2 Tx queues */
199*4882a593Smuzhiyun #define CONFIG0_DFL_1 0x5e /* 16bit bus, 8K x 2 Tx queues */
200*4882a593Smuzhiyun #define CONFIG0_RST 0xda /* Data Link Controller off (CONFIG_0) */
201*4882a593Smuzhiyun #define CONFIG0_RST_1 0xde /* Data Link Controller off (CONFIG_0) */
202*4882a593Smuzhiyun #define BANK_0 0xa0 /* bank 0 (CONFIG_1) */
203*4882a593Smuzhiyun #define BANK_1 0xa4 /* bank 1 (CONFIG_1) */
204*4882a593Smuzhiyun #define BANK_2 0xa8 /* bank 2 (CONFIG_1) */
205*4882a593Smuzhiyun #define CHIP_OFF 0x80 /* contrl chip power off (CONFIG_1) */
206*4882a593Smuzhiyun #define DO_TX 0x80 /* do transmit packet */
207*4882a593Smuzhiyun #define SEND_PKT 0x81 /* send a packet */
208*4882a593Smuzhiyun #define AUTO_MODE 0x07 /* Auto skip packet on 16 col detected */
209*4882a593Smuzhiyun #define MANU_MODE 0x03 /* Stop and skip packet on 16 col */
210*4882a593Smuzhiyun #define TDK_AUTO_MODE 0x47 /* Auto skip packet on 16 col detected */
211*4882a593Smuzhiyun #define TDK_MANU_MODE 0x43 /* Stop and skip packet on 16 col */
212*4882a593Smuzhiyun #define INTR_OFF 0x0d /* LAN controller ignores interrupts */
213*4882a593Smuzhiyun #define INTR_ON 0x1d /* LAN controller will catch interrupts */
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun #define TX_TIMEOUT ((400*HZ)/1000)
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun #define BANK_0U 0x20 /* bank 0 (CONFIG_1) */
218*4882a593Smuzhiyun #define BANK_1U 0x24 /* bank 1 (CONFIG_1) */
219*4882a593Smuzhiyun #define BANK_2U 0x28 /* bank 2 (CONFIG_1) */
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun static const struct net_device_ops fjn_netdev_ops = {
222*4882a593Smuzhiyun .ndo_open = fjn_open,
223*4882a593Smuzhiyun .ndo_stop = fjn_close,
224*4882a593Smuzhiyun .ndo_start_xmit = fjn_start_xmit,
225*4882a593Smuzhiyun .ndo_tx_timeout = fjn_tx_timeout,
226*4882a593Smuzhiyun .ndo_set_config = fjn_config,
227*4882a593Smuzhiyun .ndo_set_rx_mode = set_rx_mode,
228*4882a593Smuzhiyun .ndo_set_mac_address = eth_mac_addr,
229*4882a593Smuzhiyun .ndo_validate_addr = eth_validate_addr,
230*4882a593Smuzhiyun };
231*4882a593Smuzhiyun
fmvj18x_probe(struct pcmcia_device * link)232*4882a593Smuzhiyun static int fmvj18x_probe(struct pcmcia_device *link)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun struct local_info *lp;
235*4882a593Smuzhiyun struct net_device *dev;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun dev_dbg(&link->dev, "fmvj18x_attach()\n");
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* Make up a FMVJ18x specific data structure */
240*4882a593Smuzhiyun dev = alloc_etherdev(sizeof(struct local_info));
241*4882a593Smuzhiyun if (!dev)
242*4882a593Smuzhiyun return -ENOMEM;
243*4882a593Smuzhiyun lp = netdev_priv(dev);
244*4882a593Smuzhiyun link->priv = dev;
245*4882a593Smuzhiyun lp->p_dev = link;
246*4882a593Smuzhiyun lp->base = NULL;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* The io structure describes IO port mapping */
249*4882a593Smuzhiyun link->resource[0]->end = 32;
250*4882a593Smuzhiyun link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* General socket configuration */
253*4882a593Smuzhiyun link->config_flags |= CONF_ENABLE_IRQ;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun dev->netdev_ops = &fjn_netdev_ops;
256*4882a593Smuzhiyun dev->watchdog_timeo = TX_TIMEOUT;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun dev->ethtool_ops = &netdev_ethtool_ops;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun return fmvj18x_config(link);
261*4882a593Smuzhiyun } /* fmvj18x_attach */
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /*====================================================================*/
264*4882a593Smuzhiyun
fmvj18x_detach(struct pcmcia_device * link)265*4882a593Smuzhiyun static void fmvj18x_detach(struct pcmcia_device *link)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun struct net_device *dev = link->priv;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun dev_dbg(&link->dev, "fmvj18x_detach\n");
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun unregister_netdev(dev);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun fmvj18x_release(link);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun free_netdev(dev);
276*4882a593Smuzhiyun } /* fmvj18x_detach */
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /*====================================================================*/
279*4882a593Smuzhiyun
mfc_try_io_port(struct pcmcia_device * link)280*4882a593Smuzhiyun static int mfc_try_io_port(struct pcmcia_device *link)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun int i, ret;
283*4882a593Smuzhiyun static const unsigned int serial_base[5] =
284*4882a593Smuzhiyun { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
287*4882a593Smuzhiyun link->resource[1]->start = serial_base[i];
288*4882a593Smuzhiyun link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
289*4882a593Smuzhiyun if (link->resource[1]->start == 0) {
290*4882a593Smuzhiyun link->resource[1]->end = 0;
291*4882a593Smuzhiyun pr_notice("out of resource for serial\n");
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun ret = pcmcia_request_io(link);
294*4882a593Smuzhiyun if (ret == 0)
295*4882a593Smuzhiyun return ret;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun return ret;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
ungermann_try_io_port(struct pcmcia_device * link)300*4882a593Smuzhiyun static int ungermann_try_io_port(struct pcmcia_device *link)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun int ret;
303*4882a593Smuzhiyun unsigned int ioaddr;
304*4882a593Smuzhiyun /*
305*4882a593Smuzhiyun Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
306*4882a593Smuzhiyun 0x380,0x3c0 only for ioport.
307*4882a593Smuzhiyun */
308*4882a593Smuzhiyun for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
309*4882a593Smuzhiyun link->resource[0]->start = ioaddr;
310*4882a593Smuzhiyun ret = pcmcia_request_io(link);
311*4882a593Smuzhiyun if (ret == 0) {
312*4882a593Smuzhiyun /* calculate ConfigIndex value */
313*4882a593Smuzhiyun link->config_index =
314*4882a593Smuzhiyun ((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
315*4882a593Smuzhiyun return ret;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun return ret; /* RequestIO failed */
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
fmvj18x_ioprobe(struct pcmcia_device * p_dev,void * priv_data)321*4882a593Smuzhiyun static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun return 0; /* strange, but that's what the code did already before... */
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
fmvj18x_config(struct pcmcia_device * link)326*4882a593Smuzhiyun static int fmvj18x_config(struct pcmcia_device *link)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun struct net_device *dev = link->priv;
329*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
330*4882a593Smuzhiyun int i, ret;
331*4882a593Smuzhiyun unsigned int ioaddr;
332*4882a593Smuzhiyun enum cardtype cardtype;
333*4882a593Smuzhiyun char *card_name = "unknown";
334*4882a593Smuzhiyun u8 *buf;
335*4882a593Smuzhiyun size_t len;
336*4882a593Smuzhiyun u_char buggybuf[32];
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun dev_dbg(&link->dev, "fmvj18x_config\n");
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun link->io_lines = 5;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
343*4882a593Smuzhiyun kfree(buf);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (len) {
346*4882a593Smuzhiyun /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
347*4882a593Smuzhiyun ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL);
348*4882a593Smuzhiyun if (ret != 0)
349*4882a593Smuzhiyun goto failed;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun switch (link->manf_id) {
352*4882a593Smuzhiyun case MANFID_TDK:
353*4882a593Smuzhiyun cardtype = TDK;
354*4882a593Smuzhiyun if (link->card_id == PRODID_TDK_GN3410 ||
355*4882a593Smuzhiyun link->card_id == PRODID_TDK_NP9610 ||
356*4882a593Smuzhiyun link->card_id == PRODID_TDK_MN3200) {
357*4882a593Smuzhiyun /* MultiFunction Card */
358*4882a593Smuzhiyun link->config_base = 0x800;
359*4882a593Smuzhiyun link->config_index = 0x47;
360*4882a593Smuzhiyun link->resource[1]->end = 8;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun break;
363*4882a593Smuzhiyun case MANFID_NEC:
364*4882a593Smuzhiyun cardtype = NEC; /* MultiFunction Card */
365*4882a593Smuzhiyun link->config_base = 0x800;
366*4882a593Smuzhiyun link->config_index = 0x47;
367*4882a593Smuzhiyun link->resource[1]->end = 8;
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun case MANFID_KME:
370*4882a593Smuzhiyun cardtype = KME; /* MultiFunction Card */
371*4882a593Smuzhiyun link->config_base = 0x800;
372*4882a593Smuzhiyun link->config_index = 0x47;
373*4882a593Smuzhiyun link->resource[1]->end = 8;
374*4882a593Smuzhiyun break;
375*4882a593Smuzhiyun case MANFID_CONTEC:
376*4882a593Smuzhiyun cardtype = CONTEC;
377*4882a593Smuzhiyun break;
378*4882a593Smuzhiyun case MANFID_FUJITSU:
379*4882a593Smuzhiyun if (link->config_base == 0x0fe0)
380*4882a593Smuzhiyun cardtype = MBH10302;
381*4882a593Smuzhiyun else if (link->card_id == PRODID_FUJITSU_MBH10302)
382*4882a593Smuzhiyun /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
383*4882a593Smuzhiyun but these are MBH10304 based card. */
384*4882a593Smuzhiyun cardtype = MBH10304;
385*4882a593Smuzhiyun else if (link->card_id == PRODID_FUJITSU_MBH10304)
386*4882a593Smuzhiyun cardtype = MBH10304;
387*4882a593Smuzhiyun else
388*4882a593Smuzhiyun cardtype = LA501;
389*4882a593Smuzhiyun break;
390*4882a593Smuzhiyun default:
391*4882a593Smuzhiyun cardtype = MBH10304;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun } else {
394*4882a593Smuzhiyun /* old type card */
395*4882a593Smuzhiyun switch (link->manf_id) {
396*4882a593Smuzhiyun case MANFID_FUJITSU:
397*4882a593Smuzhiyun if (link->card_id == PRODID_FUJITSU_MBH10304) {
398*4882a593Smuzhiyun cardtype = XXX10304; /* MBH10304 with buggy CIS */
399*4882a593Smuzhiyun link->config_index = 0x20;
400*4882a593Smuzhiyun } else {
401*4882a593Smuzhiyun cardtype = MBH10302; /* NextCom NC5310, etc. */
402*4882a593Smuzhiyun link->config_index = 1;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun break;
405*4882a593Smuzhiyun case MANFID_UNGERMANN:
406*4882a593Smuzhiyun cardtype = UNGERMANN;
407*4882a593Smuzhiyun break;
408*4882a593Smuzhiyun default:
409*4882a593Smuzhiyun cardtype = MBH10302;
410*4882a593Smuzhiyun link->config_index = 1;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if (link->resource[1]->end != 0) {
415*4882a593Smuzhiyun ret = mfc_try_io_port(link);
416*4882a593Smuzhiyun if (ret != 0) goto failed;
417*4882a593Smuzhiyun } else if (cardtype == UNGERMANN) {
418*4882a593Smuzhiyun ret = ungermann_try_io_port(link);
419*4882a593Smuzhiyun if (ret != 0) goto failed;
420*4882a593Smuzhiyun } else {
421*4882a593Smuzhiyun ret = pcmcia_request_io(link);
422*4882a593Smuzhiyun if (ret)
423*4882a593Smuzhiyun goto failed;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun ret = pcmcia_request_irq(link, fjn_interrupt);
426*4882a593Smuzhiyun if (ret)
427*4882a593Smuzhiyun goto failed;
428*4882a593Smuzhiyun ret = pcmcia_enable_device(link);
429*4882a593Smuzhiyun if (ret)
430*4882a593Smuzhiyun goto failed;
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun dev->irq = link->irq;
433*4882a593Smuzhiyun dev->base_addr = link->resource[0]->start;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun if (resource_size(link->resource[1]) != 0) {
436*4882a593Smuzhiyun ret = fmvj18x_setup_mfc(link);
437*4882a593Smuzhiyun if (ret != 0) goto failed;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun ioaddr = dev->base_addr;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /* Reset controller */
443*4882a593Smuzhiyun if (sram_config == 0)
444*4882a593Smuzhiyun outb(CONFIG0_RST, ioaddr + CONFIG_0);
445*4882a593Smuzhiyun else
446*4882a593Smuzhiyun outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* Power On chip and select bank 0 */
449*4882a593Smuzhiyun if (cardtype == MBH10302)
450*4882a593Smuzhiyun outb(BANK_0, ioaddr + CONFIG_1);
451*4882a593Smuzhiyun else
452*4882a593Smuzhiyun outb(BANK_0U, ioaddr + CONFIG_1);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* Set hardware address */
455*4882a593Smuzhiyun switch (cardtype) {
456*4882a593Smuzhiyun case MBH10304:
457*4882a593Smuzhiyun case TDK:
458*4882a593Smuzhiyun case LA501:
459*4882a593Smuzhiyun case CONTEC:
460*4882a593Smuzhiyun case NEC:
461*4882a593Smuzhiyun case KME:
462*4882a593Smuzhiyun if (cardtype == MBH10304) {
463*4882a593Smuzhiyun card_name = "FMV-J182";
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
466*4882a593Smuzhiyun if (len < 11) {
467*4882a593Smuzhiyun kfree(buf);
468*4882a593Smuzhiyun goto failed;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun /* Read MACID from CIS */
471*4882a593Smuzhiyun for (i = 0; i < 6; i++)
472*4882a593Smuzhiyun dev->dev_addr[i] = buf[i + 5];
473*4882a593Smuzhiyun kfree(buf);
474*4882a593Smuzhiyun } else {
475*4882a593Smuzhiyun if (pcmcia_get_mac_from_cis(link, dev))
476*4882a593Smuzhiyun goto failed;
477*4882a593Smuzhiyun if( cardtype == TDK ) {
478*4882a593Smuzhiyun card_name = "TDK LAK-CD021";
479*4882a593Smuzhiyun } else if( cardtype == LA501 ) {
480*4882a593Smuzhiyun card_name = "LA501";
481*4882a593Smuzhiyun } else if( cardtype == NEC ) {
482*4882a593Smuzhiyun card_name = "PK-UG-J001";
483*4882a593Smuzhiyun } else if( cardtype == KME ) {
484*4882a593Smuzhiyun card_name = "Panasonic";
485*4882a593Smuzhiyun } else {
486*4882a593Smuzhiyun card_name = "C-NET(PC)C";
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun break;
490*4882a593Smuzhiyun case UNGERMANN:
491*4882a593Smuzhiyun /* Read MACID from register */
492*4882a593Smuzhiyun for (i = 0; i < 6; i++)
493*4882a593Smuzhiyun dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i);
494*4882a593Smuzhiyun card_name = "Access/CARD";
495*4882a593Smuzhiyun break;
496*4882a593Smuzhiyun case XXX10304:
497*4882a593Smuzhiyun /* Read MACID from Buggy CIS */
498*4882a593Smuzhiyun if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
499*4882a593Smuzhiyun pr_notice("unable to read hardware net address\n");
500*4882a593Smuzhiyun goto failed;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun for (i = 0 ; i < 6; i++) {
503*4882a593Smuzhiyun dev->dev_addr[i] = buggybuf[i];
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun card_name = "FMV-J182";
506*4882a593Smuzhiyun break;
507*4882a593Smuzhiyun case MBH10302:
508*4882a593Smuzhiyun default:
509*4882a593Smuzhiyun /* Read MACID from register */
510*4882a593Smuzhiyun for (i = 0; i < 6; i++)
511*4882a593Smuzhiyun dev->dev_addr[i] = inb(ioaddr + MAC_ID + i);
512*4882a593Smuzhiyun card_name = "FMV-J181";
513*4882a593Smuzhiyun break;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun lp->cardtype = cardtype;
517*4882a593Smuzhiyun SET_NETDEV_DEV(dev, &link->dev);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun if (register_netdev(dev) != 0) {
520*4882a593Smuzhiyun pr_notice("register_netdev() failed\n");
521*4882a593Smuzhiyun goto failed;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* print current configuration */
525*4882a593Smuzhiyun netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
526*4882a593Smuzhiyun card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
527*4882a593Smuzhiyun dev->base_addr, dev->irq, dev->dev_addr);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun return 0;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun failed:
532*4882a593Smuzhiyun fmvj18x_release(link);
533*4882a593Smuzhiyun return -ENODEV;
534*4882a593Smuzhiyun } /* fmvj18x_config */
535*4882a593Smuzhiyun /*====================================================================*/
536*4882a593Smuzhiyun
fmvj18x_get_hwinfo(struct pcmcia_device * link,u_char * node_id)537*4882a593Smuzhiyun static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun u_char __iomem *base;
540*4882a593Smuzhiyun int i, j;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun /* Allocate a small memory window */
543*4882a593Smuzhiyun link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
544*4882a593Smuzhiyun link->resource[2]->start = 0; link->resource[2]->end = 0;
545*4882a593Smuzhiyun i = pcmcia_request_window(link, link->resource[2], 0);
546*4882a593Smuzhiyun if (i != 0)
547*4882a593Smuzhiyun return -1;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
550*4882a593Smuzhiyun if (!base) {
551*4882a593Smuzhiyun pcmcia_release_window(link, link->resource[2]);
552*4882a593Smuzhiyun return -1;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun pcmcia_map_mem_page(link, link->resource[2], 0);
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun /*
558*4882a593Smuzhiyun * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
559*4882a593Smuzhiyun * 22 0d xx xx xx 04 06 yy yy yy yy yy yy ff
560*4882a593Smuzhiyun * 'xx' is garbage.
561*4882a593Smuzhiyun * 'yy' is MAC address.
562*4882a593Smuzhiyun */
563*4882a593Smuzhiyun for (i = 0; i < 0x200; i++) {
564*4882a593Smuzhiyun if (readb(base+i*2) == 0x22) {
565*4882a593Smuzhiyun if (readb(base+(i-1)*2) == 0xff &&
566*4882a593Smuzhiyun readb(base+(i+5)*2) == 0x04 &&
567*4882a593Smuzhiyun readb(base+(i+6)*2) == 0x06 &&
568*4882a593Smuzhiyun readb(base+(i+13)*2) == 0xff)
569*4882a593Smuzhiyun break;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun if (i != 0x200) {
574*4882a593Smuzhiyun for (j = 0 ; j < 6; j++,i++) {
575*4882a593Smuzhiyun node_id[j] = readb(base+(i+7)*2);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun iounmap(base);
580*4882a593Smuzhiyun j = pcmcia_release_window(link, link->resource[2]);
581*4882a593Smuzhiyun return (i != 0x200) ? 0 : -1;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun } /* fmvj18x_get_hwinfo */
584*4882a593Smuzhiyun /*====================================================================*/
585*4882a593Smuzhiyun
fmvj18x_setup_mfc(struct pcmcia_device * link)586*4882a593Smuzhiyun static int fmvj18x_setup_mfc(struct pcmcia_device *link)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun int i;
589*4882a593Smuzhiyun struct net_device *dev = link->priv;
590*4882a593Smuzhiyun unsigned int ioaddr;
591*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /* Allocate a small memory window */
594*4882a593Smuzhiyun link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
595*4882a593Smuzhiyun link->resource[3]->start = link->resource[3]->end = 0;
596*4882a593Smuzhiyun i = pcmcia_request_window(link, link->resource[3], 0);
597*4882a593Smuzhiyun if (i != 0)
598*4882a593Smuzhiyun return -1;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun lp->base = ioremap(link->resource[3]->start,
601*4882a593Smuzhiyun resource_size(link->resource[3]));
602*4882a593Smuzhiyun if (lp->base == NULL) {
603*4882a593Smuzhiyun netdev_notice(dev, "ioremap failed\n");
604*4882a593Smuzhiyun return -1;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun i = pcmcia_map_mem_page(link, link->resource[3], 0);
608*4882a593Smuzhiyun if (i != 0) {
609*4882a593Smuzhiyun iounmap(lp->base);
610*4882a593Smuzhiyun lp->base = NULL;
611*4882a593Smuzhiyun return -1;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun ioaddr = dev->base_addr;
615*4882a593Smuzhiyun writeb(0x47, lp->base+0x800); /* Config Option Register of LAN */
616*4882a593Smuzhiyun writeb(0x0, lp->base+0x802); /* Config and Status Register */
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun writeb(ioaddr & 0xff, lp->base+0x80a); /* I/O Base(Low) of LAN */
619*4882a593Smuzhiyun writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */
622*4882a593Smuzhiyun writeb(0x8, lp->base+0x822); /* Config and Status Register */
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun return 0;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun /*====================================================================*/
628*4882a593Smuzhiyun
fmvj18x_release(struct pcmcia_device * link)629*4882a593Smuzhiyun static void fmvj18x_release(struct pcmcia_device *link)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun struct net_device *dev = link->priv;
633*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
634*4882a593Smuzhiyun u_char __iomem *tmp;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun dev_dbg(&link->dev, "fmvj18x_release\n");
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun if (lp->base != NULL) {
639*4882a593Smuzhiyun tmp = lp->base;
640*4882a593Smuzhiyun lp->base = NULL; /* set NULL before iounmap */
641*4882a593Smuzhiyun iounmap(tmp);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun pcmcia_disable_device(link);
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
fmvj18x_suspend(struct pcmcia_device * link)648*4882a593Smuzhiyun static int fmvj18x_suspend(struct pcmcia_device *link)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun struct net_device *dev = link->priv;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun if (link->open)
653*4882a593Smuzhiyun netif_device_detach(dev);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun return 0;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun
fmvj18x_resume(struct pcmcia_device * link)658*4882a593Smuzhiyun static int fmvj18x_resume(struct pcmcia_device *link)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun struct net_device *dev = link->priv;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun if (link->open) {
663*4882a593Smuzhiyun fjn_reset(dev);
664*4882a593Smuzhiyun netif_device_attach(dev);
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun return 0;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun /*====================================================================*/
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun static const struct pcmcia_device_id fmvj18x_ids[] = {
673*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
674*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
675*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
676*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
677*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
678*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
679*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
680*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
681*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0 ", 0x8cef4d3a, 0x075fc7b6),
682*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0 ", 0x8cef4d3a, 0xbccf43e6),
683*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
684*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
685*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
686*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
687*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304 ES", 0x2599f454),
688*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
689*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
690*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
691*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
692*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
693*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
694*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
695*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
696*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05),
697*4882a593Smuzhiyun PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
698*4882a593Smuzhiyun PCMCIA_DEVICE_NULL,
699*4882a593Smuzhiyun };
700*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun static struct pcmcia_driver fmvj18x_cs_driver = {
703*4882a593Smuzhiyun .owner = THIS_MODULE,
704*4882a593Smuzhiyun .name = "fmvj18x_cs",
705*4882a593Smuzhiyun .probe = fmvj18x_probe,
706*4882a593Smuzhiyun .remove = fmvj18x_detach,
707*4882a593Smuzhiyun .id_table = fmvj18x_ids,
708*4882a593Smuzhiyun .suspend = fmvj18x_suspend,
709*4882a593Smuzhiyun .resume = fmvj18x_resume,
710*4882a593Smuzhiyun };
711*4882a593Smuzhiyun module_pcmcia_driver(fmvj18x_cs_driver);
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /*====================================================================*/
714*4882a593Smuzhiyun
fjn_interrupt(int dummy,void * dev_id)715*4882a593Smuzhiyun static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun struct net_device *dev = dev_id;
718*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
719*4882a593Smuzhiyun unsigned int ioaddr;
720*4882a593Smuzhiyun unsigned short tx_stat, rx_stat;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun ioaddr = dev->base_addr;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun /* avoid multiple interrupts */
725*4882a593Smuzhiyun outw(0x0000, ioaddr + TX_INTR);
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun /* wait for a while */
728*4882a593Smuzhiyun udelay(1);
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun /* get status */
731*4882a593Smuzhiyun tx_stat = inb(ioaddr + TX_STATUS);
732*4882a593Smuzhiyun rx_stat = inb(ioaddr + RX_STATUS);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun /* clear status */
735*4882a593Smuzhiyun outb(tx_stat, ioaddr + TX_STATUS);
736*4882a593Smuzhiyun outb(rx_stat, ioaddr + RX_STATUS);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat);
739*4882a593Smuzhiyun pr_debug(" tx_status %02x.\n", tx_stat);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
742*4882a593Smuzhiyun /* there is packet(s) in rx buffer */
743*4882a593Smuzhiyun fjn_rx(dev);
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun if (tx_stat & F_TMT_RDY) {
746*4882a593Smuzhiyun dev->stats.tx_packets += lp->sent ;
747*4882a593Smuzhiyun lp->sent = 0 ;
748*4882a593Smuzhiyun if (lp->tx_queue) {
749*4882a593Smuzhiyun outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
750*4882a593Smuzhiyun lp->sent = lp->tx_queue ;
751*4882a593Smuzhiyun lp->tx_queue = 0;
752*4882a593Smuzhiyun lp->tx_queue_len = 0;
753*4882a593Smuzhiyun netif_trans_update(dev);
754*4882a593Smuzhiyun } else {
755*4882a593Smuzhiyun lp->tx_started = 0;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun netif_wake_queue(dev);
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun pr_debug("%s: exiting interrupt,\n", dev->name);
760*4882a593Smuzhiyun pr_debug(" tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun outb(D_TX_INTR, ioaddr + TX_INTR);
763*4882a593Smuzhiyun outb(D_RX_INTR, ioaddr + RX_INTR);
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun if (lp->base != NULL) {
766*4882a593Smuzhiyun /* Ack interrupt for multifunction card */
767*4882a593Smuzhiyun writeb(0x01, lp->base+0x802);
768*4882a593Smuzhiyun writeb(0x09, lp->base+0x822);
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun return IRQ_HANDLED;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun } /* fjn_interrupt */
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun /*====================================================================*/
776*4882a593Smuzhiyun
fjn_tx_timeout(struct net_device * dev,unsigned int txqueue)777*4882a593Smuzhiyun static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
780*4882a593Smuzhiyun unsigned int ioaddr = dev->base_addr;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun netdev_notice(dev, "transmit timed out with status %04x, %s?\n",
783*4882a593Smuzhiyun htons(inw(ioaddr + TX_STATUS)),
784*4882a593Smuzhiyun inb(ioaddr + TX_STATUS) & F_TMT_RDY
785*4882a593Smuzhiyun ? "IRQ conflict" : "network cable problem");
786*4882a593Smuzhiyun netdev_notice(dev, "timeout registers: %04x %04x %04x "
787*4882a593Smuzhiyun "%04x %04x %04x %04x %04x.\n",
788*4882a593Smuzhiyun htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)),
789*4882a593Smuzhiyun htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)),
790*4882a593Smuzhiyun htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)),
791*4882a593Smuzhiyun htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14)));
792*4882a593Smuzhiyun dev->stats.tx_errors++;
793*4882a593Smuzhiyun /* ToDo: We should try to restart the adaptor... */
794*4882a593Smuzhiyun local_irq_disable();
795*4882a593Smuzhiyun fjn_reset(dev);
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun lp->tx_started = 0;
798*4882a593Smuzhiyun lp->tx_queue = 0;
799*4882a593Smuzhiyun lp->tx_queue_len = 0;
800*4882a593Smuzhiyun lp->sent = 0;
801*4882a593Smuzhiyun lp->open_time = jiffies;
802*4882a593Smuzhiyun local_irq_enable();
803*4882a593Smuzhiyun netif_wake_queue(dev);
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
fjn_start_xmit(struct sk_buff * skb,struct net_device * dev)806*4882a593Smuzhiyun static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
807*4882a593Smuzhiyun struct net_device *dev)
808*4882a593Smuzhiyun {
809*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
810*4882a593Smuzhiyun unsigned int ioaddr = dev->base_addr;
811*4882a593Smuzhiyun short length = skb->len;
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun if (length < ETH_ZLEN)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun if (skb_padto(skb, ETH_ZLEN))
816*4882a593Smuzhiyun return NETDEV_TX_OK;
817*4882a593Smuzhiyun length = ETH_ZLEN;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun netif_stop_queue(dev);
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun unsigned char *buf = skb->data;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun if (length > ETH_FRAME_LEN) {
826*4882a593Smuzhiyun netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n",
827*4882a593Smuzhiyun length);
828*4882a593Smuzhiyun return NETDEV_TX_BUSY;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun netdev_dbg(dev, "Transmitting a packet of length %lu\n",
832*4882a593Smuzhiyun (unsigned long)skb->len);
833*4882a593Smuzhiyun dev->stats.tx_bytes += skb->len;
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun /* Disable both interrupts. */
836*4882a593Smuzhiyun outw(0x0000, ioaddr + TX_INTR);
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun /* wait for a while */
839*4882a593Smuzhiyun udelay(1);
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun outw(length, ioaddr + DATAPORT);
842*4882a593Smuzhiyun outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun lp->tx_queue++;
845*4882a593Smuzhiyun lp->tx_queue_len += ((length+3) & ~1);
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun if (lp->tx_started == 0) {
848*4882a593Smuzhiyun /* If the Tx is idle, always trigger a transmit. */
849*4882a593Smuzhiyun outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
850*4882a593Smuzhiyun lp->sent = lp->tx_queue ;
851*4882a593Smuzhiyun lp->tx_queue = 0;
852*4882a593Smuzhiyun lp->tx_queue_len = 0;
853*4882a593Smuzhiyun lp->tx_started = 1;
854*4882a593Smuzhiyun netif_start_queue(dev);
855*4882a593Smuzhiyun } else {
856*4882a593Smuzhiyun if( sram_config == 0 ) {
857*4882a593Smuzhiyun if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
858*4882a593Smuzhiyun /* Yes, there is room for one more packet. */
859*4882a593Smuzhiyun netif_start_queue(dev);
860*4882a593Smuzhiyun } else {
861*4882a593Smuzhiyun if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) &&
862*4882a593Smuzhiyun lp->tx_queue < 127 )
863*4882a593Smuzhiyun /* Yes, there is room for one more packet. */
864*4882a593Smuzhiyun netif_start_queue(dev);
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun /* Re-enable interrupts */
869*4882a593Smuzhiyun outb(D_TX_INTR, ioaddr + TX_INTR);
870*4882a593Smuzhiyun outb(D_RX_INTR, ioaddr + RX_INTR);
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun dev_kfree_skb (skb);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun return NETDEV_TX_OK;
875*4882a593Smuzhiyun } /* fjn_start_xmit */
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun /*====================================================================*/
878*4882a593Smuzhiyun
fjn_reset(struct net_device * dev)879*4882a593Smuzhiyun static void fjn_reset(struct net_device *dev)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
882*4882a593Smuzhiyun unsigned int ioaddr = dev->base_addr;
883*4882a593Smuzhiyun int i;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun netdev_dbg(dev, "fjn_reset() called\n");
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun /* Reset controller */
888*4882a593Smuzhiyun if( sram_config == 0 )
889*4882a593Smuzhiyun outb(CONFIG0_RST, ioaddr + CONFIG_0);
890*4882a593Smuzhiyun else
891*4882a593Smuzhiyun outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun /* Power On chip and select bank 0 */
894*4882a593Smuzhiyun if (lp->cardtype == MBH10302)
895*4882a593Smuzhiyun outb(BANK_0, ioaddr + CONFIG_1);
896*4882a593Smuzhiyun else
897*4882a593Smuzhiyun outb(BANK_0U, ioaddr + CONFIG_1);
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun /* Set Tx modes */
900*4882a593Smuzhiyun outb(D_TX_MODE, ioaddr + TX_MODE);
901*4882a593Smuzhiyun /* set Rx modes */
902*4882a593Smuzhiyun outb(ID_MATCHED, ioaddr + RX_MODE);
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun /* Set hardware address */
905*4882a593Smuzhiyun for (i = 0; i < 6; i++)
906*4882a593Smuzhiyun outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun /* (re)initialize the multicast table */
909*4882a593Smuzhiyun set_rx_mode(dev);
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun /* Switch to bank 2 (runtime mode) */
912*4882a593Smuzhiyun if (lp->cardtype == MBH10302)
913*4882a593Smuzhiyun outb(BANK_2, ioaddr + CONFIG_1);
914*4882a593Smuzhiyun else
915*4882a593Smuzhiyun outb(BANK_2U, ioaddr + CONFIG_1);
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun /* set 16col ctrl bits */
918*4882a593Smuzhiyun if( lp->cardtype == TDK || lp->cardtype == CONTEC)
919*4882a593Smuzhiyun outb(TDK_AUTO_MODE, ioaddr + COL_CTRL);
920*4882a593Smuzhiyun else
921*4882a593Smuzhiyun outb(AUTO_MODE, ioaddr + COL_CTRL);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun /* clear Reserved Regs */
924*4882a593Smuzhiyun outb(0x00, ioaddr + BMPR12);
925*4882a593Smuzhiyun outb(0x00, ioaddr + BMPR13);
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun /* reset Skip packet reg. */
928*4882a593Smuzhiyun outb(0x01, ioaddr + RX_SKIP);
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun /* Enable Tx and Rx */
931*4882a593Smuzhiyun if( sram_config == 0 )
932*4882a593Smuzhiyun outb(CONFIG0_DFL, ioaddr + CONFIG_0);
933*4882a593Smuzhiyun else
934*4882a593Smuzhiyun outb(CONFIG0_DFL_1, ioaddr + CONFIG_0);
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun /* Init receive pointer ? */
937*4882a593Smuzhiyun inw(ioaddr + DATAPORT);
938*4882a593Smuzhiyun inw(ioaddr + DATAPORT);
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun /* Clear all status */
941*4882a593Smuzhiyun outb(0xff, ioaddr + TX_STATUS);
942*4882a593Smuzhiyun outb(0xff, ioaddr + RX_STATUS);
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun if (lp->cardtype == MBH10302)
945*4882a593Smuzhiyun outb(INTR_OFF, ioaddr + LAN_CTRL);
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun /* Turn on Rx interrupts */
948*4882a593Smuzhiyun outb(D_TX_INTR, ioaddr + TX_INTR);
949*4882a593Smuzhiyun outb(D_RX_INTR, ioaddr + RX_INTR);
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun /* Turn on interrupts from LAN card controller */
952*4882a593Smuzhiyun if (lp->cardtype == MBH10302)
953*4882a593Smuzhiyun outb(INTR_ON, ioaddr + LAN_CTRL);
954*4882a593Smuzhiyun } /* fjn_reset */
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun /*====================================================================*/
957*4882a593Smuzhiyun
fjn_rx(struct net_device * dev)958*4882a593Smuzhiyun static void fjn_rx(struct net_device *dev)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun unsigned int ioaddr = dev->base_addr;
961*4882a593Smuzhiyun int boguscount = 10; /* 5 -> 10: by agy 19940922 */
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun pr_debug("%s: in rx_packet(), rx_status %02x.\n",
964*4882a593Smuzhiyun dev->name, inb(ioaddr + RX_STATUS));
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
967*4882a593Smuzhiyun u_short status = inw(ioaddr + DATAPORT);
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n",
970*4882a593Smuzhiyun inb(ioaddr + RX_MODE), status);
971*4882a593Smuzhiyun #ifndef final_version
972*4882a593Smuzhiyun if (status == 0) {
973*4882a593Smuzhiyun outb(F_SKP_PKT, ioaddr + RX_SKIP);
974*4882a593Smuzhiyun break;
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun #endif
977*4882a593Smuzhiyun if ((status & 0xF0) != 0x20) { /* There was an error. */
978*4882a593Smuzhiyun dev->stats.rx_errors++;
979*4882a593Smuzhiyun if (status & F_LEN_ERR) dev->stats.rx_length_errors++;
980*4882a593Smuzhiyun if (status & F_ALG_ERR) dev->stats.rx_frame_errors++;
981*4882a593Smuzhiyun if (status & F_CRC_ERR) dev->stats.rx_crc_errors++;
982*4882a593Smuzhiyun if (status & F_OVR_FLO) dev->stats.rx_over_errors++;
983*4882a593Smuzhiyun } else {
984*4882a593Smuzhiyun u_short pkt_len = inw(ioaddr + DATAPORT);
985*4882a593Smuzhiyun /* Malloc up new buffer. */
986*4882a593Smuzhiyun struct sk_buff *skb;
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun if (pkt_len > 1550) {
989*4882a593Smuzhiyun netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n",
990*4882a593Smuzhiyun pkt_len);
991*4882a593Smuzhiyun outb(F_SKP_PKT, ioaddr + RX_SKIP);
992*4882a593Smuzhiyun dev->stats.rx_errors++;
993*4882a593Smuzhiyun break;
994*4882a593Smuzhiyun }
995*4882a593Smuzhiyun skb = netdev_alloc_skb(dev, pkt_len + 2);
996*4882a593Smuzhiyun if (skb == NULL) {
997*4882a593Smuzhiyun outb(F_SKP_PKT, ioaddr + RX_SKIP);
998*4882a593Smuzhiyun dev->stats.rx_dropped++;
999*4882a593Smuzhiyun break;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun skb_reserve(skb, 2);
1003*4882a593Smuzhiyun insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
1004*4882a593Smuzhiyun (pkt_len + 1) >> 1);
1005*4882a593Smuzhiyun skb->protocol = eth_type_trans(skb, dev);
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun {
1008*4882a593Smuzhiyun int i;
1009*4882a593Smuzhiyun pr_debug("%s: Rxed packet of length %d: ",
1010*4882a593Smuzhiyun dev->name, pkt_len);
1011*4882a593Smuzhiyun for (i = 0; i < 14; i++)
1012*4882a593Smuzhiyun pr_debug(" %02x", skb->data[i]);
1013*4882a593Smuzhiyun pr_debug(".\n");
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun netif_rx(skb);
1017*4882a593Smuzhiyun dev->stats.rx_packets++;
1018*4882a593Smuzhiyun dev->stats.rx_bytes += pkt_len;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun if (--boguscount <= 0)
1021*4882a593Smuzhiyun break;
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun /* If any worth-while packets have been received, dev_rint()
1025*4882a593Smuzhiyun has done a netif_wake_queue() for us and will work on them
1026*4882a593Smuzhiyun when we get to the bottom-half routine. */
1027*4882a593Smuzhiyun /*
1028*4882a593Smuzhiyun if (lp->cardtype != TDK) {
1029*4882a593Smuzhiyun int i;
1030*4882a593Smuzhiyun for (i = 0; i < 20; i++) {
1031*4882a593Smuzhiyun if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
1032*4882a593Smuzhiyun break;
1033*4882a593Smuzhiyun (void)inw(ioaddr + DATAPORT); /+ dummy status read +/
1034*4882a593Smuzhiyun outb(F_SKP_PKT, ioaddr + RX_SKIP);
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun if (i > 0)
1038*4882a593Smuzhiyun pr_debug("%s: Exint Rx packet with mode %02x after "
1039*4882a593Smuzhiyun "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun */
1042*4882a593Smuzhiyun } /* fjn_rx */
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun /*====================================================================*/
1045*4882a593Smuzhiyun
netdev_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)1046*4882a593Smuzhiyun static void netdev_get_drvinfo(struct net_device *dev,
1047*4882a593Smuzhiyun struct ethtool_drvinfo *info)
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
1050*4882a593Smuzhiyun strlcpy(info->version, DRV_VERSION, sizeof(info->version));
1051*4882a593Smuzhiyun snprintf(info->bus_info, sizeof(info->bus_info),
1052*4882a593Smuzhiyun "PCMCIA 0x%lx", dev->base_addr);
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun static const struct ethtool_ops netdev_ethtool_ops = {
1056*4882a593Smuzhiyun .get_drvinfo = netdev_get_drvinfo,
1057*4882a593Smuzhiyun };
1058*4882a593Smuzhiyun
fjn_config(struct net_device * dev,struct ifmap * map)1059*4882a593Smuzhiyun static int fjn_config(struct net_device *dev, struct ifmap *map){
1060*4882a593Smuzhiyun return 0;
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun
fjn_open(struct net_device * dev)1063*4882a593Smuzhiyun static int fjn_open(struct net_device *dev)
1064*4882a593Smuzhiyun {
1065*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
1066*4882a593Smuzhiyun struct pcmcia_device *link = lp->p_dev;
1067*4882a593Smuzhiyun
1068*4882a593Smuzhiyun pr_debug("fjn_open('%s').\n", dev->name);
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun if (!pcmcia_dev_present(link))
1071*4882a593Smuzhiyun return -ENODEV;
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun link->open++;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun fjn_reset(dev);
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun lp->tx_started = 0;
1078*4882a593Smuzhiyun lp->tx_queue = 0;
1079*4882a593Smuzhiyun lp->tx_queue_len = 0;
1080*4882a593Smuzhiyun lp->open_time = jiffies;
1081*4882a593Smuzhiyun netif_start_queue(dev);
1082*4882a593Smuzhiyun
1083*4882a593Smuzhiyun return 0;
1084*4882a593Smuzhiyun } /* fjn_open */
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun /*====================================================================*/
1087*4882a593Smuzhiyun
fjn_close(struct net_device * dev)1088*4882a593Smuzhiyun static int fjn_close(struct net_device *dev)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun struct local_info *lp = netdev_priv(dev);
1091*4882a593Smuzhiyun struct pcmcia_device *link = lp->p_dev;
1092*4882a593Smuzhiyun unsigned int ioaddr = dev->base_addr;
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun pr_debug("fjn_close('%s').\n", dev->name);
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun lp->open_time = 0;
1097*4882a593Smuzhiyun netif_stop_queue(dev);
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun /* Set configuration register 0 to disable Tx and Rx. */
1100*4882a593Smuzhiyun if( sram_config == 0 )
1101*4882a593Smuzhiyun outb(CONFIG0_RST ,ioaddr + CONFIG_0);
1102*4882a593Smuzhiyun else
1103*4882a593Smuzhiyun outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun /* Update the statistics -- ToDo. */
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun /* Power-down the chip. Green, green, green! */
1108*4882a593Smuzhiyun outb(CHIP_OFF ,ioaddr + CONFIG_1);
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun /* Set the ethernet adaptor disable IRQ */
1111*4882a593Smuzhiyun if (lp->cardtype == MBH10302)
1112*4882a593Smuzhiyun outb(INTR_OFF, ioaddr + LAN_CTRL);
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun link->open--;
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun return 0;
1117*4882a593Smuzhiyun } /* fjn_close */
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun /*====================================================================*/
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun /*
1122*4882a593Smuzhiyun Set the multicast/promiscuous mode for this adaptor.
1123*4882a593Smuzhiyun */
1124*4882a593Smuzhiyun
set_rx_mode(struct net_device * dev)1125*4882a593Smuzhiyun static void set_rx_mode(struct net_device *dev)
1126*4882a593Smuzhiyun {
1127*4882a593Smuzhiyun unsigned int ioaddr = dev->base_addr;
1128*4882a593Smuzhiyun u_char mc_filter[8]; /* Multicast hash filter */
1129*4882a593Smuzhiyun u_long flags;
1130*4882a593Smuzhiyun int i;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun int saved_bank;
1133*4882a593Smuzhiyun int saved_config_0 = inb(ioaddr + CONFIG_0);
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun local_irq_save(flags);
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun /* Disable Tx and Rx */
1138*4882a593Smuzhiyun if (sram_config == 0)
1139*4882a593Smuzhiyun outb(CONFIG0_RST, ioaddr + CONFIG_0);
1140*4882a593Smuzhiyun else
1141*4882a593Smuzhiyun outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun if (dev->flags & IFF_PROMISC) {
1144*4882a593Smuzhiyun memset(mc_filter, 0xff, sizeof(mc_filter));
1145*4882a593Smuzhiyun outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
1146*4882a593Smuzhiyun } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
1147*4882a593Smuzhiyun (dev->flags & IFF_ALLMULTI)) {
1148*4882a593Smuzhiyun /* Too many to filter perfectly -- accept all multicasts. */
1149*4882a593Smuzhiyun memset(mc_filter, 0xff, sizeof(mc_filter));
1150*4882a593Smuzhiyun outb(2, ioaddr + RX_MODE); /* Use normal mode. */
1151*4882a593Smuzhiyun } else if (netdev_mc_empty(dev)) {
1152*4882a593Smuzhiyun memset(mc_filter, 0x00, sizeof(mc_filter));
1153*4882a593Smuzhiyun outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */
1154*4882a593Smuzhiyun } else {
1155*4882a593Smuzhiyun struct netdev_hw_addr *ha;
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun memset(mc_filter, 0, sizeof(mc_filter));
1158*4882a593Smuzhiyun netdev_for_each_mc_addr(ha, dev) {
1159*4882a593Smuzhiyun unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
1160*4882a593Smuzhiyun mc_filter[bit >> 3] |= (1 << (bit & 7));
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun outb(2, ioaddr + RX_MODE); /* Use normal mode. */
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun /* Switch to bank 1 and set the multicast table. */
1166*4882a593Smuzhiyun saved_bank = inb(ioaddr + CONFIG_1);
1167*4882a593Smuzhiyun outb(0xe4, ioaddr + CONFIG_1);
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun for (i = 0; i < 8; i++)
1170*4882a593Smuzhiyun outb(mc_filter[i], ioaddr + MAR_ADR + i);
1171*4882a593Smuzhiyun outb(saved_bank, ioaddr + CONFIG_1);
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun outb(saved_config_0, ioaddr + CONFIG_0);
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun local_irq_restore(flags);
1176*4882a593Smuzhiyun }
1177