diff options
Diffstat (limited to 'drivers/isdn/hisax/elsa_cs.c')
-rw-r--r-- | drivers/isdn/hisax/elsa_cs.c | 158 |
1 files changed, 37 insertions, 121 deletions
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 6fc6868de0b0..062fb8f0739f 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c | |||
@@ -96,8 +96,6 @@ module_param(protocol, int, 0); | |||
96 | 96 | ||
97 | static void elsa_cs_config(dev_link_t *link); | 97 | static void elsa_cs_config(dev_link_t *link); |
98 | static void elsa_cs_release(dev_link_t *link); | 98 | static void elsa_cs_release(dev_link_t *link); |
99 | static int elsa_cs_event(event_t event, int priority, | ||
100 | event_callback_args_t *args); | ||
101 | 99 | ||
102 | /* | 100 | /* |
103 | The attach() and detach() entry points are used to create and destroy | 101 | The attach() and detach() entry points are used to create and destroy |
@@ -105,39 +103,9 @@ static int elsa_cs_event(event_t event, int priority, | |||
105 | needed to manage one actual PCMCIA card. | 103 | needed to manage one actual PCMCIA card. |
106 | */ | 104 | */ |
107 | 105 | ||
108 | static dev_link_t *elsa_cs_attach(void); | 106 | static void elsa_cs_detach(struct pcmcia_device *p_dev); |
109 | static void elsa_cs_detach(dev_link_t *); | ||
110 | 107 | ||
111 | /* | 108 | /* |
112 | The dev_info variable is the "key" that is used to match up this | ||
113 | device driver with appropriate cards, through the card configuration | ||
114 | database. | ||
115 | */ | ||
116 | |||
117 | static dev_info_t dev_info = "elsa_cs"; | ||
118 | |||
119 | /* | ||
120 | A linked list of "instances" of the elsa_cs device. Each actual | ||
121 | PCMCIA card corresponds to one device instance, and is described | ||
122 | by one dev_link_t structure (defined in ds.h). | ||
123 | |||
124 | You may not want to use a linked list for this -- for example, the | ||
125 | memory card driver uses an array of dev_link_t pointers, where minor | ||
126 | device numbers are used to derive the corresponding array index. | ||
127 | */ | ||
128 | |||
129 | static dev_link_t *dev_list = NULL; | ||
130 | |||
131 | /* | ||
132 | A dev_link_t structure has fields for most things that are needed | ||
133 | to keep track of a socket, but there will usually be some device | ||
134 | specific information that also needs to be kept track of. The | ||
135 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
136 | a device-specific private data structure, like this. | ||
137 | |||
138 | To simplify the data structure handling, we actually include the | ||
139 | dev_link_t structure in the device's private data structure. | ||
140 | |||
141 | A driver needs to provide a dev_node_t structure for each device | 109 | A driver needs to provide a dev_node_t structure for each device |
142 | on a card. In some cases, there is only one device per card (for | 110 | on a card. In some cases, there is only one device per card (for |
143 | example, ethernet cards, modems). In other cases, there may be | 111 | example, ethernet cards, modems). In other cases, there may be |
@@ -171,18 +139,16 @@ typedef struct local_info_t { | |||
171 | 139 | ||
172 | ======================================================================*/ | 140 | ======================================================================*/ |
173 | 141 | ||
174 | static dev_link_t *elsa_cs_attach(void) | 142 | static int elsa_cs_attach(struct pcmcia_device *p_dev) |
175 | { | 143 | { |
176 | client_reg_t client_reg; | ||
177 | dev_link_t *link; | 144 | dev_link_t *link; |
178 | local_info_t *local; | 145 | local_info_t *local; |
179 | int ret; | ||
180 | 146 | ||
181 | DEBUG(0, "elsa_cs_attach()\n"); | 147 | DEBUG(0, "elsa_cs_attach()\n"); |
182 | 148 | ||
183 | /* Allocate space for private device-specific data */ | 149 | /* Allocate space for private device-specific data */ |
184 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 150 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
185 | if (!local) return NULL; | 151 | if (!local) return -ENOMEM; |
186 | memset(local, 0, sizeof(local_info_t)); | 152 | memset(local, 0, sizeof(local_info_t)); |
187 | local->cardnr = -1; | 153 | local->cardnr = -1; |
188 | link = &local->link; link->priv = local; | 154 | link = &local->link; link->priv = local; |
@@ -207,20 +173,13 @@ static dev_link_t *elsa_cs_attach(void) | |||
207 | link->conf.Vcc = 50; | 173 | link->conf.Vcc = 50; |
208 | link->conf.IntType = INT_MEMORY_AND_IO; | 174 | link->conf.IntType = INT_MEMORY_AND_IO; |
209 | 175 | ||
210 | /* Register with Card Services */ | 176 | link->handle = p_dev; |
211 | link->next = dev_list; | 177 | p_dev->instance = link; |
212 | dev_list = link; | ||
213 | client_reg.dev_info = &dev_info; | ||
214 | client_reg.Version = 0x0210; | ||
215 | client_reg.event_callback_args.client_data = link; | ||
216 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
217 | if (ret != CS_SUCCESS) { | ||
218 | cs_error(link->handle, RegisterClient, ret); | ||
219 | elsa_cs_detach(link); | ||
220 | return NULL; | ||
221 | } | ||
222 | 178 | ||
223 | return link; | 179 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
180 | elsa_cs_config(link); | ||
181 | |||
182 | return 0; | ||
224 | } /* elsa_cs_attach */ | 183 | } /* elsa_cs_attach */ |
225 | 184 | ||
226 | /*====================================================================== | 185 | /*====================================================================== |
@@ -232,32 +191,18 @@ static dev_link_t *elsa_cs_attach(void) | |||
232 | 191 | ||
233 | ======================================================================*/ | 192 | ======================================================================*/ |
234 | 193 | ||
235 | static void elsa_cs_detach(dev_link_t *link) | 194 | static void elsa_cs_detach(struct pcmcia_device *p_dev) |
236 | { | 195 | { |
237 | dev_link_t **linkp; | 196 | dev_link_t *link = dev_to_instance(p_dev); |
238 | local_info_t *info = link->priv; | 197 | local_info_t *info = link->priv; |
239 | int ret; | ||
240 | 198 | ||
241 | DEBUG(0, "elsa_cs_detach(0x%p)\n", link); | 199 | DEBUG(0, "elsa_cs_detach(0x%p)\n", link); |
242 | 200 | ||
243 | /* Locate device structure */ | 201 | if (link->state & DEV_CONFIG) { |
244 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | 202 | info->busy = 1; |
245 | if (*linkp == link) break; | 203 | elsa_cs_release(link); |
246 | if (*linkp == NULL) | ||
247 | return; | ||
248 | |||
249 | if (link->state & DEV_CONFIG) | ||
250 | elsa_cs_release(link); | ||
251 | |||
252 | /* Break the link with Card Services */ | ||
253 | if (link->handle) { | ||
254 | ret = pcmcia_deregister_client(link->handle); | ||
255 | if (ret != CS_SUCCESS) | ||
256 | cs_error(link->handle, DeregisterClient, ret); | ||
257 | } | 204 | } |
258 | 205 | ||
259 | /* Unlink device structure and free it */ | ||
260 | *linkp = link->next; | ||
261 | kfree(info); | 206 | kfree(info); |
262 | 207 | ||
263 | } /* elsa_cs_detach */ | 208 | } /* elsa_cs_detach */ |
@@ -447,60 +392,31 @@ static void elsa_cs_release(dev_link_t *link) | |||
447 | link->state &= ~DEV_CONFIG; | 392 | link->state &= ~DEV_CONFIG; |
448 | } /* elsa_cs_release */ | 393 | } /* elsa_cs_release */ |
449 | 394 | ||
450 | /*====================================================================== | 395 | static int elsa_suspend(struct pcmcia_device *p_dev) |
451 | 396 | { | |
452 | The card status event handler. Mostly, this schedules other | 397 | dev_link_t *link = dev_to_instance(p_dev); |
453 | stuff to run after an event is received. A CARD_REMOVAL event | 398 | local_info_t *dev = link->priv; |
454 | also sets some flags to discourage the net drivers from trying | ||
455 | to talk to the card any more. | ||
456 | 399 | ||
457 | When a CARD_REMOVAL event is received, we immediately set a flag | 400 | link->state |= DEV_SUSPEND; |
458 | to block future accesses to this device. All the functions that | 401 | dev->busy = 1; |
459 | actually access the device should check this flag to make sure | 402 | if (link->state & DEV_CONFIG) |
460 | the card is still present. | 403 | pcmcia_release_configuration(link->handle); |
461 | 404 | ||
462 | ======================================================================*/ | 405 | return 0; |
406 | } | ||
463 | 407 | ||
464 | static int elsa_cs_event(event_t event, int priority, | 408 | static int elsa_resume(struct pcmcia_device *p_dev) |
465 | event_callback_args_t *args) | ||
466 | { | 409 | { |
467 | dev_link_t *link = args->client_data; | 410 | dev_link_t *link = dev_to_instance(p_dev); |
468 | local_info_t *dev = link->priv; | 411 | local_info_t *dev = link->priv; |
469 | |||
470 | DEBUG(1, "elsa_cs_event(%d)\n", event); | ||
471 | 412 | ||
472 | switch (event) { | 413 | link->state &= ~DEV_SUSPEND; |
473 | case CS_EVENT_CARD_REMOVAL: | 414 | if (link->state & DEV_CONFIG) |
474 | link->state &= ~DEV_PRESENT; | 415 | pcmcia_request_configuration(link->handle, &link->conf); |
475 | if (link->state & DEV_CONFIG) { | ||
476 | ((local_info_t*)link->priv)->busy = 1; | ||
477 | elsa_cs_release(link); | ||
478 | } | ||
479 | break; | ||
480 | case CS_EVENT_CARD_INSERTION: | ||
481 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
482 | elsa_cs_config(link); | ||
483 | break; | ||
484 | case CS_EVENT_PM_SUSPEND: | ||
485 | link->state |= DEV_SUSPEND; | ||
486 | /* Fall through... */ | ||
487 | case CS_EVENT_RESET_PHYSICAL: | ||
488 | /* Mark the device as stopped, to block IO until later */ | ||
489 | dev->busy = 1; | ||
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 | dev->busy = 0; | 416 | dev->busy = 0; |
500 | break; | 417 | |
501 | } | 418 | return 0; |
502 | return 0; | 419 | } |
503 | } /* elsa_cs_event */ | ||
504 | 420 | ||
505 | static struct pcmcia_device_id elsa_ids[] = { | 421 | static struct pcmcia_device_id elsa_ids[] = { |
506 | PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257), | 422 | PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257), |
@@ -514,10 +430,11 @@ static struct pcmcia_driver elsa_cs_driver = { | |||
514 | .drv = { | 430 | .drv = { |
515 | .name = "elsa_cs", | 431 | .name = "elsa_cs", |
516 | }, | 432 | }, |
517 | .attach = elsa_cs_attach, | 433 | .probe = elsa_cs_attach, |
518 | .event = elsa_cs_event, | 434 | .remove = elsa_cs_detach, |
519 | .detach = elsa_cs_detach, | ||
520 | .id_table = elsa_ids, | 435 | .id_table = elsa_ids, |
436 | .suspend = elsa_suspend, | ||
437 | .resume = elsa_resume, | ||
521 | }; | 438 | }; |
522 | 439 | ||
523 | static int __init init_elsa_cs(void) | 440 | static int __init init_elsa_cs(void) |
@@ -528,7 +445,6 @@ static int __init init_elsa_cs(void) | |||
528 | static void __exit exit_elsa_cs(void) | 445 | static void __exit exit_elsa_cs(void) |
529 | { | 446 | { |
530 | pcmcia_unregister_driver(&elsa_cs_driver); | 447 | pcmcia_unregister_driver(&elsa_cs_driver); |
531 | BUG_ON(dev_list != NULL); | ||
532 | } | 448 | } |
533 | 449 | ||
534 | module_init(init_elsa_cs); | 450 | module_init(init_elsa_cs); |