aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/ds.c81
1 files changed, 48 insertions, 33 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 677105e35759..8966dd09139d 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -415,15 +415,61 @@ static int pcmcia_device_probe(struct device * dev)
415} 415}
416 416
417 417
418/*
419 * Removes a PCMCIA card from the device tree and socket list.
420 */
421static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
422{
423 struct pcmcia_device *p_dev;
424 struct pcmcia_device *tmp;
425 unsigned long flags;
426
427 ds_dbg(2, "unbind_request(%d)\n", s->sock);
428
429
430 if (!leftover)
431 s->device_count = 0;
432 else
433 s->device_count = 1;
434
435 /* unregister all pcmcia_devices registered with this socket, except leftover */
436 list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
437 if (p_dev == leftover)
438 continue;
439
440 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
441 list_del(&p_dev->socket_device_list);
442 p_dev->_removed=1;
443 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
444
445 device_unregister(&p_dev->dev);
446 }
447
448 return;
449}
450
451
418static int pcmcia_device_remove(struct device * dev) 452static int pcmcia_device_remove(struct device * dev)
419{ 453{
420 struct pcmcia_device *p_dev; 454 struct pcmcia_device *p_dev;
421 struct pcmcia_driver *p_drv; 455 struct pcmcia_driver *p_drv;
456 struct pcmcia_device_id *did;
422 int i; 457 int i;
423 458
424 /* detach the "instance" */
425 p_dev = to_pcmcia_dev(dev); 459 p_dev = to_pcmcia_dev(dev);
426 p_drv = to_pcmcia_drv(dev->driver); 460 p_drv = to_pcmcia_drv(dev->driver);
461
462 /* If we're removing the primary module driving a
463 * pseudo multi-function card, we need to unbind
464 * all devices
465 */
466 did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
467 if ((did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
468 (p_dev->socket->device_count != 0) &&
469 (p_dev->device_no == 0))
470 pcmcia_card_remove(p_dev->socket, p_dev);
471
472 /* detach the "instance" */
427 if (!p_drv) 473 if (!p_drv)
428 return 0; 474 return 0;
429 475
@@ -449,37 +495,6 @@ static int pcmcia_device_remove(struct device * dev)
449 495
450 496
451/* 497/*
452 * Removes a PCMCIA card from the device tree and socket list.
453 */
454static void pcmcia_card_remove(struct pcmcia_socket *s)
455{
456 struct pcmcia_device *p_dev;
457 unsigned long flags;
458
459 ds_dbg(2, "unbind_request(%d)\n", s->sock);
460
461 s->device_count = 0;
462
463 for (;;) {
464 /* unregister all pcmcia_devices registered with this socket*/
465 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
466 if (list_empty(&s->devices_list)) {
467 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
468 return;
469 }
470 p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
471 list_del(&p_dev->socket_device_list);
472 p_dev->_removed=1;
473 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
474
475 device_unregister(&p_dev->dev);
476 }
477
478 return;
479} /* unbind_request */
480
481
482/*
483 * pcmcia_device_query -- determine information about a pcmcia device 498 * pcmcia_device_query -- determine information about a pcmcia device
484 */ 499 */
485static int pcmcia_device_query(struct pcmcia_device *p_dev) 500static int pcmcia_device_query(struct pcmcia_device *p_dev)
@@ -1136,7 +1151,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
1136 switch (event) { 1151 switch (event) {
1137 case CS_EVENT_CARD_REMOVAL: 1152 case CS_EVENT_CARD_REMOVAL:
1138 s->pcmcia_state.present = 0; 1153 s->pcmcia_state.present = 0;
1139 pcmcia_card_remove(skt); 1154 pcmcia_card_remove(skt, NULL);
1140 handle_event(skt, event); 1155 handle_event(skt, event);
1141 break; 1156 break;
1142 1157