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