1 /* $Id: avm_cs.c,v 1.1.1.1 2005/04/11 02:50:22 jack Exp $
3 * A PCMCIA client driver for AVM B1/M1/M2
5 * Copyright 1999 by Carsten Paeth <calle@calle.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>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/sched.h>
16 #include <linux/ptrace.h>
17 #include <linux/slab.h>
18 #include <linux/string.h>
19 #include <linux/timer.h>
20 #include <linux/tty.h>
21 #include <linux/serial.h>
22 #include <linux/major.h>
24 #include <asm/system.h>
26 #include <pcmcia/version.h>
27 #include <pcmcia/cs_types.h>
28 #include <pcmcia/cs.h>
29 #include <pcmcia/cistpl.h>
30 #include <pcmcia/ciscode.h>
31 #include <pcmcia/ds.h>
32 #include <pcmcia/cisreg.h>
34 #include <linux/skbuff.h>
35 #include <linux/capi.h>
36 #include <linux/b1lli.h>
37 #include <linux/b1pcmcia.h>
39 /*====================================================================*/
41 MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
42 MODULE_AUTHOR("Carsten Paeth");
43 MODULE_LICENSE("GPL");
45 /*====================================================================*/
47 /* Parameters that can be set with 'insmod' */
49 /* This means pick from 15, 12, 11, 10, 9, 7, 5, 4, and 3 */
50 static int default_irq_list[10] = { 15, 12, 11, 10, 9, 7, 5, 4, 3, -1 };
51 static int irq_list[10] = { -1 };
53 MODULE_PARM(irq_list, "1-10i");
55 /*====================================================================*/
58 The event() function is this driver's Card Services event handler.
59 It will be called by Card Services when an appropriate card status
60 event is received. The config() and release() entry points are
61 used to configure or release a socket, in response to card insertion
62 and ejection events. They are invoked from the skeleton event
66 static void avmcs_config(dev_link_t *link);
67 static void avmcs_release(u_long arg);
68 static int avmcs_event(event_t event, int priority,
69 event_callback_args_t *args);
72 The attach() and detach() entry points are used to create and destroy
73 "instances" of the driver, where each instance represents everything
74 needed to manage one actual PCMCIA card.
77 static dev_link_t *avmcs_attach(void);
78 static void avmcs_detach(dev_link_t *);
81 The dev_info variable is the "key" that is used to match up this
82 device driver with appropriate cards, through the card configuration
86 static dev_info_t dev_info = "avm_cs";
89 A linked list of "instances" of the skeleton device. Each actual
90 PCMCIA card corresponds to one device instance, and is described
91 by one dev_link_t structure (defined in ds.h).
93 You may not want to use a linked list for this -- for example, the
94 memory card driver uses an array of dev_link_t pointers, where minor
95 device numbers are used to derive the corresponding array index.
98 static dev_link_t *dev_list = NULL;
101 A dev_link_t structure has fields for most things that are needed
102 to keep track of a socket, but there will usually be some device
103 specific information that also needs to be kept track of. The
104 'priv' pointer in a dev_link_t structure can be used to point to
105 a device-specific private data structure, like this.
107 A driver needs to provide a dev_node_t structure for each device
108 on a card. In some cases, there is only one device per card (for
109 example, ethernet cards, modems). In other cases, there may be
110 many actual or logical devices (SCSI adapters, memory cards with
111 multiple partitions). The dev_node_t structures need to be kept
112 in a linked list starting at the 'dev' field of a dev_link_t
113 structure. We allocate them in the card's private data structure,
114 because they generally can't be allocated dynamically.
117 typedef struct local_info_t {
121 /*====================================================================*/
123 static void cs_error(client_handle_t handle, int func, int ret)
125 error_info_t err = { func, ret };
126 CardServices(ReportError, handle, &err);
129 /*======================================================================
131 avmcs_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 *avmcs_attach(void)
143 client_reg_t client_reg;
148 /* Initialize the dev_link_t structure */
149 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
152 memset(link, 0, sizeof(struct dev_link_t));
153 link->release.function = &avmcs_release;
154 link->release.data = (u_long)link;
156 /* The io structure describes IO port mapping */
157 link->io.NumPorts1 = 16;
158 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
159 link->io.NumPorts2 = 0;
161 /* Interrupt setup */
162 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
163 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
165 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
166 if (irq_list[0] != -1) {
167 for (i = 0; i < 10 && irq_list[i] > 0; i++)
168 link->irq.IRQInfo2 |= 1 << irq_list[i];
170 for (i = 0; i < 10 && default_irq_list[i] > 0; i++)
171 link->irq.IRQInfo2 |= 1 << default_irq_list[i];
174 /* General socket configuration */
175 link->conf.Attributes = CONF_ENABLE_IRQ;
177 link->conf.IntType = INT_MEMORY_AND_IO;
178 link->conf.ConfigIndex = 1;
179 link->conf.Present = PRESENT_OPTION;
181 /* Allocate space for private device-specific data */
182 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
185 memset(local, 0, sizeof(local_info_t));
188 /* Register with Card Services */
189 link->next = dev_list;
191 client_reg.dev_info = &dev_info;
192 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
193 client_reg.EventMask =
194 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
195 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
196 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
197 client_reg.event_handler = &avmcs_event;
198 client_reg.Version = 0x0210;
199 client_reg.event_callback_args.client_data = link;
200 ret = CardServices(RegisterClient, &link->handle, &client_reg);
202 cs_error(link->handle, RegisterClient, ret);
210 /*======================================================================
212 This deletes a driver "instance". The device is de-registered
213 with Card Services. If it has been released, all local data
214 structures are freed. Otherwise, the structures will be freed
215 when the device is released.
217 ======================================================================*/
219 static void avmcs_detach(dev_link_t *link)
223 /* Locate device structure */
224 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
225 if (*linkp == link) break;
230 If the device is currently configured and active, we won't
231 actually delete it yet. Instead, it is marked so that when
232 the release() function is called, that will trigger a proper
235 if (link->state & DEV_CONFIG) {
236 link->state |= DEV_STALE_LINK;
240 /* Break the link with Card Services */
242 CardServices(DeregisterClient, link->handle);
244 /* Unlink device structure, free pieces */
253 /*======================================================================
255 avmcs_config() is scheduled to run after a CARD_INSERTION event
256 is received, to configure the PCMCIA socket, and to make the
257 ethernet device available to the system.
259 ======================================================================*/
261 static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
265 i = CardServices(fn, handle, tuple);
266 if (i != CS_SUCCESS) return i;
267 i = CardServices(GetTupleData, handle, tuple);
268 if (i != CS_SUCCESS) return i;
269 return CardServices(ParseTuple, handle, tuple, parse);
272 #define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
273 #define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
275 static void avmcs_config(dev_link_t *link)
277 client_handle_t handle;
280 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
286 int (*addcard)(unsigned int port, unsigned irq);
288 handle = link->handle;
292 This reads the card's CONFIG tuple to find its configuration
296 tuple.DesiredTuple = CISTPL_CONFIG;
297 i = CardServices(GetFirstTuple, handle, &tuple);
298 if (i != CS_SUCCESS) break;
299 tuple.TupleData = buf;
300 tuple.TupleDataMax = 64;
301 tuple.TupleOffset = 0;
302 i = CardServices(GetTupleData, handle, &tuple);
303 if (i != CS_SUCCESS) break;
304 i = CardServices(ParseTuple, handle, &tuple, &parse);
305 if (i != CS_SUCCESS) break;
306 link->conf.ConfigBase = parse.config.base;
308 if (i != CS_SUCCESS) {
309 cs_error(link->handle, ParseTuple, i);
310 link->state &= ~DEV_CONFIG_PENDING;
315 link->state |= DEV_CONFIG;
319 tuple.Attributes = 0;
320 tuple.TupleData = buf;
321 tuple.TupleDataMax = 254;
322 tuple.TupleOffset = 0;
323 tuple.DesiredTuple = CISTPL_VERS_1;
326 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
327 strncpy(devname,parse.version_1.str + parse.version_1.ofs[1],
333 tuple.TupleData = (cisdata_t *)buf;
334 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
335 tuple.Attributes = 0;
336 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
337 i = first_tuple(handle, &tuple, &parse);
338 while (i == CS_SUCCESS) {
339 if (cf->io.nwin > 0) {
340 link->conf.ConfigIndex = cf->index;
341 link->io.BasePort1 = cf->io.win[0].base;
342 link->io.NumPorts1 = cf->io.win[0].len;
343 link->io.NumPorts2 = 0;
344 printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
346 link->io.BasePort1+link->io.NumPorts1-1);
347 i = CardServices(RequestIO, link->handle, &link->io);
348 if (i == CS_SUCCESS) goto found_port;
350 i = next_tuple(handle, &tuple, &parse);
354 if (i != CS_SUCCESS) {
355 cs_error(link->handle, RequestIO, i);
360 * allocate an interrupt line
362 i = CardServices(RequestIRQ, link->handle, &link->irq);
363 if (i != CS_SUCCESS) {
364 cs_error(link->handle, RequestIRQ, i);
365 CardServices(ReleaseIO, link->handle, &link->io);
370 * configure the PCMCIA socket
372 i = CardServices(RequestConfiguration, link->handle, &link->conf);
373 if (i != CS_SUCCESS) {
374 cs_error(link->handle, RequestConfiguration, i);
375 CardServices(ReleaseIO, link->handle, &link->io);
376 CardServices(ReleaseIRQ, link->handle, &link->irq);
382 /* At this point, the dev_node_t structure(s) should be
383 initialized and arranged in a linked list at link->dev. */
386 char *s = strrchr(devname, ' ');
390 strcpy(dev->node.dev_name, s);
391 if (strcmp("M1", s) == 0) {
392 cardtype = AVM_CARDTYPE_M1;
393 } else if (strcmp("M2", s) == 0) {
394 cardtype = AVM_CARDTYPE_M2;
396 cardtype = AVM_CARDTYPE_B1;
399 strcpy(dev->node.dev_name, "b1");
400 cardtype = AVM_CARDTYPE_B1;
403 dev->node.major = 64;
405 link->dev = &dev->node;
407 link->state &= ~DEV_CONFIG_PENDING;
408 /* If any step failed, release any partially configured state */
410 avmcs_release((u_long)link);
416 case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
417 case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
419 case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
421 if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
422 printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
423 dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
424 avmcs_release((u_long)link);
431 /*======================================================================
433 After a card is removed, avmcs_release() will unregister the net
434 device, and release the PCMCIA configuration. If the device is
435 still open, this will be postponed until it is closed.
437 ======================================================================*/
439 static void avmcs_release(u_long arg)
441 dev_link_t *link = (dev_link_t *)arg;
444 If the device is currently in use, we won't release until it
448 link->state |= DEV_STALE_CONFIG;
452 b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
454 /* Unlink the device chain */
457 /* Don't bother checking to see if these succeed or not */
458 CardServices(ReleaseConfiguration, link->handle);
459 CardServices(ReleaseIO, link->handle, &link->io);
460 CardServices(ReleaseIRQ, link->handle, &link->irq);
461 link->state &= ~DEV_CONFIG;
463 if (link->state & DEV_STALE_LINK)
466 } /* avmcs_release */
468 /*======================================================================
470 The card status event handler. Mostly, this schedules other
471 stuff to run after an event is received. A CARD_REMOVAL event
472 also sets some flags to discourage the net drivers from trying
473 to talk to the card any more.
475 When a CARD_REMOVAL event is received, we immediately set a flag
476 to block future accesses to this device. All the functions that
477 actually access the device should check this flag to make sure
478 the card is still present.
480 ======================================================================*/
482 static int avmcs_event(event_t event, int priority,
483 event_callback_args_t *args)
485 dev_link_t *link = args->client_data;
488 case CS_EVENT_CARD_REMOVAL:
489 link->state &= ~DEV_PRESENT;
490 if (link->state & DEV_CONFIG) {
491 link->release.expires = jiffies + (HZ/20);
492 add_timer(&link->release);
495 case CS_EVENT_CARD_INSERTION:
496 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
499 case CS_EVENT_PM_SUSPEND:
500 link->state |= DEV_SUSPEND;
501 /* Fall through... */
502 case CS_EVENT_RESET_PHYSICAL:
503 if (link->state & DEV_CONFIG)
504 CardServices(ReleaseConfiguration, link->handle);
506 case CS_EVENT_PM_RESUME:
507 link->state &= ~DEV_SUSPEND;
508 /* Fall through... */
509 case CS_EVENT_CARD_RESET:
510 if (link->state & DEV_CONFIG)
511 CardServices(RequestConfiguration, link->handle, &link->conf);
517 /*====================================================================*/
519 static int __init avmcs_init(void)
522 CardServices(GetCardServicesInfo, &serv);
523 if (serv.Revision != CS_RELEASE_CODE) {
524 printk(KERN_NOTICE "avm_cs: Card Services release "
525 "does not match!\n");
528 register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach);
532 static void __exit avmcs_exit(void)
534 unregister_pccard_driver(&dev_info);
535 while (dev_list != NULL) {
536 if (dev_list->state & DEV_CONFIG)
537 avmcs_release((u_long)dev_list);
538 avmcs_detach(dev_list);
542 module_init(avmcs_init);
543 module_exit(avmcs_exit);