aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax/avma1_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hisax/avma1_cs.c')
-rw-r--r--drivers/isdn/hisax/avma1_cs.c150
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
70static void avma1cs_config(dev_link_t *link); 70static void avma1cs_config(dev_link_t *link);
71static void avma1cs_release(dev_link_t *link); 71static void avma1cs_release(dev_link_t *link);
72static 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
81static dev_link_t *avma1cs_attach(void); 79static void avma1cs_detach(struct pcmcia_device *p_dev);
82static 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
90static 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
102static 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
137static dev_link_t *avma1cs_attach(void) 119static 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
206static void avma1cs_detach(dev_link_t *link) 179static 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/*====================================================================== 393static 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
462static int avma1cs_event(event_t event, int priority, 404static 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
496static struct pcmcia_device_id avma1cs_ids[] = { 416static 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)
521static void __exit exit_avma1_cs(void) 442static 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
527module_init(init_avma1_cs); 447module_init(init_avma1_cs);