aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax/elsa_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hisax/elsa_cs.c')
-rw-r--r--drivers/isdn/hisax/elsa_cs.c158
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
97static void elsa_cs_config(dev_link_t *link); 97static void elsa_cs_config(dev_link_t *link);
98static void elsa_cs_release(dev_link_t *link); 98static void elsa_cs_release(dev_link_t *link);
99static 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
108static dev_link_t *elsa_cs_attach(void); 106static void elsa_cs_detach(struct pcmcia_device *p_dev);
109static 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
117static 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
129static 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
174static dev_link_t *elsa_cs_attach(void) 142static 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
235static void elsa_cs_detach(dev_link_t *link) 194static 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/*====================================================================== 395static 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
464static int elsa_cs_event(event_t event, int priority, 408static 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
505static struct pcmcia_device_id elsa_ids[] = { 421static 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
523static int __init init_elsa_cs(void) 440static int __init init_elsa_cs(void)
@@ -528,7 +445,6 @@ static int __init init_elsa_cs(void)
528static void __exit exit_elsa_cs(void) 445static 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
534module_init(init_elsa_cs); 450module_init(init_elsa_cs);