diff options
Diffstat (limited to 'drivers/isdn/hardware/avm/avm_cs.c')
-rw-r--r-- | drivers/isdn/hardware/avm/avm_cs.c | 145 |
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 | ||
54 | static void avmcs_config(dev_link_t *link); | 54 | static void avmcs_config(dev_link_t *link); |
55 | static void avmcs_release(dev_link_t *link); | 55 | static void avmcs_release(dev_link_t *link); |
56 | static 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 | ||
65 | static dev_link_t *avmcs_attach(void); | 63 | static void avmcs_detach(struct pcmcia_device *p_dev); |
66 | static 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 | |||
74 | static 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 | ||
86 | static 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 | ||
121 | static dev_link_t *avmcs_attach(void) | 102 | static 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 | ||
188 | static void avmcs_detach(dev_link_t *link) | 161 | static 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 | ||
382 | static 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 | |||
393 | static 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 | ||
447 | static 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 | ||
480 | static struct pcmcia_device_id avmcs_ids[] = { | 419 | static 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 | ||
499 | static int __init avmcs_init(void) | 439 | static int __init avmcs_init(void) |
@@ -504,7 +444,6 @@ static int __init avmcs_init(void) | |||
504 | static void __exit avmcs_exit(void) | 444 | static 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 | ||
510 | module_init(avmcs_init); | 449 | module_init(avmcs_init); |