diff options
Diffstat (limited to 'drivers/isdn/hisax/avma1_cs.c')
-rw-r--r-- | drivers/isdn/hisax/avma1_cs.c | 150 |
1 files changed, 35 insertions, 115 deletions
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 5f5a5ae740d2..969da40c4248 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c | |||
@@ -69,8 +69,6 @@ module_param(isdnprot, int, 0); | |||
69 | 69 | ||
70 | static void avma1cs_config(dev_link_t *link); | 70 | static void avma1cs_config(dev_link_t *link); |
71 | static void avma1cs_release(dev_link_t *link); | 71 | static void avma1cs_release(dev_link_t *link); |
72 | static int avma1cs_event(event_t event, int priority, | ||
73 | event_callback_args_t *args); | ||
74 | 72 | ||
75 | /* | 73 | /* |
76 | The attach() and detach() entry points are used to create and destroy | 74 | The attach() and detach() entry points are used to create and destroy |
@@ -78,16 +76,8 @@ static int avma1cs_event(event_t event, int priority, | |||
78 | needed to manage one actual PCMCIA card. | 76 | needed to manage one actual PCMCIA card. |
79 | */ | 77 | */ |
80 | 78 | ||
81 | static dev_link_t *avma1cs_attach(void); | 79 | static void avma1cs_detach(struct pcmcia_device *p_dev); |
82 | static void avma1cs_detach(dev_link_t *); | ||
83 | 80 | ||
84 | /* | ||
85 | The dev_info variable is the "key" that is used to match up this | ||
86 | device driver with appropriate cards, through the card configuration | ||
87 | database. | ||
88 | */ | ||
89 | |||
90 | static dev_info_t dev_info = "avma1_cs"; | ||
91 | 81 | ||
92 | /* | 82 | /* |
93 | A linked list of "instances" of the skeleton device. Each actual | 83 | A linked list of "instances" of the skeleton device. Each actual |
@@ -99,15 +89,7 @@ static dev_info_t dev_info = "avma1_cs"; | |||
99 | device numbers are used to derive the corresponding array index. | 89 | device numbers are used to derive the corresponding array index. |
100 | */ | 90 | */ |
101 | 91 | ||
102 | static dev_link_t *dev_list = NULL; | ||
103 | |||
104 | /* | 92 | /* |
105 | A dev_link_t structure has fields for most things that are needed | ||
106 | to keep track of a socket, but there will usually be some device | ||
107 | specific information that also needs to be kept track of. The | ||
108 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
109 | a device-specific private data structure, like this. | ||
110 | |||
111 | A driver needs to provide a dev_node_t structure for each device | 93 | A driver needs to provide a dev_node_t structure for each device |
112 | on a card. In some cases, there is only one device per card (for | 94 | on a card. In some cases, there is only one device per card (for |
113 | example, ethernet cards, modems). In other cases, there may be | 95 | example, ethernet cards, modems). In other cases, there may be |
@@ -134,26 +116,24 @@ typedef struct local_info_t { | |||
134 | 116 | ||
135 | ======================================================================*/ | 117 | ======================================================================*/ |
136 | 118 | ||
137 | static dev_link_t *avma1cs_attach(void) | 119 | static int avma1cs_attach(struct pcmcia_device *p_dev) |
138 | { | 120 | { |
139 | client_reg_t client_reg; | ||
140 | dev_link_t *link; | 121 | dev_link_t *link; |
141 | local_info_t *local; | 122 | local_info_t *local; |
142 | int ret; | 123 | |
143 | |||
144 | DEBUG(0, "avma1cs_attach()\n"); | 124 | DEBUG(0, "avma1cs_attach()\n"); |
145 | 125 | ||
146 | /* Initialize the dev_link_t structure */ | 126 | /* Initialize the dev_link_t structure */ |
147 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 127 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
148 | if (!link) | 128 | if (!link) |
149 | return NULL; | 129 | return -ENOMEM; |
150 | memset(link, 0, sizeof(struct dev_link_t)); | 130 | memset(link, 0, sizeof(struct dev_link_t)); |
151 | 131 | ||
152 | /* Allocate space for private device-specific data */ | 132 | /* Allocate space for private device-specific data */ |
153 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 133 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
154 | if (!local) { | 134 | if (!local) { |
155 | kfree(link); | 135 | kfree(link); |
156 | return NULL; | 136 | return -ENOMEM; |
157 | } | 137 | } |
158 | memset(local, 0, sizeof(local_info_t)); | 138 | memset(local, 0, sizeof(local_info_t)); |
159 | link->priv = local; | 139 | link->priv = local; |
@@ -178,20 +158,13 @@ static dev_link_t *avma1cs_attach(void) | |||
178 | link->conf.ConfigIndex = 1; | 158 | link->conf.ConfigIndex = 1; |
179 | link->conf.Present = PRESENT_OPTION; | 159 | link->conf.Present = PRESENT_OPTION; |
180 | 160 | ||
181 | /* Register with Card Services */ | 161 | link->handle = p_dev; |
182 | link->next = dev_list; | 162 | p_dev->instance = link; |
183 | dev_list = link; | ||
184 | client_reg.dev_info = &dev_info; | ||
185 | client_reg.Version = 0x0210; | ||
186 | client_reg.event_callback_args.client_data = link; | ||
187 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
188 | if (ret != 0) { | ||
189 | cs_error(link->handle, RegisterClient, ret); | ||
190 | avma1cs_detach(link); | ||
191 | return NULL; | ||
192 | } | ||
193 | 163 | ||
194 | return link; | 164 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
165 | avma1cs_config(link); | ||
166 | |||
167 | return 0; | ||
195 | } /* avma1cs_attach */ | 168 | } /* avma1cs_attach */ |
196 | 169 | ||
197 | /*====================================================================== | 170 | /*====================================================================== |
@@ -203,42 +176,17 @@ static dev_link_t *avma1cs_attach(void) | |||
203 | 176 | ||
204 | ======================================================================*/ | 177 | ======================================================================*/ |
205 | 178 | ||
206 | static void avma1cs_detach(dev_link_t *link) | 179 | static void avma1cs_detach(struct pcmcia_device *p_dev) |
207 | { | 180 | { |
208 | dev_link_t **linkp; | 181 | dev_link_t *link = dev_to_instance(p_dev); |
209 | 182 | ||
210 | DEBUG(0, "avma1cs_detach(0x%p)\n", link); | 183 | DEBUG(0, "avma1cs_detach(0x%p)\n", link); |
211 | |||
212 | /* Locate device structure */ | ||
213 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
214 | if (*linkp == link) break; | ||
215 | if (*linkp == NULL) | ||
216 | return; | ||
217 | 184 | ||
218 | /* | 185 | if (link->state & DEV_CONFIG) |
219 | If the device is currently configured and active, we won't | 186 | avma1cs_release(link); |
220 | actually delete it yet. Instead, it is marked so that when | ||
221 | the release() function is called, that will trigger a proper | ||
222 | detach(). | ||
223 | */ | ||
224 | if (link->state & DEV_CONFIG) { | ||
225 | #ifdef PCMCIA_DEBUG | ||
226 | printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' " | ||
227 | "still locked\n", link->dev->dev_name); | ||
228 | #endif | ||
229 | link->state |= DEV_STALE_LINK; | ||
230 | return; | ||
231 | } | ||
232 | 187 | ||
233 | /* Break the link with Card Services */ | ||
234 | if (link->handle) | ||
235 | pcmcia_deregister_client(link->handle); | ||
236 | |||
237 | /* Unlink device structure, free pieces */ | ||
238 | *linkp = link->next; | ||
239 | kfree(link->priv); | 188 | kfree(link->priv); |
240 | kfree(link); | 189 | kfree(link); |
241 | |||
242 | } /* avma1cs_detach */ | 190 | } /* avma1cs_detach */ |
243 | 191 | ||
244 | /*====================================================================== | 192 | /*====================================================================== |
@@ -440,58 +388,30 @@ static void avma1cs_release(dev_link_t *link) | |||
440 | pcmcia_release_io(link->handle, &link->io); | 388 | pcmcia_release_io(link->handle, &link->io); |
441 | pcmcia_release_irq(link->handle, &link->irq); | 389 | pcmcia_release_irq(link->handle, &link->irq); |
442 | link->state &= ~DEV_CONFIG; | 390 | link->state &= ~DEV_CONFIG; |
443 | |||
444 | if (link->state & DEV_STALE_LINK) | ||
445 | avma1cs_detach(link); | ||
446 | } /* avma1cs_release */ | 391 | } /* avma1cs_release */ |
447 | 392 | ||
448 | /*====================================================================== | 393 | static int avma1cs_suspend(struct pcmcia_device *dev) |
394 | { | ||
395 | dev_link_t *link = dev_to_instance(dev); | ||
449 | 396 | ||
450 | The card status event handler. Mostly, this schedules other | 397 | link->state |= DEV_SUSPEND; |
451 | stuff to run after an event is received. A CARD_REMOVAL event | 398 | if (link->state & DEV_CONFIG) |
452 | also sets some flags to discourage the net drivers from trying | 399 | pcmcia_release_configuration(link->handle); |
453 | to talk to the card any more. | ||
454 | 400 | ||
455 | When a CARD_REMOVAL event is received, we immediately set a flag | 401 | return 0; |
456 | to block future accesses to this device. All the functions that | 402 | } |
457 | actually access the device should check this flag to make sure | ||
458 | the card is still present. | ||
459 | |||
460 | ======================================================================*/ | ||
461 | 403 | ||
462 | static int avma1cs_event(event_t event, int priority, | 404 | static int avma1cs_resume(struct pcmcia_device *dev) |
463 | event_callback_args_t *args) | ||
464 | { | 405 | { |
465 | dev_link_t *link = args->client_data; | 406 | dev_link_t *link = dev_to_instance(dev); |
466 | 407 | ||
467 | DEBUG(1, "avma1cs_event(0x%06x)\n", event); | 408 | link->state &= ~DEV_SUSPEND; |
468 | 409 | if (link->state & DEV_CONFIG) | |
469 | switch (event) { | ||
470 | case CS_EVENT_CARD_REMOVAL: | ||
471 | if (link->state & DEV_CONFIG) | ||
472 | avma1cs_release(link); | ||
473 | break; | ||
474 | case CS_EVENT_CARD_INSERTION: | ||
475 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
476 | avma1cs_config(link); | ||
477 | break; | ||
478 | case CS_EVENT_PM_SUSPEND: | ||
479 | link->state |= DEV_SUSPEND; | ||
480 | /* Fall through... */ | ||
481 | case CS_EVENT_RESET_PHYSICAL: | ||
482 | if (link->state & DEV_CONFIG) | ||
483 | pcmcia_release_configuration(link->handle); | ||
484 | break; | ||
485 | case CS_EVENT_PM_RESUME: | ||
486 | link->state &= ~DEV_SUSPEND; | ||
487 | /* Fall through... */ | ||
488 | case CS_EVENT_CARD_RESET: | ||
489 | if (link->state & DEV_CONFIG) | ||
490 | pcmcia_request_configuration(link->handle, &link->conf); | 410 | pcmcia_request_configuration(link->handle, &link->conf); |
491 | break; | 411 | |
492 | } | 412 | return 0; |
493 | return 0; | 413 | } |
494 | } /* avma1cs_event */ | 414 | |
495 | 415 | ||
496 | static struct pcmcia_device_id avma1cs_ids[] = { | 416 | static struct pcmcia_device_id avma1cs_ids[] = { |
497 | PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), | 417 | PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), |
@@ -505,10 +425,11 @@ static struct pcmcia_driver avma1cs_driver = { | |||
505 | .drv = { | 425 | .drv = { |
506 | .name = "avma1_cs", | 426 | .name = "avma1_cs", |
507 | }, | 427 | }, |
508 | .attach = avma1cs_attach, | 428 | .probe = avma1cs_attach, |
509 | .event = avma1cs_event, | 429 | .remove = avma1cs_detach, |
510 | .detach = avma1cs_detach, | ||
511 | .id_table = avma1cs_ids, | 430 | .id_table = avma1cs_ids, |
431 | .suspend = avma1cs_suspend, | ||
432 | .resume = avma1cs_resume, | ||
512 | }; | 433 | }; |
513 | 434 | ||
514 | /*====================================================================*/ | 435 | /*====================================================================*/ |
@@ -521,7 +442,6 @@ static int __init init_avma1_cs(void) | |||
521 | static void __exit exit_avma1_cs(void) | 442 | static void __exit exit_avma1_cs(void) |
522 | { | 443 | { |
523 | pcmcia_unregister_driver(&avma1cs_driver); | 444 | pcmcia_unregister_driver(&avma1cs_driver); |
524 | BUG_ON(dev_list != NULL); | ||
525 | } | 445 | } |
526 | 446 | ||
527 | module_init(init_avma1_cs); | 447 | module_init(init_avma1_cs); |