aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-11-22 16:55:54 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 14:25:52 -0800
commitee49fb5dc89d34f1794ac9362fa97c1a640f7ddd (patch)
tree310d11b695b631c091c9f442d566400ba9a86de9 /drivers/usb/core/hub.c
parentd25450c68767481f7c9cc4823a6da8235db40be6 (diff)
USB: keep count of unsuspended children
This patch (as818b) simplifies autosuspend processing by keeping track of the number of unsuspended children of each USB hub. This will permit us to avoid a good deal of unnecessary work all the time; we will no longer have to create a bunch of workqueue entries to carry out autosuspend requests, only to have them fail because one of the hub's children isn't suspended. The basic idea is simple. There already is a usage counter in the usb_device structure for preventing autosuspends. The patch just increments that counter for every unsuspended child. There's only one tricky part: When a device disconnects we need to remember whether it was suspended at the time (leave the counter alone) or not (decrement the counter). Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 46df5e60764..e46d38b1824 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1039,6 +1039,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
if (udev->children[i])
recursively_mark_NOTATTACHED(udev->children[i]);
}
+ if (udev->state == USB_STATE_SUSPENDED)
+ udev->discon_suspended = 1;
udev->state = USB_STATE_NOTATTACHED;
}
@@ -1228,6 +1230,14 @@ void usb_disconnect(struct usb_device **pdev)
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
+ /* Decrement the parent's count of unsuspended children */
+ if (udev->parent) {
+ usb_pm_lock(udev);
+ if (!udev->discon_suspended)
+ usb_autosuspend_device(udev->parent, 1);
+ usb_pm_unlock(udev);
+ }
+
put_device(&udev->dev);
}
@@ -1356,6 +1366,10 @@ static int __usb_new_device(void *void_data)
goto fail;
}
+ /* Increment the parent's count of unsuspended children */
+ if (udev->parent)
+ usb_autoresume_device(udev->parent, 1);
+
exit:
module_put(THIS_MODULE);
return err;