1 /*** -*- linux-c -*- **********************************************************
2
3 Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
4
5 Copyright 2000-2001 ATMEL Corporation.
6 Copyright 2003 Simon Kelley.
7
8 This code was developed from version 2.1.1 of the Atmel drivers,
9 released by Atmel corp. under the GPL in December 2002. It also
10 includes code from the Linux aironet drivers (C) Benjamin Reed,
11 and the Linux PCMCIA package, (C) David Hinds.
12
13 For all queries about this code, please contact the current author,
14 Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
15
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
20
21 This software is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with Atmel wireless lan drivers; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
30 ******************************************************************************/
31
32 #include <linux/config.h>
33 #ifdef __IN_PCMCIA_PACKAGE__
34 #include <pcmcia/k_compat.h>
35 #endif
36 #include <linux/init.h>
37 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/ptrace.h>
40 #include <linux/slab.h>
41 #include <linux/string.h>
42 #include <linux/netdevice.h>
43
44 #include <pcmcia/version.h>
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 #include <linux/802_11.h>
56
57
58 /*
59 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
60 you do not define PCMCIA_DEBUG at all, all the debug code will be
61 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
62 be present but disabled -- but it can then be enabled for specific
63 modules at load time with a 'pc_debug=#' option to insmod.
64 */
65 #ifdef PCMCIA_DEBUG
66 static int pc_debug = PCMCIA_DEBUG;
67 MODULE_PARM(pc_debug, "i");
68 static char *version = "$Revision: 1.2 $";
69 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
70 #else
71 #define DEBUG(n, args...)
72 #endif
73
74 /*====================================================================*/
75
76 /* Parameters that can be set with 'insmod' */
77
78 /* The old way: bit map of interrupts to choose from */
79 /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
80 static u_int irq_mask = 0xdeb8;
81 /* Newer, simpler way of listing specific interrupts */
82 static int irq_list[4] = { -1 };
83
84 MODULE_AUTHOR("Simon Kelley");
85 MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
86 MODULE_LICENSE("GPL");
87 MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
88 MODULE_PARM(irq_mask, "i");
89 MODULE_PARM(irq_list, "1-4i");
90
91 /*====================================================================*/
92
93 /*
94 The event() function is this driver's Card Services event handler.
95 It will be called by Card Services when an appropriate card status
96 event is received. The config() and release() entry points are
97 used to configure or release a socket, in response to card
98 insertion and ejection events. They are invoked from the atmel_cs
99 event handler.
100 */
101
102 struct net_device *init_atmel_card(int, int, char *, int,
103 int (*present_func)(void *), void * );
104 void stop_atmel_card( struct net_device *, int );
105 int reset_atmel_card( struct net_device * );
106
107 static void atmel_config(dev_link_t *link);
108 static void atmel_release(dev_link_t *link);
109 static int atmel_event(event_t event, int priority,
110 event_callback_args_t *args);
111
112 /*
113 The attach() and detach() entry points are used to create and destroy
114 "instances" of the driver, where each instance represents everything
115 needed to manage one actual PCMCIA card.
116 */
117
118 static dev_link_t *atmel_attach(void);
119 static void atmel_detach(dev_link_t *);
120
121 /*
122 You'll also need to prototype all the functions that will actually
123 be used to talk to your device. See 'pcmem_cs' for a good example
124 of a fully self-sufficient driver; the other drivers rely more or
125 less on other parts of the kernel.
126 */
127
128 /*
129 The dev_info variable is the "key" that is used to match up this
130 device driver with appropriate cards, through the card configuration
131 database.
132 */
133
134 static dev_info_t dev_info = "atmel_cs";
135
136 /*
137 A linked list of "instances" of the atmelnet device. Each actual
138 PCMCIA card corresponds to one device instance, and is described
139 by one dev_link_t structure (defined in ds.h).
140
141 You may not want to use a linked list for this -- for example, the
142 memory card driver uses an array of dev_link_t pointers, where minor
143 device numbers are used to derive the corresponding array index.
144 */
145
146 static dev_link_t *dev_list = NULL;
147
148 /*
149 A dev_link_t structure has fields for most things that are needed
150 to keep track of a socket, but there will usually be some device
151 specific information that also needs to be kept track of. The
152 'priv' pointer in a dev_link_t structure can be used to point to
153 a device-specific private data structure, like this.
154
155 A driver needs to provide a dev_node_t structure for each device
156 on a card. In some cases, there is only one device per card (for
157 example, ethernet cards, modems). In other cases, there may be
158 many actual or logical devices (SCSI adapters, memory cards with
159 multiple partitions). The dev_node_t structures need to be kept
160 in a linked list starting at the 'dev' field of a dev_link_t
161 structure. We allocate them in the card's private data structure,
162 because they generally shouldn't be allocated dynamically.
163
164 In this case, we also provide a flag to indicate if a device is
165 "stopped" due to a power management event, or card ejection. The
166 device IO routines can use a flag like this to throttle IO to a
167 card that is not ready to accept it.
168 */
169
170 typedef struct local_info_t {
171 dev_node_t node;
172 struct net_device *eth_dev;
173 } local_info_t;
174
175 /*====================================================================*/
176
cs_error(client_handle_t handle,int func,int ret)177 static void cs_error(client_handle_t handle, int func, int ret)
178 {
179 error_info_t err = { func, ret };
180 CardServices(ReportError, handle, &err);
181 }
182
183 /*======================================================================
184
185 atmel_attach() creates an "instance" of the driver, allocating
186 local data structures for one device. The device is registered
187 with Card Services.
188
189 The dev_link structure is initialized, but we don't actually
190 configure the card at this point -- we wait until we receive a
191 card insertion event.
192
193 ======================================================================*/
194
atmel_attach(void)195 static dev_link_t *atmel_attach(void)
196 {
197 client_reg_t client_reg;
198 dev_link_t *link;
199 local_info_t *local;
200 int ret, i;
201
202 DEBUG(0, "atmel_attach()\n");
203
204 /* Initialize the dev_link_t structure */
205 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
206 if (!link) {
207 printk(KERN_ERR "atmel_cs: no memory for new device\n");
208 return NULL;
209 }
210 memset(link, 0, sizeof(struct dev_link_t));
211
212 /* Interrupt setup */
213 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
214 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
215 if (irq_list[0] == -1)
216 link->irq.IRQInfo2 = irq_mask;
217 else
218 for (i = 0; i < 4; i++)
219 link->irq.IRQInfo2 |= 1 << irq_list[i];
220 link->irq.Handler = NULL;
221
222 /*
223 General socket configuration defaults can go here. In this
224 client, we assume very little, and rely on the CIS for almost
225 everything. In most clients, many details (i.e., number, sizes,
226 and attributes of IO windows) are fixed by the nature of the
227 device, and can be hard-wired here.
228 */
229 link->conf.Attributes = 0;
230 link->conf.Vcc = 50;
231 link->conf.IntType = INT_MEMORY_AND_IO;
232
233 /* Allocate space for private device-specific data */
234 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
235 if (!local) {
236 printk(KERN_ERR "atmel_cs: no memory for new device\n");
237 kfree (link);
238 return NULL;
239 }
240 memset(local, 0, sizeof(local_info_t));
241 link->priv = local;
242
243 /* Register with Card Services */
244 link->next = dev_list;
245 dev_list = link;
246 client_reg.dev_info = &dev_info;
247 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
248 client_reg.EventMask =
249 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
250 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
251 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
252 client_reg.event_handler = &atmel_event;
253 client_reg.Version = 0x0210;
254 client_reg.event_callback_args.client_data = link;
255 ret = CardServices(RegisterClient, &link->handle, &client_reg);
256 if (ret != 0) {
257 cs_error(link->handle, RegisterClient, ret);
258 atmel_detach(link);
259 return NULL;
260 }
261
262 return link;
263 } /* atmel_attach */
264
265 /*======================================================================
266
267 This deletes a driver "instance". The device is de-registered
268 with Card Services. If it has been released, all local data
269 structures are freed. Otherwise, the structures will be freed
270 when the device is released.
271
272 ======================================================================*/
273
atmel_detach(dev_link_t * link)274 static void atmel_detach(dev_link_t *link)
275 {
276 dev_link_t **linkp;
277
278 DEBUG(0, "atmel_detach(0x%p)\n", link);
279
280 /* Locate device structure */
281 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
282 if (*linkp == link) break;
283 if (*linkp == NULL)
284 return;
285
286 if (link->state & DEV_CONFIG)
287 atmel_release(link);
288
289 /* Break the link with Card Services */
290 if (link->handle)
291 CardServices(DeregisterClient, link->handle);
292
293 /* Unlink device structure, free pieces */
294 *linkp = link->next;
295 if (link->priv)
296 kfree(link->priv);
297 kfree(link);
298 }
299
300 /*======================================================================
301
302 atmel_config() is scheduled to run after a CARD_INSERTION event
303 is received, to configure the PCMCIA socket, and to make the
304 device available to the system.
305
306 ======================================================================*/
307
308 #define CS_CHECK(fn, args...) \
309 while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
310
311 #define CFG_CHECK(fn, args...) \
312 if (CardServices(fn, args) != 0) goto next_entry
313
314 /* Call-back function to interrogate PCMCIA-specific information
315 about the current existance of the card */
card_present(void * arg)316 static int card_present(void *arg)
317 {
318 dev_link_t *link = (dev_link_t *)arg;
319 if (link->state & DEV_SUSPEND)
320 return 0;
321 else if (link->state & DEV_PRESENT)
322 return 1;
323
324 return 0;
325 }
326
327 /* list of cards we know about and their firmware requirements.
328 Go either by Manfid or version strings.
329 Cards not in this list will need a firmware parameter to the module
330 in all probability. Note that the SMC 2632 V2 and V3 have the same
331 manfids, so we ignore those and use the version1 strings. */
332
333 static struct {
334 int manf, card;
335 char *ver1;
336 char *firmware;
337 char *name;
338 } card_table[] = {
339 { 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d.bin", "Actiontec 802CAT1" },
340 { 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502.bin", "NoName-RFMD" },
341 { 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d.bin", "NoName-revD" },
342 { 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e.bin", "NoName-revE" },
343 { 0, 0, "ATMEL/AT76C504", "atmel_at76c504.bin", "NoName-504" },
344 { MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com.bin", "3com 3CRWE62092B" },
345 { MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com.bin", "3com 3CRSHPW_96" },
346 { 0, 0, "SMC/2632W-V2", "atmel_at76c502.bin", "SMC 2632W-V2" },
347 { 0, 0, "SMC/2632W", "atmel_at76c502d.bin", "SMC 2632W-V3" },
348 { 0xd601, 0x0007, NULL, "atmel_at76c502.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */
349 { 0x01bf, 0x3302, NULL, "atmel_at76c502d.bin", "Belkin F5D6060u"}, /* " " " " " */
350 { 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502.bin", "BT Voyager 1020"},
351 { 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502.bin", "Siemens Gigaset PC Card II" },
352 { 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e.bin", "CNet CNWLC-811ARL" }
353 };
354
atmel_config(dev_link_t * link)355 static void atmel_config(dev_link_t *link)
356 {
357 client_handle_t handle;
358 tuple_t tuple;
359 cisparse_t parse;
360 local_info_t *dev;
361 int last_fn, last_ret;
362 u_char buf[64];
363 int card_index = -1, done = 0;
364
365 handle = link->handle;
366 dev = link->priv;
367
368 DEBUG(0, "atmel_config(0x%p)\n", link);
369
370 tuple.Attributes = 0;
371 tuple.TupleData = buf;
372 tuple.TupleDataMax = sizeof(buf);
373 tuple.TupleOffset = 0;
374
375 tuple.DesiredTuple = CISTPL_MANFID;
376 if (CardServices(GetFirstTuple, handle, &tuple) == 0) {
377 int i;
378 cistpl_manfid_t *manfid;
379 CS_CHECK(GetTupleData, handle, &tuple);
380 CS_CHECK(ParseTuple, handle, &tuple, &parse);
381 manfid = &(parse.manfid);
382 for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
383 if (!card_table[i].ver1 &&
384 manfid->manf == card_table[i].manf &&
385 manfid->card == card_table[i].card) {
386 card_index = i;
387 done = 1;
388 }
389 }
390 }
391
392 tuple.DesiredTuple = CISTPL_VERS_1;
393 if (!done && (CardServices(GetFirstTuple, handle, &tuple) == 0)) {
394 int i, j, k;
395 cistpl_vers_1_t *ver1;
396 CS_CHECK(GetTupleData, handle, &tuple);
397 CS_CHECK(ParseTuple, handle, &tuple, &parse);
398 ver1 = &(parse.version_1);
399
400 for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
401 for (j = 0; j < ver1->ns; j++) {
402 char *p = card_table[i].ver1;
403 char *q = &ver1->str[ver1->ofs[j]];
404 if (!p)
405 goto mismatch;
406 for (k = 0; k < j; k++) {
407 while ((*p != '\0') && (*p != '/')) p++;
408 if (*p == '\0') {
409 if (*q != '\0')
410 goto mismatch;
411 } else
412 p++;
413 }
414 while((*q != '\0') && (*p != '\0') &&
415 (*p != '/') && (*p == *q)) p++, q++;
416 if (((*p != '\0') && *p != '/') || *q != '\0')
417 goto mismatch;
418 }
419 card_index = i;
420 break; /* done */
421
422 mismatch:
423 j = 0; /* dummy stmt to shut up compiler */
424 }
425 }
426
427 /*
428 This reads the card's CONFIG tuple to find its configuration
429 registers.
430 */
431 tuple.DesiredTuple = CISTPL_CONFIG;
432 CS_CHECK(GetFirstTuple, handle, &tuple);
433 CS_CHECK(GetTupleData, handle, &tuple);
434 CS_CHECK(ParseTuple, handle, &tuple, &parse);
435 link->conf.ConfigBase = parse.config.base;
436 link->conf.Present = parse.config.rmask[0];
437
438 /* Configure card */
439 link->state |= DEV_CONFIG;
440
441 /*
442 In this loop, we scan the CIS for configuration table entries,
443 each of which describes a valid card configuration, including
444 voltage, IO window, memory window, and interrupt settings.
445
446 We make no assumptions about the card to be configured: we use
447 just the information available in the CIS. In an ideal world,
448 this would work for any PCMCIA card, but it requires a complete
449 and accurate CIS. In practice, a driver usually "knows" most of
450 these things without consulting the CIS, and most client drivers
451 will only use the CIS to fill in implementation-defined details.
452 */
453 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
454 CS_CHECK(GetFirstTuple, handle, &tuple);
455 while (1) {
456 cistpl_cftable_entry_t dflt = { 0 };
457 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
458 CFG_CHECK(GetTupleData, handle, &tuple);
459 CFG_CHECK(ParseTuple, handle, &tuple, &parse);
460
461 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
462 if (cfg->index == 0) goto next_entry;
463 link->conf.ConfigIndex = cfg->index;
464
465 /* Does this card need audio output? */
466 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
467 link->conf.Attributes |= CONF_ENABLE_SPKR;
468 link->conf.Status = CCSR_AUDIO_ENA;
469 }
470
471 /* Use power settings for Vcc and Vpp if present */
472 /* Note that the CIS values need to be rescaled */
473 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM))
474 link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
475 else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM))
476 link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
477
478 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
479 link->conf.Vpp1 = link->conf.Vpp2 =
480 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
481 else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
482 link->conf.Vpp1 = link->conf.Vpp2 =
483 dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
484
485 /* Do we need to allocate an interrupt? */
486 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
487 link->conf.Attributes |= CONF_ENABLE_IRQ;
488
489 /* IO window settings */
490 link->io.NumPorts1 = link->io.NumPorts2 = 0;
491 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
492 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
493 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
494 if (!(io->flags & CISTPL_IO_8BIT))
495 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
496 if (!(io->flags & CISTPL_IO_16BIT))
497 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
498 link->io.BasePort1 = io->win[0].base;
499 link->io.NumPorts1 = io->win[0].len;
500 if (io->nwin > 1) {
501 link->io.Attributes2 = link->io.Attributes1;
502 link->io.BasePort2 = io->win[1].base;
503 link->io.NumPorts2 = io->win[1].len;
504 }
505 }
506
507 /* This reserves IO space but doesn't actually enable it */
508 CFG_CHECK(RequestIO, link->handle, &link->io);
509 /* If we got this far, we're cool! */
510 break;
511
512 next_entry:
513 CS_CHECK(GetNextTuple, handle, &tuple);
514 }
515
516 /*
517 Allocate an interrupt line. Note that this does not assign a
518 handler to the interrupt, unless the 'Handler' member of the
519 irq structure is initialized.
520 */
521 if (link->conf.Attributes & CONF_ENABLE_IRQ)
522 CS_CHECK(RequestIRQ, link->handle, &link->irq);
523
524 /*
525 This actually configures the PCMCIA socket -- setting up
526 the I/O windows and the interrupt mapping, and putting the
527 card and host interface into "Memory and IO" mode.
528 */
529 CS_CHECK(RequestConfiguration, link->handle, &link->conf);
530
531 if (link->irq.AssignedIRQ == 0) {
532 printk(KERN_ALERT
533 "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config.");
534 goto cs_failed;
535 }
536
537 ((local_info_t*)link->priv)->eth_dev =
538 init_atmel_card(link->irq.AssignedIRQ,
539 link->io.BasePort1,
540 card_index == -1 ? NULL : card_table[card_index].firmware,
541 card_index == -1 ? 0 : (card_table[card_index].manf == MANFID_3COM),
542 card_present,
543 link);
544 if (!((local_info_t*)link->priv)->eth_dev)
545 goto cs_failed;
546
547 /*
548 At this point, the dev_node_t structure(s) need to be
549 initialized and arranged in a linked list at link->dev.
550 */
551 strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
552 dev->node.major = dev->node.minor = 0;
553 link->dev = &dev->node;
554
555 /* Finally, report what we've done */
556 printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d",
557 dev->node.dev_name,
558 card_index == -1 ? "" : card_table[card_index].name,
559 card_index == -1 ? "" : " ",
560 link->conf.ConfigIndex,
561 link->conf.Vcc/10, link->conf.Vcc%10);
562 if (link->conf.Vpp1)
563 printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
564 if (link->conf.Attributes & CONF_ENABLE_IRQ)
565 printk(", irq %d", link->irq.AssignedIRQ);
566 if (link->io.NumPorts1)
567 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
568 link->io.BasePort1+link->io.NumPorts1-1);
569 if (link->io.NumPorts2)
570 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
571 link->io.BasePort2+link->io.NumPorts2-1);
572 printk("\n");
573
574 link->state &= ~DEV_CONFIG_PENDING;
575 return;
576
577 cs_failed:
578 cs_error(link->handle, last_fn, last_ret);
579 atmel_release(link);
580 }
581
582 /*======================================================================
583
584 After a card is removed, atmel_release() will unregister the
585 device, and release the PCMCIA configuration. If the device is
586 still open, this will be postponed until it is closed.
587
588 ======================================================================*/
589
atmel_release(dev_link_t * link)590 static void atmel_release(dev_link_t *link)
591 {
592 struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
593
594 DEBUG(0, "atmel_release(0x%p)\n", link);
595
596 /* Unlink the device chain */
597 link->dev = NULL;
598
599 if (dev)
600 stop_atmel_card(dev, 0);
601 ((local_info_t*)link->priv)->eth_dev = 0;
602
603 /* Don't bother checking to see if these succeed or not */
604 CardServices(ReleaseConfiguration, link->handle);
605 if (link->io.NumPorts1)
606 CardServices(ReleaseIO, link->handle, &link->io);
607 if (link->irq.AssignedIRQ)
608 CardServices(ReleaseIRQ, link->handle, &link->irq);
609 link->state &= ~DEV_CONFIG;
610 }
611
612 /*======================================================================
613
614 The card status event handler. Mostly, this schedules other
615 stuff to run after an event is received.
616
617 When a CARD_REMOVAL event is received, we immediately set a
618 private flag to block future accesses to this device. All the
619 functions that actually access the device should check this flag
620 to make sure the card is still present.
621
622 ======================================================================*/
623
atmel_event(event_t event,int priority,event_callback_args_t * args)624 static int atmel_event(event_t event, int priority,
625 event_callback_args_t *args)
626 {
627 dev_link_t *link = args->client_data;
628 local_info_t *local = link->priv;
629
630 DEBUG(1, "atmel_event(0x%06x)\n", event);
631
632 switch (event) {
633 case CS_EVENT_CARD_REMOVAL:
634 link->state &= ~DEV_PRESENT;
635 if (link->state & DEV_CONFIG) {
636 netif_device_detach(local->eth_dev);
637 atmel_release(link);
638 }
639 break;
640 case CS_EVENT_CARD_INSERTION:
641 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
642 atmel_config(link);
643 break;
644 case CS_EVENT_PM_SUSPEND:
645 link->state |= DEV_SUSPEND;
646 /* Fall through... */
647 case CS_EVENT_RESET_PHYSICAL:
648 if (link->state & DEV_CONFIG) {
649 netif_device_detach(local->eth_dev);
650 CardServices(ReleaseConfiguration, link->handle);
651 }
652 break;
653 case CS_EVENT_PM_RESUME:
654 link->state &= ~DEV_SUSPEND;
655 /* Fall through... */
656 case CS_EVENT_CARD_RESET:
657 if (link->state & DEV_CONFIG) {
658 CardServices(RequestConfiguration, link->handle, &link->conf);
659 reset_atmel_card(local->eth_dev);
660 netif_device_attach(local->eth_dev);
661 }
662 break;
663 }
664 return 0;
665 } /* atmel_event */
666
atmel_cs_init(void)667 static int atmel_cs_init(void)
668 {
669 servinfo_t serv;
670 DEBUG(0, "%s\n", version);
671 CardServices(GetCardServicesInfo, &serv);
672 if (serv.Revision != CS_RELEASE_CODE) {
673 printk(KERN_NOTICE "atmel_cs: Card Services release "
674 "does not match!\n");
675 return -1;
676 }
677 register_pcmcia_driver(&dev_info, &atmel_attach, &atmel_detach);
678 return 0;
679 }
680
atmel_cs_cleanup(void)681 static void atmel_cs_cleanup(void)
682 {
683 unregister_pcmcia_driver(&dev_info);
684
685 /* XXX: this really needs to move into generic code.. */
686 while (dev_list != NULL) {
687 if (dev_list->state & DEV_CONFIG)
688 atmel_release(dev_list);
689 atmel_detach(dev_list);
690 }
691 }
692
693 /*
694 This program is free software; you can redistribute it and/or
695 modify it under the terms of the GNU General Public License
696 as published by the Free Software Foundation; either version 2
697 of the License, or (at your option) any later version.
698
699 This program is distributed in the hope that it will be useful,
700 but WITHOUT ANY WARRANTY; without even the implied warranty of
701 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
702 GNU General Public License for more details.
703
704 In addition:
705
706 Redistribution and use in source and binary forms, with or without
707 modification, are permitted provided that the following conditions
708 are met:
709
710 1. Redistributions of source code must retain the above copyright
711 notice, this list of conditions and the following disclaimer.
712 2. Redistributions in binary form must reproduce the above copyright
713 notice, this list of conditions and the following disclaimer in the
714 documentation and/or other materials provided with the distribution.
715 3. The name of the author may not be used to endorse or promote
716 products derived from this software without specific prior written
717 permission.
718
719 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
720 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
721 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
722 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
723 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
724 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
725 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
726 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
727 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
728 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
729 POSSIBILITY OF SUCH DAMAGE.
730 */
731
732 module_init(atmel_cs_init);
733 module_exit(atmel_cs_cleanup);
734