diff options
Diffstat (limited to 'drivers/isdn/hisax/teles_cs.c')
-rw-r--r-- | drivers/isdn/hisax/teles_cs.c | 149 |
1 files changed, 38 insertions, 111 deletions
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 0ddef1bf778b..4e5c14c7240e 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c | |||
@@ -77,8 +77,6 @@ module_param(protocol, int, 0); | |||
77 | 77 | ||
78 | static void teles_cs_config(dev_link_t *link); | 78 | static void teles_cs_config(dev_link_t *link); |
79 | static void teles_cs_release(dev_link_t *link); | 79 | static void teles_cs_release(dev_link_t *link); |
80 | static int teles_cs_event(event_t event, int priority, | ||
81 | event_callback_args_t *args); | ||
82 | 80 | ||
83 | /* | 81 | /* |
84 | The attach() and detach() entry points are used to create and destroy | 82 | The attach() and detach() entry points are used to create and destroy |
@@ -86,16 +84,7 @@ static int teles_cs_event(event_t event, int priority, | |||
86 | needed to manage one actual PCMCIA card. | 84 | needed to manage one actual PCMCIA card. |
87 | */ | 85 | */ |
88 | 86 | ||
89 | static dev_link_t *teles_attach(void); | 87 | static void teles_detach(struct pcmcia_device *p_dev); |
90 | static void teles_detach(dev_link_t *); | ||
91 | |||
92 | /* | ||
93 | The dev_info variable is the "key" that is used to match up this | ||
94 | device driver with appropriate cards, through the card configuration | ||
95 | database. | ||
96 | */ | ||
97 | |||
98 | static dev_info_t dev_info = "teles_cs"; | ||
99 | 88 | ||
100 | /* | 89 | /* |
101 | A linked list of "instances" of the teles_cs device. Each actual | 90 | A linked list of "instances" of the teles_cs device. Each actual |
@@ -107,18 +96,7 @@ static dev_info_t dev_info = "teles_cs"; | |||
107 | device numbers are used to derive the corresponding array index. | 96 | device numbers are used to derive the corresponding array index. |
108 | */ | 97 | */ |
109 | 98 | ||
110 | static dev_link_t *dev_list = NULL; | ||
111 | |||
112 | /* | 99 | /* |
113 | A dev_link_t structure has fields for most things that are needed | ||
114 | to keep track of a socket, but there will usually be some device | ||
115 | specific information that also needs to be kept track of. The | ||
116 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
117 | a device-specific private data structure, like this. | ||
118 | |||
119 | To simplify the data structure handling, we actually include the | ||
120 | dev_link_t structure in the device's private data structure. | ||
121 | |||
122 | A driver needs to provide a dev_node_t structure for each device | 100 | A driver needs to provide a dev_node_t structure for each device |
123 | on a card. In some cases, there is only one device per card (for | 101 | on a card. In some cases, there is only one device per card (for |
124 | example, ethernet cards, modems). In other cases, there may be | 102 | example, ethernet cards, modems). In other cases, there may be |
@@ -152,18 +130,16 @@ typedef struct local_info_t { | |||
152 | 130 | ||
153 | ======================================================================*/ | 131 | ======================================================================*/ |
154 | 132 | ||
155 | static dev_link_t *teles_attach(void) | 133 | static int teles_attach(struct pcmcia_device *p_dev) |
156 | { | 134 | { |
157 | client_reg_t client_reg; | ||
158 | dev_link_t *link; | 135 | dev_link_t *link; |
159 | local_info_t *local; | 136 | local_info_t *local; |
160 | int ret; | ||
161 | 137 | ||
162 | DEBUG(0, "teles_attach()\n"); | 138 | DEBUG(0, "teles_attach()\n"); |
163 | 139 | ||
164 | /* Allocate space for private device-specific data */ | 140 | /* Allocate space for private device-specific data */ |
165 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 141 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
166 | if (!local) return NULL; | 142 | if (!local) return -ENOMEM; |
167 | memset(local, 0, sizeof(local_info_t)); | 143 | memset(local, 0, sizeof(local_info_t)); |
168 | local->cardnr = -1; | 144 | local->cardnr = -1; |
169 | link = &local->link; link->priv = local; | 145 | link = &local->link; link->priv = local; |
@@ -188,20 +164,13 @@ static dev_link_t *teles_attach(void) | |||
188 | link->conf.Vcc = 50; | 164 | link->conf.Vcc = 50; |
189 | link->conf.IntType = INT_MEMORY_AND_IO; | 165 | link->conf.IntType = INT_MEMORY_AND_IO; |
190 | 166 | ||
191 | /* Register with Card Services */ | 167 | link->handle = p_dev; |
192 | link->next = dev_list; | 168 | p_dev->instance = link; |
193 | dev_list = link; | 169 | |
194 | client_reg.dev_info = &dev_info; | 170 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
195 | client_reg.Version = 0x0210; | 171 | teles_cs_config(link); |
196 | client_reg.event_callback_args.client_data = link; | ||
197 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
198 | if (ret != CS_SUCCESS) { | ||
199 | cs_error(link->handle, RegisterClient, ret); | ||
200 | teles_detach(link); | ||
201 | return NULL; | ||
202 | } | ||
203 | 172 | ||
204 | return link; | 173 | return 0; |
205 | } /* teles_attach */ | 174 | } /* teles_attach */ |
206 | 175 | ||
207 | /*====================================================================== | 176 | /*====================================================================== |
@@ -213,32 +182,18 @@ static dev_link_t *teles_attach(void) | |||
213 | 182 | ||
214 | ======================================================================*/ | 183 | ======================================================================*/ |
215 | 184 | ||
216 | static void teles_detach(dev_link_t *link) | 185 | static void teles_detach(struct pcmcia_device *p_dev) |
217 | { | 186 | { |
218 | dev_link_t **linkp; | 187 | dev_link_t *link = dev_to_instance(p_dev); |
219 | local_info_t *info = link->priv; | 188 | local_info_t *info = link->priv; |
220 | int ret; | ||
221 | 189 | ||
222 | DEBUG(0, "teles_detach(0x%p)\n", link); | 190 | DEBUG(0, "teles_detach(0x%p)\n", link); |
223 | 191 | ||
224 | /* Locate device structure */ | 192 | if (link->state & DEV_CONFIG) { |
225 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | 193 | info->busy = 1; |
226 | if (*linkp == link) break; | 194 | teles_cs_release(link); |
227 | if (*linkp == NULL) | ||
228 | return; | ||
229 | |||
230 | if (link->state & DEV_CONFIG) | ||
231 | teles_cs_release(link); | ||
232 | |||
233 | /* Break the link with Card Services */ | ||
234 | if (link->handle) { | ||
235 | ret = pcmcia_deregister_client(link->handle); | ||
236 | if (ret != CS_SUCCESS) | ||
237 | cs_error(link->handle, DeregisterClient, ret); | ||
238 | } | 195 | } |
239 | 196 | ||
240 | /* Unlink device structure and free it */ | ||
241 | *linkp = link->next; | ||
242 | kfree(info); | 197 | kfree(info); |
243 | 198 | ||
244 | } /* teles_detach */ | 199 | } /* teles_detach */ |
@@ -428,60 +383,32 @@ static void teles_cs_release(dev_link_t *link) | |||
428 | link->state &= ~DEV_CONFIG; | 383 | link->state &= ~DEV_CONFIG; |
429 | } /* teles_cs_release */ | 384 | } /* teles_cs_release */ |
430 | 385 | ||
431 | /*====================================================================== | 386 | static int teles_suspend(struct pcmcia_device *p_dev) |
432 | 387 | { | |
433 | The card status event handler. Mostly, this schedules other | 388 | dev_link_t *link = dev_to_instance(p_dev); |
434 | stuff to run after an event is received. A CARD_REMOVAL event | 389 | local_info_t *dev = link->priv; |
435 | also sets some flags to discourage the net drivers from trying | ||
436 | to talk to the card any more. | ||
437 | 390 | ||
438 | When a CARD_REMOVAL event is received, we immediately set a flag | 391 | link->state |= DEV_SUSPEND; |
439 | to block future accesses to this device. All the functions that | 392 | dev->busy = 1; |
440 | actually access the device should check this flag to make sure | 393 | if (link->state & DEV_CONFIG) |
441 | the card is still present. | 394 | pcmcia_release_configuration(link->handle); |
442 | 395 | ||
443 | ======================================================================*/ | 396 | return 0; |
397 | } | ||
444 | 398 | ||
445 | static int teles_cs_event(event_t event, int priority, | 399 | static int teles_resume(struct pcmcia_device *p_dev) |
446 | event_callback_args_t *args) | ||
447 | { | 400 | { |
448 | dev_link_t *link = args->client_data; | 401 | dev_link_t *link = dev_to_instance(p_dev); |
449 | local_info_t *dev = link->priv; | 402 | local_info_t *dev = link->priv; |
450 | |||
451 | DEBUG(1, "teles_cs_event(%d)\n", event); | ||
452 | 403 | ||
453 | switch (event) { | 404 | link->state &= ~DEV_SUSPEND; |
454 | case CS_EVENT_CARD_REMOVAL: | 405 | if (link->state & DEV_CONFIG) |
455 | link->state &= ~DEV_PRESENT; | 406 | pcmcia_request_configuration(link->handle, &link->conf); |
456 | if (link->state & DEV_CONFIG) { | ||
457 | ((local_info_t*)link->priv)->busy = 1; | ||
458 | teles_cs_release(link); | ||
459 | } | ||
460 | break; | ||
461 | case CS_EVENT_CARD_INSERTION: | ||
462 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
463 | teles_cs_config(link); | ||
464 | break; | ||
465 | case CS_EVENT_PM_SUSPEND: | ||
466 | link->state |= DEV_SUSPEND; | ||
467 | /* Fall through... */ | ||
468 | case CS_EVENT_RESET_PHYSICAL: | ||
469 | /* Mark the device as stopped, to block IO until later */ | ||
470 | dev->busy = 1; | ||
471 | if (link->state & DEV_CONFIG) | ||
472 | pcmcia_release_configuration(link->handle); | ||
473 | break; | ||
474 | case CS_EVENT_PM_RESUME: | ||
475 | link->state &= ~DEV_SUSPEND; | ||
476 | /* Fall through... */ | ||
477 | case CS_EVENT_CARD_RESET: | ||
478 | if (link->state & DEV_CONFIG) | ||
479 | pcmcia_request_configuration(link->handle, &link->conf); | ||
480 | dev->busy = 0; | 407 | dev->busy = 0; |
481 | break; | 408 | |
482 | } | 409 | return 0; |
483 | return 0; | 410 | } |
484 | } /* teles_cs_event */ | 411 | |
485 | 412 | ||
486 | static struct pcmcia_device_id teles_ids[] = { | 413 | static struct pcmcia_device_id teles_ids[] = { |
487 | PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119), | 414 | PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119), |
@@ -494,10 +421,11 @@ static struct pcmcia_driver teles_cs_driver = { | |||
494 | .drv = { | 421 | .drv = { |
495 | .name = "teles_cs", | 422 | .name = "teles_cs", |
496 | }, | 423 | }, |
497 | .attach = teles_attach, | 424 | .probe = teles_attach, |
498 | .event = teles_cs_event, | 425 | .remove = teles_detach, |
499 | .detach = teles_detach, | ||
500 | .id_table = teles_ids, | 426 | .id_table = teles_ids, |
427 | .suspend = teles_suspend, | ||
428 | .resume = teles_resume, | ||
501 | }; | 429 | }; |
502 | 430 | ||
503 | static int __init init_teles_cs(void) | 431 | static int __init init_teles_cs(void) |
@@ -508,7 +436,6 @@ static int __init init_teles_cs(void) | |||
508 | static void __exit exit_teles_cs(void) | 436 | static void __exit exit_teles_cs(void) |
509 | { | 437 | { |
510 | pcmcia_unregister_driver(&teles_cs_driver); | 438 | pcmcia_unregister_driver(&teles_cs_driver); |
511 | BUG_ON(dev_list != NULL); | ||
512 | } | 439 | } |
513 | 440 | ||
514 | module_init(init_teles_cs); | 441 | module_init(init_teles_cs); |