diff options
| -rw-r--r-- | drivers/pcmcia/ds.c | 81 |
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 | */ | ||
| 421 | static 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 | |||
| 418 | static int pcmcia_device_remove(struct device * dev) | 452 | static 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 | */ | ||
| 454 | static 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 | */ |
| 485 | static int pcmcia_device_query(struct pcmcia_device *p_dev) | 500 | static 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 | ||
