Skip to content

Commit

Permalink
[PATCH] pcmcia: pseudo device handling update
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dominik Brodowski committed Mar 31, 2006
1 parent 9940ec3 commit d6ff5a8
Showing 1 changed file with 48 additions and 33 deletions.
81 changes: 48 additions & 33 deletions drivers/pcmcia/ds.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,15 +415,61 @@ static int pcmcia_device_probe(struct device * dev)
}


/*
* Removes a PCMCIA card from the device tree and socket list.
*/
static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
{
struct pcmcia_device *p_dev;
struct pcmcia_device *tmp;
unsigned long flags;

ds_dbg(2, "unbind_request(%d)\n", s->sock);


if (!leftover)
s->device_count = 0;
else
s->device_count = 1;

/* unregister all pcmcia_devices registered with this socket, except leftover */
list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
if (p_dev == leftover)
continue;

spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_del(&p_dev->socket_device_list);
p_dev->_removed=1;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);

device_unregister(&p_dev->dev);
}

return;
}


static int pcmcia_device_remove(struct device * dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
struct pcmcia_device_id *did;
int i;

/* detach the "instance" */
p_dev = to_pcmcia_dev(dev);
p_drv = to_pcmcia_drv(dev->driver);

/* If we're removing the primary module driving a
* pseudo multi-function card, we need to unbind
* all devices
*/
did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
if ((did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
(p_dev->socket->device_count != 0) &&
(p_dev->device_no == 0))
pcmcia_card_remove(p_dev->socket, p_dev);

/* detach the "instance" */
if (!p_drv)
return 0;

Expand All @@ -448,37 +494,6 @@ static int pcmcia_device_remove(struct device * dev)
}


/*
* Removes a PCMCIA card from the device tree and socket list.
*/
static void pcmcia_card_remove(struct pcmcia_socket *s)
{
struct pcmcia_device *p_dev;
unsigned long flags;

ds_dbg(2, "unbind_request(%d)\n", s->sock);

s->device_count = 0;

for (;;) {
/* unregister all pcmcia_devices registered with this socket*/
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
if (list_empty(&s->devices_list)) {
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
return;
}
p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
list_del(&p_dev->socket_device_list);
p_dev->_removed=1;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);

device_unregister(&p_dev->dev);
}

return;
} /* unbind_request */


/*
* pcmcia_device_query -- determine information about a pcmcia device
*/
Expand Down Expand Up @@ -1136,7 +1151,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
switch (event) {
case CS_EVENT_CARD_REMOVAL:
s->pcmcia_state.present = 0;
pcmcia_card_remove(skt);
pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
break;

Expand Down

0 comments on commit d6ff5a8

Please sign in to comment.