aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax/teles_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hisax/teles_cs.c')
-rw-r--r--drivers/isdn/hisax/teles_cs.c149
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
78static void teles_cs_config(dev_link_t *link); 78static void teles_cs_config(dev_link_t *link);
79static void teles_cs_release(dev_link_t *link); 79static void teles_cs_release(dev_link_t *link);
80static 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
89static dev_link_t *teles_attach(void); 87static void teles_detach(struct pcmcia_device *p_dev);
90static 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
98static 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
110static 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
155static dev_link_t *teles_attach(void) 133static 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
216static void teles_detach(dev_link_t *link) 185static 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/*====================================================================== 386static 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
445static int teles_cs_event(event_t event, int priority, 399static 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
486static struct pcmcia_device_id teles_ids[] = { 413static 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
503static int __init init_teles_cs(void) 431static int __init init_teles_cs(void)
@@ -508,7 +436,6 @@ static int __init init_teles_cs(void)
508static void __exit exit_teles_cs(void) 436static 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
514module_init(init_teles_cs); 441module_init(init_teles_cs);