2 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
5 * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
12 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/sched.h>
18 #include <linux/ptrace.h>
19 #include <linux/slab.h>
20 #include <linux/string.h>
22 #include <asm/system.h>
24 #include <pcmcia/version.h>
25 #include <pcmcia/cs_types.h>
26 #include <pcmcia/cs.h>
27 #include <pcmcia/cistpl.h>
28 #include <pcmcia/ds.h>
29 #include "hisax_cfg.h"
31 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
32 MODULE_AUTHOR("Carsten Paeth");
33 MODULE_LICENSE("GPL");
36 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
37 you do not define PCMCIA_DEBUG at all, all the debug code will be
38 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
39 be present but disabled -- but it can then be enabled for specific
40 modules at load time with a 'pc_debug=#' option to insmod.
43 static int pc_debug = PCMCIA_DEBUG;
44 MODULE_PARM(pc_debug, "i");
45 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
46 static char *version =
47 "avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)";
49 #define DEBUG(n, args...)
52 /*====================================================================*/
54 /* Parameters that can be set with 'insmod' */
56 static int default_irq_list[11] = { 15, 13, 12, 11, 10, 9, 7, 5, 4, 3, -1 };
57 static int irq_list[11] = { -1 };
58 static int isdnprot = 2;
60 MODULE_PARM(irq_list, "1-11i");
61 MODULE_PARM(isdnprot, "1-4i");
63 /*====================================================================*/
66 The event() function is this driver's Card Services event handler.
67 It will be called by Card Services when an appropriate card status
68 event is received. The config() and release() entry points are
69 used to configure or release a socket, in response to card insertion
70 and ejection events. They are invoked from the skeleton event
74 static void avma1cs_config(dev_link_t *link);
75 static void avma1cs_release(dev_link_t *link);
76 static int avma1cs_event(event_t event, int priority,
77 event_callback_args_t *args);
80 The attach() and detach() entry points are used to create and destroy
81 "instances" of the driver, where each instance represents everything
82 needed to manage one actual PCMCIA card.
85 static dev_link_t *avma1cs_attach(void);
86 static void avma1cs_detach(dev_link_t *);
89 The dev_info variable is the "key" that is used to match up this
90 device driver with appropriate cards, through the card configuration
94 static dev_info_t dev_info = "avma1_cs";
97 A linked list of "instances" of the skeleton device. Each actual
98 PCMCIA card corresponds to one device instance, and is described
99 by one dev_link_t structure (defined in ds.h).
101 You may not want to use a linked list for this -- for example, the
102 memory card driver uses an array of dev_link_t pointers, where minor
103 device numbers are used to derive the corresponding array index.
106 static dev_link_t *dev_list = NULL;
109 A dev_link_t structure has fields for most things that are needed
110 to keep track of a socket, but there will usually be some device
111 specific information that also needs to be kept track of. The
112 'priv' pointer in a dev_link_t structure can be used to point to
113 a device-specific private data structure, like this.
115 A driver needs to provide a dev_node_t structure for each device
116 on a card. In some cases, there is only one device per card (for
117 example, ethernet cards, modems). In other cases, there may be
118 many actual or logical devices (SCSI adapters, memory cards with
119 multiple partitions). The dev_node_t structures need to be kept
120 in a linked list starting at the 'dev' field of a dev_link_t
121 structure. We allocate them in the card's private data structure,
122 because they generally can't be allocated dynamically.
125 typedef struct local_info_t {
129 /*======================================================================
131 avma1cs_attach() creates an "instance" of the driver, allocating
132 local data structures for one device. The device is registered
135 The dev_link structure is initialized, but we don't actually
136 configure the card at this point -- we wait until we receive a
137 card insertion event.
139 ======================================================================*/
141 static dev_link_t *avma1cs_attach(void)
143 client_reg_t client_reg;
148 DEBUG(0, "avma1cs_attach()\n");
150 /* Initialize the dev_link_t structure */
151 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
154 memset(link, 0, sizeof(struct dev_link_t));
156 /* Allocate space for private device-specific data */
157 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
162 memset(local, 0, sizeof(local_info_t));
165 /* The io structure describes IO port mapping */
166 link->io.NumPorts1 = 16;
167 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
168 link->io.NumPorts2 = 16;
169 link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
170 link->io.IOAddrLines = 5;
172 /* Interrupt setup */
173 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
174 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
176 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
177 if (irq_list[0] != -1) {
178 for (i = 0; i < 10 && irq_list[i] > 0; i++)
179 link->irq.IRQInfo2 |= 1 << irq_list[i];
181 for (i = 0; i < 10 && default_irq_list[i] > 0; i++)
182 link->irq.IRQInfo2 |= 1 << default_irq_list[i];
185 /* General socket configuration */
186 link->conf.Attributes = CONF_ENABLE_IRQ;
188 link->conf.IntType = INT_MEMORY_AND_IO;
189 link->conf.ConfigIndex = 1;
190 link->conf.Present = PRESENT_OPTION;
192 /* Register with Card Services */
193 link->next = dev_list;
195 client_reg.dev_info = &dev_info;
196 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
197 client_reg.EventMask =
198 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
199 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
200 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
201 client_reg.event_handler = &avma1cs_event;
202 client_reg.Version = 0x0210;
203 client_reg.event_callback_args.client_data = link;
204 ret = pcmcia_register_client(&link->handle, &client_reg);
206 cs_error(link->handle, RegisterClient, ret);
207 avma1cs_detach(link);
212 } /* avma1cs_attach */
214 /*======================================================================
216 This deletes a driver "instance". The device is de-registered
217 with Card Services. If it has been released, all local data
218 structures are freed. Otherwise, the structures will be freed
219 when the device is released.
221 ======================================================================*/
223 static void avma1cs_detach(dev_link_t *link)
227 DEBUG(0, "avma1cs_detach(0x%p)\n", link);
229 /* Locate device structure */
230 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
231 if (*linkp == link) break;
236 If the device is currently configured and active, we won't
237 actually delete it yet. Instead, it is marked so that when
238 the release() function is called, that will trigger a proper
241 if (link->state & DEV_CONFIG) {
243 printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' "
244 "still locked\n", link->dev->dev_name);
246 link->state |= DEV_STALE_LINK;
250 /* Break the link with Card Services */
252 pcmcia_deregister_client(link->handle);
254 /* Unlink device structure, free pieces */
261 } /* avma1cs_detach */
263 /*======================================================================
265 avma1cs_config() is scheduled to run after a CARD_INSERTION event
266 is received, to configure the PCMCIA socket, and to make the
267 ethernet device available to the system.
269 ======================================================================*/
271 static int get_tuple(client_handle_t handle, tuple_t *tuple,
274 int i = pcmcia_get_tuple_data(handle, tuple);
275 if (i != CS_SUCCESS) return i;
276 return pcmcia_parse_tuple(handle, tuple, parse);
279 static int first_tuple(client_handle_t handle, tuple_t *tuple,
282 int i = pcmcia_get_first_tuple(handle, tuple);
283 if (i != CS_SUCCESS) return i;
284 return get_tuple(handle, tuple, parse);
287 static int next_tuple(client_handle_t handle, tuple_t *tuple,
290 int i = pcmcia_get_next_tuple(handle, tuple);
291 if (i != CS_SUCCESS) return i;
292 return get_tuple(handle, tuple, parse);
295 static void avma1cs_config(dev_link_t *link)
297 client_handle_t handle;
300 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
308 handle = link->handle;
311 DEBUG(0, "avma1cs_config(0x%p)\n", link);
314 This reads the card's CONFIG tuple to find its configuration
318 tuple.DesiredTuple = CISTPL_CONFIG;
319 i = pcmcia_get_first_tuple(handle, &tuple);
320 if (i != CS_SUCCESS) break;
321 tuple.TupleData = buf;
322 tuple.TupleDataMax = 64;
323 tuple.TupleOffset = 0;
324 i = pcmcia_get_tuple_data(handle, &tuple);
325 if (i != CS_SUCCESS) break;
326 i = pcmcia_parse_tuple(handle, &tuple, &parse);
327 if (i != CS_SUCCESS) break;
328 link->conf.ConfigBase = parse.config.base;
330 if (i != CS_SUCCESS) {
331 cs_error(link->handle, ParseTuple, i);
332 link->state &= ~DEV_CONFIG_PENDING;
337 link->state |= DEV_CONFIG;
341 tuple.Attributes = 0;
342 tuple.TupleData = buf;
343 tuple.TupleDataMax = 254;
344 tuple.TupleOffset = 0;
345 tuple.DesiredTuple = CISTPL_VERS_1;
348 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
349 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
355 tuple.TupleData = (cisdata_t *)buf;
356 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
357 tuple.Attributes = 0;
358 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
359 i = first_tuple(handle, &tuple, &parse);
360 while (i == CS_SUCCESS) {
361 if (cf->io.nwin > 0) {
362 link->conf.ConfigIndex = cf->index;
363 link->io.BasePort1 = cf->io.win[0].base;
364 link->io.NumPorts1 = cf->io.win[0].len;
365 link->io.NumPorts2 = 0;
366 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
368 link->io.BasePort1+link->io.NumPorts1 - 1);
369 i = pcmcia_request_io(link->handle, &link->io);
370 if (i == CS_SUCCESS) goto found_port;
372 i = next_tuple(handle, &tuple, &parse);
376 if (i != CS_SUCCESS) {
377 cs_error(link->handle, RequestIO, i);
382 * allocate an interrupt line
384 i = pcmcia_request_irq(link->handle, &link->irq);
385 if (i != CS_SUCCESS) {
386 cs_error(link->handle, RequestIRQ, i);
387 pcmcia_release_io(link->handle, &link->io);
392 * configure the PCMCIA socket
394 i = pcmcia_request_configuration(link->handle, &link->conf);
395 if (i != CS_SUCCESS) {
396 cs_error(link->handle, RequestConfiguration, i);
397 pcmcia_release_io(link->handle, &link->io);
398 pcmcia_release_irq(link->handle, &link->irq);
404 /* At this point, the dev_node_t structure(s) should be
405 initialized and arranged in a linked list at link->dev. */
407 strcpy(dev->node.dev_name, "A1");
408 dev->node.major = 45;
410 link->dev = &dev->node;
412 link->state &= ~DEV_CONFIG_PENDING;
413 /* If any step failed, release any partially configured state */
415 avma1cs_release(link);
419 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
420 link->io.BasePort1, link->irq.AssignedIRQ);
422 icard.para[0] = link->irq.AssignedIRQ;
423 icard.para[1] = link->io.BasePort1;
424 icard.protocol = isdnprot;
425 icard.typ = ISDN_CTYPE_A1_PCMCIA;
427 i = hisax_init_pcmcia(link, &busy, &icard);
429 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
430 avma1cs_release(link);
435 } /* avma1cs_config */
437 /*======================================================================
439 After a card is removed, avma1cs_release() will unregister the net
440 device, and release the PCMCIA configuration. If the device is
441 still open, this will be postponed until it is closed.
443 ======================================================================*/
445 static void avma1cs_release(dev_link_t *link)
447 local_info_t *local = link->priv;
449 DEBUG(0, "avma1cs_release(0x%p)\n", link);
451 /* no unregister function with hisax */
452 HiSax_closecard(local->node.minor);
454 /* Unlink the device chain */
457 /* Don't bother checking to see if these succeed or not */
458 pcmcia_release_configuration(link->handle);
459 pcmcia_release_io(link->handle, &link->io);
460 pcmcia_release_irq(link->handle, &link->irq);
461 link->state &= ~DEV_CONFIG;
463 if (link->state & DEV_STALE_LINK)
464 avma1cs_detach(link);
465 } /* avma1cs_release */
467 /*======================================================================
469 The card status event handler. Mostly, this schedules other
470 stuff to run after an event is received. A CARD_REMOVAL event
471 also sets some flags to discourage the net drivers from trying
472 to talk to the card any more.
474 When a CARD_REMOVAL event is received, we immediately set a flag
475 to block future accesses to this device. All the functions that
476 actually access the device should check this flag to make sure
477 the card is still present.
479 ======================================================================*/
481 static int avma1cs_event(event_t event, int priority,
482 event_callback_args_t *args)
484 dev_link_t *link = args->client_data;
486 DEBUG(1, "avma1cs_event(0x%06x)\n", event);
489 case CS_EVENT_CARD_REMOVAL:
490 if (link->state & DEV_CONFIG)
491 avma1cs_release(link);
493 case CS_EVENT_CARD_INSERTION:
494 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
495 avma1cs_config(link);
497 case CS_EVENT_PM_SUSPEND:
498 link->state |= DEV_SUSPEND;
499 /* Fall through... */
500 case CS_EVENT_RESET_PHYSICAL:
501 if (link->state & DEV_CONFIG)
502 pcmcia_release_configuration(link->handle);
504 case CS_EVENT_PM_RESUME:
505 link->state &= ~DEV_SUSPEND;
506 /* Fall through... */
507 case CS_EVENT_CARD_RESET:
508 if (link->state & DEV_CONFIG)
509 pcmcia_request_configuration(link->handle, &link->conf);
513 } /* avma1cs_event */
515 static struct pcmcia_driver avma1cs_driver = {
516 .owner = THIS_MODULE,
520 .attach = avma1cs_attach,
521 .detach = avma1cs_detach,
524 /*====================================================================*/
526 static int __init init_avma1_cs(void)
528 return(pcmcia_register_driver(&avma1cs_driver));
531 static void __exit exit_avma1_cs(void)
533 pcmcia_unregister_driver(&avma1cs_driver);
535 /* XXX: this really needs to move into generic code.. */
536 while (dev_list != NULL) {
537 if (dev_list->state & DEV_CONFIG)
538 avma1cs_release(dev_list);
539 avma1cs_detach(dev_list);
543 module_init(init_avma1_cs);
544 module_exit(exit_avma1_cs);