aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/ds.c97
1 files changed, 62 insertions, 35 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5223395b246a..32b4d6baa917 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -57,8 +57,6 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644);
57 57
58spinlock_t pcmcia_dev_list_lock; 58spinlock_t pcmcia_dev_list_lock;
59 59
60static int unbind_request(struct pcmcia_socket *s);
61
62/*====================================================================*/ 60/*====================================================================*/
63 61
64/* code which was in cs.c before */ 62/* code which was in cs.c before */
@@ -205,7 +203,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
205 unsigned int i; 203 unsigned int i;
206 u32 hash; 204 u32 hash;
207 205
208 if (!p_drv->attach || !p_drv->event || !p_drv->detach) 206 if (!p_drv->attach || !p_drv->event || !p_drv->remove)
209 printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " 207 printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
210 "function\n", p_drv->drv.name); 208 "function\n", p_drv->drv.name);
211 209
@@ -399,13 +397,42 @@ static int pcmcia_device_remove(struct device * dev)
399{ 397{
400 struct pcmcia_device *p_dev; 398 struct pcmcia_device *p_dev;
401 struct pcmcia_driver *p_drv; 399 struct pcmcia_driver *p_drv;
400 int i;
402 401
403 /* detach the "instance" */ 402 /* detach the "instance" */
404 p_dev = to_pcmcia_dev(dev); 403 p_dev = to_pcmcia_dev(dev);
405 p_drv = to_pcmcia_drv(dev->driver); 404 p_drv = to_pcmcia_drv(dev->driver);
406 405
406 /* the likely, new path */
407 if (p_drv && p_drv->remove) {
408 p_drv->remove(p_dev);
409
410 /* check for proper unloading */
411 if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
412 printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
413 p_drv->drv.name);
414
415 for (i = 0; i < MAX_WIN; i++)
416 if (p_dev->state & CLIENT_WIN_REQ(i))
417 printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",
418 p_drv->drv.name);
419
420 /* undo pcmcia_register_client */
421 p_dev->state = CLIENT_UNBOUND;
422 pcmcia_put_dev(p_dev);
423
424 /* references from pcmcia_probe_device */
425 pcmcia_put_dev(p_dev);
426 module_put(p_drv->owner);
427
428 return 0;
429 }
430
431 /* old path */
407 if (p_drv) { 432 if (p_drv) {
408 if ((p_drv->detach) && (p_dev->instance)) { 433 if ((p_drv->detach) && (p_dev->instance)) {
434 printk(KERN_INFO "pcmcia: using deprecated detach mechanism. Fix the driver!\n");
435
409 p_drv->detach(p_dev->instance); 436 p_drv->detach(p_dev->instance);
410 /* from pcmcia_probe_device */ 437 /* from pcmcia_probe_device */
411 put_device(&p_dev->dev); 438 put_device(&p_dev->dev);
@@ -417,6 +444,36 @@ static int pcmcia_device_remove(struct device * dev)
417} 444}
418 445
419 446
447/*
448 * Removes a PCMCIA card from the device tree and socket list.
449 */
450static void pcmcia_card_remove(struct pcmcia_socket *s)
451{
452 struct pcmcia_device *p_dev;
453 unsigned long flags;
454
455 ds_dbg(2, "unbind_request(%d)\n", s->sock);
456
457 s->device_count = 0;
458
459 for (;;) {
460 /* unregister all pcmcia_devices registered with this socket*/
461 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
462 if (list_empty(&s->devices_list)) {
463 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
464 return;
465 }
466 p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
467 list_del(&p_dev->socket_device_list);
468 p_dev->state |= CLIENT_STALE;
469 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
470
471 device_unregister(&p_dev->dev);
472 }
473
474 return;
475} /* unbind_request */
476
420 477
421/* 478/*
422 * pcmcia_device_query -- determine information about a pcmcia device 479 * pcmcia_device_query -- determine information about a pcmcia device
@@ -1059,8 +1116,8 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
1059 1116
1060 case CS_EVENT_CARD_REMOVAL: 1117 case CS_EVENT_CARD_REMOVAL:
1061 s->pcmcia_state.present = 0; 1118 s->pcmcia_state.present = 0;
1062 send_event(skt, event, priority); 1119 send_event(skt, event, priority);
1063 unbind_request(skt); 1120 pcmcia_card_remove(skt);
1064 handle_event(skt, event); 1121 handle_event(skt, event);
1065 break; 1122 break;
1066 1123
@@ -1177,36 +1234,6 @@ int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req)
1177EXPORT_SYMBOL(pcmcia_register_client); 1234EXPORT_SYMBOL(pcmcia_register_client);
1178 1235
1179 1236
1180/* unbind _all_ devices attached to a given pcmcia_bus_socket. The
1181 * drivers have been called with EVENT_CARD_REMOVAL before.
1182 */
1183static int unbind_request(struct pcmcia_socket *s)
1184{
1185 struct pcmcia_device *p_dev;
1186 unsigned long flags;
1187
1188 ds_dbg(2, "unbind_request(%d)\n", s->sock);
1189
1190 s->device_count = 0;
1191
1192 for (;;) {
1193 /* unregister all pcmcia_devices registered with this socket*/
1194 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
1195 if (list_empty(&s->devices_list)) {
1196 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
1197 return 0;
1198 }
1199 p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
1200 list_del(&p_dev->socket_device_list);
1201 p_dev->state |= CLIENT_STALE;
1202 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
1203
1204 device_unregister(&p_dev->dev);
1205 }
1206
1207 return 0;
1208} /* unbind_request */
1209
1210int pcmcia_deregister_client(struct pcmcia_device *p_dev) 1237int pcmcia_deregister_client(struct pcmcia_device *p_dev)
1211{ 1238{
1212 struct pcmcia_socket *s; 1239 struct pcmcia_socket *s;