diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2006-02-05 03:51:34 -0500 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2006-03-31 10:26:58 -0500 |
commit | d6ff5a8532b553e4d85ea65c99eaa0794edf5311 (patch) | |
tree | 2777a69b9c06197ddc7826bf44230e0ca9b04fcd /drivers/pcmcia | |
parent | 9940ec3617fec1db13e589bbc3f37e37878c7683 (diff) |
[PATCH] pcmcia: pseudo device handling update
If the driver for the primary pseudo device is removed from the device,
the secondary driver must be removed as well -- it cannot exist on its own.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia')
-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 | ||