[PATCH] fix semaphore handling in __unregister_chrdev_region
[linux/fpc-iii.git] / drivers / isdn / hisax / avma1_cs.c
blob663a0bf703b707b6fcc2c6ebfa2de1cbbd409605
1 /*
2 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
4 * Author Carsten Paeth
5 * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
6 *
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>
21 #include <asm/io.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.
42 #ifdef PCMCIA_DEBUG
43 static int pc_debug = PCMCIA_DEBUG;
44 module_param(pc_debug, int, 0);
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)";
48 #else
49 #define DEBUG(n, args...)
50 #endif
52 /*====================================================================*/
54 /* Parameters that can be set with 'insmod' */
56 static int isdnprot = 2;
58 module_param(isdnprot, int, 0);
60 /*====================================================================*/
63 The event() function is this driver's Card Services event handler.
64 It will be called by Card Services when an appropriate card status
65 event is received. The config() and release() entry points are
66 used to configure or release a socket, in response to card insertion
67 and ejection events. They are invoked from the skeleton event
68 handler.
71 static void avma1cs_config(dev_link_t *link);
72 static void avma1cs_release(dev_link_t *link);
73 static int avma1cs_event(event_t event, int priority,
74 event_callback_args_t *args);
77 The attach() and detach() entry points are used to create and destroy
78 "instances" of the driver, where each instance represents everything
79 needed to manage one actual PCMCIA card.
82 static dev_link_t *avma1cs_attach(void);
83 static void avma1cs_detach(dev_link_t *);
86 The dev_info variable is the "key" that is used to match up this
87 device driver with appropriate cards, through the card configuration
88 database.
91 static dev_info_t dev_info = "avma1_cs";
94 A linked list of "instances" of the skeleton device. Each actual
95 PCMCIA card corresponds to one device instance, and is described
96 by one dev_link_t structure (defined in ds.h).
98 You may not want to use a linked list for this -- for example, the
99 memory card driver uses an array of dev_link_t pointers, where minor
100 device numbers are used to derive the corresponding array index.
103 static dev_link_t *dev_list = NULL;
106 A dev_link_t structure has fields for most things that are needed
107 to keep track of a socket, but there will usually be some device
108 specific information that also needs to be kept track of. The
109 'priv' pointer in a dev_link_t structure can be used to point to
110 a device-specific private data structure, like this.
112 A driver needs to provide a dev_node_t structure for each device
113 on a card. In some cases, there is only one device per card (for
114 example, ethernet cards, modems). In other cases, there may be
115 many actual or logical devices (SCSI adapters, memory cards with
116 multiple partitions). The dev_node_t structures need to be kept
117 in a linked list starting at the 'dev' field of a dev_link_t
118 structure. We allocate them in the card's private data structure,
119 because they generally can't be allocated dynamically.
122 typedef struct local_info_t {
123 dev_node_t node;
124 } local_info_t;
126 /*======================================================================
128 avma1cs_attach() creates an "instance" of the driver, allocating
129 local data structures for one device. The device is registered
130 with Card Services.
132 The dev_link structure is initialized, but we don't actually
133 configure the card at this point -- we wait until we receive a
134 card insertion event.
136 ======================================================================*/
138 static dev_link_t *avma1cs_attach(void)
140 client_reg_t client_reg;
141 dev_link_t *link;
142 local_info_t *local;
143 int ret;
145 DEBUG(0, "avma1cs_attach()\n");
147 /* Initialize the dev_link_t structure */
148 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
149 if (!link)
150 return NULL;
151 memset(link, 0, sizeof(struct dev_link_t));
153 /* Allocate space for private device-specific data */
154 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
155 if (!local) {
156 kfree(link);
157 return NULL;
159 memset(local, 0, sizeof(local_info_t));
160 link->priv = local;
162 /* The io structure describes IO port mapping */
163 link->io.NumPorts1 = 16;
164 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
165 link->io.NumPorts2 = 16;
166 link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
167 link->io.IOAddrLines = 5;
169 /* Interrupt setup */
170 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
171 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
173 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
175 /* General socket configuration */
176 link->conf.Attributes = CONF_ENABLE_IRQ;
177 link->conf.Vcc = 50;
178 link->conf.IntType = INT_MEMORY_AND_IO;
179 link->conf.ConfigIndex = 1;
180 link->conf.Present = PRESENT_OPTION;
182 /* Register with Card Services */
183 link->next = dev_list;
184 dev_list = link;
185 client_reg.dev_info = &dev_info;
186 client_reg.EventMask =
187 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
188 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
189 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
190 client_reg.event_handler = &avma1cs_event;
191 client_reg.Version = 0x0210;
192 client_reg.event_callback_args.client_data = link;
193 ret = pcmcia_register_client(&link->handle, &client_reg);
194 if (ret != 0) {
195 cs_error(link->handle, RegisterClient, ret);
196 avma1cs_detach(link);
197 return NULL;
200 return link;
201 } /* avma1cs_attach */
203 /*======================================================================
205 This deletes a driver "instance". The device is de-registered
206 with Card Services. If it has been released, all local data
207 structures are freed. Otherwise, the structures will be freed
208 when the device is released.
210 ======================================================================*/
212 static void avma1cs_detach(dev_link_t *link)
214 dev_link_t **linkp;
216 DEBUG(0, "avma1cs_detach(0x%p)\n", link);
218 /* Locate device structure */
219 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
220 if (*linkp == link) break;
221 if (*linkp == NULL)
222 return;
225 If the device is currently configured and active, we won't
226 actually delete it yet. Instead, it is marked so that when
227 the release() function is called, that will trigger a proper
228 detach().
230 if (link->state & DEV_CONFIG) {
231 #ifdef PCMCIA_DEBUG
232 printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' "
233 "still locked\n", link->dev->dev_name);
234 #endif
235 link->state |= DEV_STALE_LINK;
236 return;
239 /* Break the link with Card Services */
240 if (link->handle)
241 pcmcia_deregister_client(link->handle);
243 /* Unlink device structure, free pieces */
244 *linkp = link->next;
245 if (link->priv) {
246 kfree(link->priv);
248 kfree(link);
250 } /* avma1cs_detach */
252 /*======================================================================
254 avma1cs_config() is scheduled to run after a CARD_INSERTION event
255 is received, to configure the PCMCIA socket, and to make the
256 ethernet device available to the system.
258 ======================================================================*/
260 static int get_tuple(client_handle_t handle, tuple_t *tuple,
261 cisparse_t *parse)
263 int i = pcmcia_get_tuple_data(handle, tuple);
264 if (i != CS_SUCCESS) return i;
265 return pcmcia_parse_tuple(handle, tuple, parse);
268 static int first_tuple(client_handle_t handle, tuple_t *tuple,
269 cisparse_t *parse)
271 int i = pcmcia_get_first_tuple(handle, tuple);
272 if (i != CS_SUCCESS) return i;
273 return get_tuple(handle, tuple, parse);
276 static int next_tuple(client_handle_t handle, tuple_t *tuple,
277 cisparse_t *parse)
279 int i = pcmcia_get_next_tuple(handle, tuple);
280 if (i != CS_SUCCESS) return i;
281 return get_tuple(handle, tuple, parse);
284 static void avma1cs_config(dev_link_t *link)
286 client_handle_t handle;
287 tuple_t tuple;
288 cisparse_t parse;
289 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
290 local_info_t *dev;
291 int i;
292 u_char buf[64];
293 char devname[128];
294 IsdnCard_t icard;
295 int busy = 0;
297 handle = link->handle;
298 dev = link->priv;
300 DEBUG(0, "avma1cs_config(0x%p)\n", link);
303 This reads the card's CONFIG tuple to find its configuration
304 registers.
306 do {
307 tuple.DesiredTuple = CISTPL_CONFIG;
308 i = pcmcia_get_first_tuple(handle, &tuple);
309 if (i != CS_SUCCESS) break;
310 tuple.TupleData = buf;
311 tuple.TupleDataMax = 64;
312 tuple.TupleOffset = 0;
313 i = pcmcia_get_tuple_data(handle, &tuple);
314 if (i != CS_SUCCESS) break;
315 i = pcmcia_parse_tuple(handle, &tuple, &parse);
316 if (i != CS_SUCCESS) break;
317 link->conf.ConfigBase = parse.config.base;
318 } while (0);
319 if (i != CS_SUCCESS) {
320 cs_error(link->handle, ParseTuple, i);
321 link->state &= ~DEV_CONFIG_PENDING;
322 return;
325 /* Configure card */
326 link->state |= DEV_CONFIG;
328 do {
330 tuple.Attributes = 0;
331 tuple.TupleData = buf;
332 tuple.TupleDataMax = 254;
333 tuple.TupleOffset = 0;
334 tuple.DesiredTuple = CISTPL_VERS_1;
336 devname[0] = 0;
337 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
338 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
339 sizeof(devname));
342 * find IO port
344 tuple.TupleData = (cisdata_t *)buf;
345 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
346 tuple.Attributes = 0;
347 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
348 i = first_tuple(handle, &tuple, &parse);
349 while (i == CS_SUCCESS) {
350 if (cf->io.nwin > 0) {
351 link->conf.ConfigIndex = cf->index;
352 link->io.BasePort1 = cf->io.win[0].base;
353 link->io.NumPorts1 = cf->io.win[0].len;
354 link->io.NumPorts2 = 0;
355 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
356 link->io.BasePort1,
357 link->io.BasePort1+link->io.NumPorts1 - 1);
358 i = pcmcia_request_io(link->handle, &link->io);
359 if (i == CS_SUCCESS) goto found_port;
361 i = next_tuple(handle, &tuple, &parse);
364 found_port:
365 if (i != CS_SUCCESS) {
366 cs_error(link->handle, RequestIO, i);
367 break;
371 * allocate an interrupt line
373 i = pcmcia_request_irq(link->handle, &link->irq);
374 if (i != CS_SUCCESS) {
375 cs_error(link->handle, RequestIRQ, i);
376 pcmcia_release_io(link->handle, &link->io);
377 break;
381 * configure the PCMCIA socket
383 i = pcmcia_request_configuration(link->handle, &link->conf);
384 if (i != CS_SUCCESS) {
385 cs_error(link->handle, RequestConfiguration, i);
386 pcmcia_release_io(link->handle, &link->io);
387 pcmcia_release_irq(link->handle, &link->irq);
388 break;
391 } while (0);
393 /* At this point, the dev_node_t structure(s) should be
394 initialized and arranged in a linked list at link->dev. */
396 strcpy(dev->node.dev_name, "A1");
397 dev->node.major = 45;
398 dev->node.minor = 0;
399 link->dev = &dev->node;
401 link->state &= ~DEV_CONFIG_PENDING;
402 /* If any step failed, release any partially configured state */
403 if (i != 0) {
404 avma1cs_release(link);
405 return;
408 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
409 link->io.BasePort1, link->irq.AssignedIRQ);
411 icard.para[0] = link->irq.AssignedIRQ;
412 icard.para[1] = link->io.BasePort1;
413 icard.protocol = isdnprot;
414 icard.typ = ISDN_CTYPE_A1_PCMCIA;
416 i = hisax_init_pcmcia(link, &busy, &icard);
417 if (i < 0) {
418 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
419 avma1cs_release(link);
420 return;
422 dev->node.minor = i;
424 } /* avma1cs_config */
426 /*======================================================================
428 After a card is removed, avma1cs_release() will unregister the net
429 device, and release the PCMCIA configuration. If the device is
430 still open, this will be postponed until it is closed.
432 ======================================================================*/
434 static void avma1cs_release(dev_link_t *link)
436 local_info_t *local = link->priv;
438 DEBUG(0, "avma1cs_release(0x%p)\n", link);
440 /* no unregister function with hisax */
441 HiSax_closecard(local->node.minor);
443 /* Unlink the device chain */
444 link->dev = NULL;
446 /* Don't bother checking to see if these succeed or not */
447 pcmcia_release_configuration(link->handle);
448 pcmcia_release_io(link->handle, &link->io);
449 pcmcia_release_irq(link->handle, &link->irq);
450 link->state &= ~DEV_CONFIG;
452 if (link->state & DEV_STALE_LINK)
453 avma1cs_detach(link);
454 } /* avma1cs_release */
456 /*======================================================================
458 The card status event handler. Mostly, this schedules other
459 stuff to run after an event is received. A CARD_REMOVAL event
460 also sets some flags to discourage the net drivers from trying
461 to talk to the card any more.
463 When a CARD_REMOVAL event is received, we immediately set a flag
464 to block future accesses to this device. All the functions that
465 actually access the device should check this flag to make sure
466 the card is still present.
468 ======================================================================*/
470 static int avma1cs_event(event_t event, int priority,
471 event_callback_args_t *args)
473 dev_link_t *link = args->client_data;
475 DEBUG(1, "avma1cs_event(0x%06x)\n", event);
477 switch (event) {
478 case CS_EVENT_CARD_REMOVAL:
479 if (link->state & DEV_CONFIG)
480 avma1cs_release(link);
481 break;
482 case CS_EVENT_CARD_INSERTION:
483 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
484 avma1cs_config(link);
485 break;
486 case CS_EVENT_PM_SUSPEND:
487 link->state |= DEV_SUSPEND;
488 /* Fall through... */
489 case CS_EVENT_RESET_PHYSICAL:
490 if (link->state & DEV_CONFIG)
491 pcmcia_release_configuration(link->handle);
492 break;
493 case CS_EVENT_PM_RESUME:
494 link->state &= ~DEV_SUSPEND;
495 /* Fall through... */
496 case CS_EVENT_CARD_RESET:
497 if (link->state & DEV_CONFIG)
498 pcmcia_request_configuration(link->handle, &link->conf);
499 break;
501 return 0;
502 } /* avma1cs_event */
504 static struct pcmcia_driver avma1cs_driver = {
505 .owner = THIS_MODULE,
506 .drv = {
507 .name = "avma1_cs",
509 .attach = avma1cs_attach,
510 .detach = avma1cs_detach,
513 /*====================================================================*/
515 static int __init init_avma1_cs(void)
517 return(pcmcia_register_driver(&avma1cs_driver));
520 static void __exit exit_avma1_cs(void)
522 pcmcia_unregister_driver(&avma1cs_driver);
523 BUG_ON(dev_list != NULL);
526 module_init(init_avma1_cs);
527 module_exit(exit_avma1_cs);