1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#ifdef __IN_PCMCIA_PACKAGE__
33#include <pcmcia/k_compat.h>
34#endif
35#include <linux/init.h>
36#include <linux/kernel.h>
37#include <linux/module.h>
38#include <linux/ptrace.h>
39#include <linux/slab.h>
40#include <linux/string.h>
41#include <linux/netdevice.h>
42#include <linux/moduleparam.h>
43#include <linux/device.h>
44
45#include <pcmcia/cs_types.h>
46#include <pcmcia/cs.h>
47#include <pcmcia/cistpl.h>
48#include <pcmcia/cisreg.h>
49#include <pcmcia/ds.h>
50#include <pcmcia/ciscode.h>
51
52#include <asm/io.h>
53#include <asm/system.h>
54#include <linux/wireless.h>
55
56#include "atmel.h"
57
58
59
60
61
62
63
64
65
66#ifdef PCMCIA_DEBUG
67static int pc_debug = PCMCIA_DEBUG;
68module_param(pc_debug, int, 0);
69static char *version = "$Revision: 1.2 $";
70#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
71#else
72#define DEBUG(n, args...)
73#endif
74
75
76
77MODULE_AUTHOR("Simon Kelley");
78MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
79MODULE_LICENSE("GPL");
80MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
81
82
83
84
85
86
87
88
89
90
91
92
93static int atmel_config(struct pcmcia_device *link);
94static void atmel_release(struct pcmcia_device *link);
95
96
97
98
99
100
101
102static void atmel_detach(struct pcmcia_device *p_dev);
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137typedef struct local_info_t {
138 dev_node_t node;
139 struct net_device *eth_dev;
140} local_info_t;
141
142
143
144
145
146
147
148
149
150
151
152
153
154static int atmel_probe(struct pcmcia_device *p_dev)
155{
156 local_info_t *local;
157
158 DEBUG(0, "atmel_attach()\n");
159
160
161 p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
162 p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
163 p_dev->irq.Handler = NULL;
164
165
166
167
168
169
170
171
172 p_dev->conf.Attributes = 0;
173 p_dev->conf.IntType = INT_MEMORY_AND_IO;
174
175
176 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
177 if (!local) {
178 printk(KERN_ERR "atmel_cs: no memory for new device\n");
179 return -ENOMEM;
180 }
181 p_dev->priv = local;
182
183 return atmel_config(p_dev);
184}
185
186
187
188
189
190
191
192
193
194
195static void atmel_detach(struct pcmcia_device *link)
196{
197 DEBUG(0, "atmel_detach(0x%p)\n", link);
198
199 atmel_release(link);
200
201 kfree(link->priv);
202}
203
204
205
206
207
208
209
210
211
212#define CS_CHECK(fn, ret) \
213do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
214
215
216
217static int card_present(void *arg)
218{
219 struct pcmcia_device *link = (struct pcmcia_device *)arg;
220
221 if (pcmcia_dev_present(link))
222 return 1;
223
224 return 0;
225}
226
227static int atmel_config_check(struct pcmcia_device *p_dev,
228 cistpl_cftable_entry_t *cfg,
229 cistpl_cftable_entry_t *dflt,
230 unsigned int vcc,
231 void *priv_data)
232{
233 if (cfg->index == 0)
234 return -ENODEV;
235
236
237 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
238 p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
239 p_dev->conf.Status = CCSR_AUDIO_ENA;
240 }
241
242
243
244 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
245 p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
246 else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
247 p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
248
249
250 if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
251 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
252
253
254 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
255 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
256 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
257 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
258 if (!(io->flags & CISTPL_IO_8BIT))
259 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
260 if (!(io->flags & CISTPL_IO_16BIT))
261 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
262 p_dev->io.BasePort1 = io->win[0].base;
263 p_dev->io.NumPorts1 = io->win[0].len;
264 if (io->nwin > 1) {
265 p_dev->io.Attributes2 = p_dev->io.Attributes1;
266 p_dev->io.BasePort2 = io->win[1].base;
267 p_dev->io.NumPorts2 = io->win[1].len;
268 }
269 }
270
271
272 return pcmcia_request_io(p_dev, &p_dev->io);
273}
274
275static int atmel_config(struct pcmcia_device *link)
276{
277 local_info_t *dev;
278 int last_fn, last_ret;
279 struct pcmcia_device_id *did;
280
281 dev = link->priv;
282 did = dev_get_drvdata(&handle_to_dev(link));
283
284 DEBUG(0, "atmel_config(0x%p)\n", link);
285
286
287
288
289
290
291
292
293
294
295
296
297
298 if (pcmcia_loop_config(link, atmel_config_check, NULL))
299 goto failed;
300
301
302
303
304
305
306 if (link->conf.Attributes & CONF_ENABLE_IRQ)
307 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
308
309
310
311
312
313
314 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
315
316 if (link->irq.AssignedIRQ == 0) {
317 printk(KERN_ALERT
318 "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config.");
319 goto cs_failed;
320 }
321
322 ((local_info_t*)link->priv)->eth_dev =
323 init_atmel_card(link->irq.AssignedIRQ,
324 link->io.BasePort1,
325 did ? did->driver_info : ATMEL_FW_TYPE_NONE,
326 &handle_to_dev(link),
327 card_present,
328 link);
329 if (!((local_info_t*)link->priv)->eth_dev)
330 goto cs_failed;
331
332
333
334
335
336
337 strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
338 dev->node.major = dev->node.minor = 0;
339 link->dev_node = &dev->node;
340
341 return 0;
342
343 cs_failed:
344 cs_error(link, last_fn, last_ret);
345 failed:
346 atmel_release(link);
347 return -ENODEV;
348}
349
350
351
352
353
354
355
356
357
358static void atmel_release(struct pcmcia_device *link)
359{
360 struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
361
362 DEBUG(0, "atmel_release(0x%p)\n", link);
363
364 if (dev)
365 stop_atmel_card(dev);
366 ((local_info_t*)link->priv)->eth_dev = NULL;
367
368 pcmcia_disable_device(link);
369}
370
371static int atmel_suspend(struct pcmcia_device *link)
372{
373 local_info_t *local = link->priv;
374
375 netif_device_detach(local->eth_dev);
376
377 return 0;
378}
379
380static int atmel_resume(struct pcmcia_device *link)
381{
382 local_info_t *local = link->priv;
383
384 atmel_open(local->eth_dev);
385 netif_device_attach(local->eth_dev);
386
387 return 0;
388}
389
390
391
392
393#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
394 .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
395 PCMCIA_DEV_ID_MATCH_CARD_ID, \
396 .manf_id = (manf), \
397 .card_id = (card), \
398 .driver_info = (kernel_ulong_t)(info), }
399
400#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
401 .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
402 PCMCIA_DEV_ID_MATCH_PROD_ID2, \
403 .prod_id = { (v1), (v2), NULL, NULL }, \
404 .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
405 .driver_info = (kernel_ulong_t)(info), }
406
407static struct pcmcia_device_id atmel_ids[] = {
408 PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
409 PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
410 PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
411 PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
412 PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
413 PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
414 PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
415 PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
416 PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
417 PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
418 PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
419 PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
420 PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
421 PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
422 PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
423 PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
424 PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
425 PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
426 PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
427 PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
428 PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
429 PCMCIA_DEVICE_NULL
430};
431
432MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
433
434static struct pcmcia_driver atmel_driver = {
435 .owner = THIS_MODULE,
436 .drv = {
437 .name = "atmel_cs",
438 },
439 .probe = atmel_probe,
440 .remove = atmel_detach,
441 .id_table = atmel_ids,
442 .suspend = atmel_suspend,
443 .resume = atmel_resume,
444};
445
446static int atmel_cs_init(void)
447{
448 return pcmcia_register_driver(&atmel_driver);
449}
450
451static void atmel_cs_cleanup(void)
452{
453 pcmcia_unregister_driver(&atmel_driver);
454}
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495module_init(atmel_cs_init);
496module_exit(atmel_cs_cleanup);
497