aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hardware/avm/avm_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hardware/avm/avm_cs.c')
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c145
1 files changed, 42 insertions, 103 deletions
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 27391c32f3eb..2a2b03ff096b 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -53,8 +53,6 @@ MODULE_LICENSE("GPL");
53 53
54static void avmcs_config(dev_link_t *link); 54static void avmcs_config(dev_link_t *link);
55static void avmcs_release(dev_link_t *link); 55static void avmcs_release(dev_link_t *link);
56static int avmcs_event(event_t event, int priority,
57 event_callback_args_t *args);
58 56
59/* 57/*
60 The attach() and detach() entry points are used to create and destroy 58 The attach() and detach() entry points are used to create and destroy
@@ -62,16 +60,7 @@ static int avmcs_event(event_t event, int priority,
62 needed to manage one actual PCMCIA card. 60 needed to manage one actual PCMCIA card.
63*/ 61*/
64 62
65static dev_link_t *avmcs_attach(void); 63static void avmcs_detach(struct pcmcia_device *p_dev);
66static void avmcs_detach(dev_link_t *);
67
68/*
69 The dev_info variable is the "key" that is used to match up this
70 device driver with appropriate cards, through the card configuration
71 database.
72*/
73
74static dev_info_t dev_info = "avm_cs";
75 64
76/* 65/*
77 A linked list of "instances" of the skeleton device. Each actual 66 A linked list of "instances" of the skeleton device. Each actual
@@ -83,15 +72,7 @@ static dev_info_t dev_info = "avm_cs";
83 device numbers are used to derive the corresponding array index. 72 device numbers are used to derive the corresponding array index.
84*/ 73*/
85 74
86static dev_link_t *dev_list = NULL;
87
88/* 75/*
89 A dev_link_t structure has fields for most things that are needed
90 to keep track of a socket, but there will usually be some device
91 specific information that also needs to be kept track of. The
92 'priv' pointer in a dev_link_t structure can be used to point to
93 a device-specific private data structure, like this.
94
95 A driver needs to provide a dev_node_t structure for each device 76 A driver needs to provide a dev_node_t structure for each device
96 on a card. In some cases, there is only one device per card (for 77 on a card. In some cases, there is only one device per card (for
97 example, ethernet cards, modems). In other cases, there may be 78 example, ethernet cards, modems). In other cases, there may be
@@ -118,13 +99,11 @@ typedef struct local_info_t {
118 99
119======================================================================*/ 100======================================================================*/
120 101
121static dev_link_t *avmcs_attach(void) 102static int avmcs_attach(struct pcmcia_device *p_dev)
122{ 103{
123 client_reg_t client_reg;
124 dev_link_t *link; 104 dev_link_t *link;
125 local_info_t *local; 105 local_info_t *local;
126 int ret; 106
127
128 /* Initialize the dev_link_t structure */ 107 /* Initialize the dev_link_t structure */
129 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); 108 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
130 if (!link) 109 if (!link)
@@ -155,25 +134,19 @@ static dev_link_t *avmcs_attach(void)
155 goto err_kfree; 134 goto err_kfree;
156 memset(local, 0, sizeof(local_info_t)); 135 memset(local, 0, sizeof(local_info_t));
157 link->priv = local; 136 link->priv = local;
158 137
159 /* Register with Card Services */ 138 link->handle = p_dev;
160 link->next = dev_list; 139 p_dev->instance = link;
161 dev_list = link; 140
162 client_reg.dev_info = &dev_info; 141 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
163 client_reg.Version = 0x0210; 142 avmcs_config(link);
164 client_reg.event_callback_args.client_data = link; 143
165 ret = pcmcia_register_client(&link->handle, &client_reg); 144 return 0;
166 if (ret != 0) {
167 cs_error(link->handle, RegisterClient, ret);
168 avmcs_detach(link);
169 goto err;
170 }
171 return link;
172 145
173 err_kfree: 146 err_kfree:
174 kfree(link); 147 kfree(link);
175 err: 148 err:
176 return NULL; 149 return -EINVAL;
177} /* avmcs_attach */ 150} /* avmcs_attach */
178 151
179/*====================================================================== 152/*======================================================================
@@ -185,33 +158,13 @@ static dev_link_t *avmcs_attach(void)
185 158
186======================================================================*/ 159======================================================================*/
187 160
188static void avmcs_detach(dev_link_t *link) 161static void avmcs_detach(struct pcmcia_device *p_dev)
189{ 162{
190 dev_link_t **linkp; 163 dev_link_t *link = dev_to_instance(p_dev);
191
192 /* Locate device structure */
193 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
194 if (*linkp == link) break;
195 if (*linkp == NULL)
196 return;
197 164
198 /* 165 if (link->state & DEV_CONFIG)
199 If the device is currently configured and active, we won't 166 avmcs_release(link);
200 actually delete it yet. Instead, it is marked so that when
201 the release() function is called, that will trigger a proper
202 detach().
203 */
204 if (link->state & DEV_CONFIG) {
205 link->state |= DEV_STALE_LINK;
206 return;
207 }
208 167
209 /* Break the link with Card Services */
210 if (link->handle)
211 pcmcia_deregister_client(link->handle);
212
213 /* Unlink device structure, free pieces */
214 *linkp = link->next;
215 kfree(link->priv); 168 kfree(link->priv);
216 kfree(link); 169 kfree(link);
217} /* avmcs_detach */ 170} /* avmcs_detach */
@@ -424,12 +377,30 @@ static void avmcs_release(dev_link_t *link)
424 pcmcia_release_io(link->handle, &link->io); 377 pcmcia_release_io(link->handle, &link->io);
425 pcmcia_release_irq(link->handle, &link->irq); 378 pcmcia_release_irq(link->handle, &link->irq);
426 link->state &= ~DEV_CONFIG; 379 link->state &= ~DEV_CONFIG;
427
428 if (link->state & DEV_STALE_LINK)
429 avmcs_detach(link);
430
431} /* avmcs_release */ 380} /* avmcs_release */
432 381
382static int avmcs_suspend(struct pcmcia_device *dev)
383{
384 dev_link_t *link = dev_to_instance(dev);
385
386 link->state |= DEV_SUSPEND;
387 if (link->state & DEV_CONFIG)
388 pcmcia_release_configuration(link->handle);
389
390 return 0;
391}
392
393static int avmcs_resume(struct pcmcia_device *dev)
394{
395 dev_link_t *link = dev_to_instance(dev);
396
397 link->state &= ~DEV_SUSPEND;
398 if (link->state & DEV_CONFIG)
399 pcmcia_request_configuration(link->handle, &link->conf);
400
401 return 0;
402}
403
433/*====================================================================== 404/*======================================================================
434 405
435 The card status event handler. Mostly, this schedules other 406 The card status event handler. Mostly, this schedules other
@@ -444,38 +415,6 @@ static void avmcs_release(dev_link_t *link)
444 415
445======================================================================*/ 416======================================================================*/
446 417
447static int avmcs_event(event_t event, int priority,
448 event_callback_args_t *args)
449{
450 dev_link_t *link = args->client_data;
451
452 switch (event) {
453 case CS_EVENT_CARD_REMOVAL:
454 link->state &= ~DEV_PRESENT;
455 if (link->state & DEV_CONFIG)
456 avmcs_release(link);
457 break;
458 case CS_EVENT_CARD_INSERTION:
459 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
460 avmcs_config(link);
461 break;
462 case CS_EVENT_PM_SUSPEND:
463 link->state |= DEV_SUSPEND;
464 /* Fall through... */
465 case CS_EVENT_RESET_PHYSICAL:
466 if (link->state & DEV_CONFIG)
467 pcmcia_release_configuration(link->handle);
468 break;
469 case CS_EVENT_PM_RESUME:
470 link->state &= ~DEV_SUSPEND;
471 /* Fall through... */
472 case CS_EVENT_CARD_RESET:
473 if (link->state & DEV_CONFIG)
474 pcmcia_request_configuration(link->handle, &link->conf);
475 break;
476 }
477 return 0;
478} /* avmcs_event */
479 418
480static struct pcmcia_device_id avmcs_ids[] = { 419static struct pcmcia_device_id avmcs_ids[] = {
481 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), 420 PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
@@ -490,10 +429,11 @@ static struct pcmcia_driver avmcs_driver = {
490 .drv = { 429 .drv = {
491 .name = "avm_cs", 430 .name = "avm_cs",
492 }, 431 },
493 .attach = avmcs_attach, 432 .probe = avmcs_attach,
494 .event = avmcs_event, 433 .remove = avmcs_detach,
495 .detach = avmcs_detach,
496 .id_table = avmcs_ids, 434 .id_table = avmcs_ids,
435 .suspend= avmcs_suspend,
436 .resume = avmcs_resume,
497}; 437};
498 438
499static int __init avmcs_init(void) 439static int __init avmcs_init(void)
@@ -504,7 +444,6 @@ static int __init avmcs_init(void)
504static void __exit avmcs_exit(void) 444static void __exit avmcs_exit(void)
505{ 445{
506 pcmcia_unregister_driver(&avmcs_driver); 446 pcmcia_unregister_driver(&avmcs_driver);
507 BUG_ON(dev_list != NULL);
508} 447}
509 448
510module_init(avmcs_init); 449module_init(avmcs_init);