diff options
| -rw-r--r-- | drivers/usb/core/usb.c | 33 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hub.c | 16 | ||||
| -rw-r--r-- | include/linux/usb.h | 1 |
3 files changed, 50 insertions, 0 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index b10da720f2b4..7dad603dde43 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
| @@ -209,6 +209,39 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) | |||
| 209 | } | 209 | } |
| 210 | EXPORT_SYMBOL_GPL(usb_find_interface); | 210 | EXPORT_SYMBOL_GPL(usb_find_interface); |
| 211 | 211 | ||
| 212 | struct each_dev_arg { | ||
| 213 | void *data; | ||
| 214 | int (*fn)(struct usb_device *, void *); | ||
| 215 | }; | ||
| 216 | |||
| 217 | static int __each_dev(struct device *dev, void *data) | ||
| 218 | { | ||
| 219 | struct each_dev_arg *arg = (struct each_dev_arg *)data; | ||
| 220 | |||
| 221 | /* There are struct usb_interface on the same bus, filter them out */ | ||
| 222 | if (!is_usb_device(dev)) | ||
| 223 | return 0; | ||
| 224 | |||
| 225 | return arg->fn(container_of(dev, struct usb_device, dev), arg->data); | ||
| 226 | } | ||
| 227 | |||
| 228 | /** | ||
| 229 | * usb_for_each_dev - iterate over all USB devices in the system | ||
| 230 | * @data: data pointer that will be handed to the callback function | ||
| 231 | * @fn: callback function to be called for each USB device | ||
| 232 | * | ||
| 233 | * Iterate over all USB devices and call @fn for each, passing it @data. If it | ||
| 234 | * returns anything other than 0, we break the iteration prematurely and return | ||
| 235 | * that value. | ||
| 236 | */ | ||
| 237 | int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *)) | ||
| 238 | { | ||
| 239 | struct each_dev_arg arg = {data, fn}; | ||
| 240 | |||
| 241 | return bus_for_each_dev(&usb_bus_type, NULL, &arg, __each_dev); | ||
| 242 | } | ||
| 243 | EXPORT_SYMBOL_GPL(usb_for_each_dev); | ||
| 244 | |||
| 212 | /** | 245 | /** |
| 213 | * usb_release_dev - free a usb device structure when all users of it are finished. | 246 | * usb_release_dev - free a usb device structure when all users of it are finished. |
| 214 | * @dev: device that's been disconnected | 247 | * @dev: device that's been disconnected |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 9ab4a4d9768a..b2f64506840b 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
| @@ -42,6 +42,12 @@ static int ehci_hub_control( | |||
| 42 | u16 wLength | 42 | u16 wLength |
| 43 | ); | 43 | ); |
| 44 | 44 | ||
| 45 | static int persist_enabled_on_companion(struct usb_device *udev, void *unused) | ||
| 46 | { | ||
| 47 | return !udev->maxchild && udev->persist_enabled && | ||
| 48 | udev->bus->root_hub->speed < USB_SPEED_HIGH; | ||
| 49 | } | ||
| 50 | |||
| 45 | /* After a power loss, ports that were owned by the companion must be | 51 | /* After a power loss, ports that were owned by the companion must be |
| 46 | * reset so that the companion can still own them. | 52 | * reset so that the companion can still own them. |
| 47 | */ | 53 | */ |
| @@ -56,6 +62,16 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
| 56 | if (!ehci->owned_ports) | 62 | if (!ehci->owned_ports) |
| 57 | return; | 63 | return; |
| 58 | 64 | ||
| 65 | /* | ||
| 66 | * USB 1.1 devices are mostly HIDs, which don't need to persist across | ||
| 67 | * suspends. If we ensure that none of our companion's devices have | ||
| 68 | * persist_enabled (by looking through all USB 1.1 buses in the system), | ||
| 69 | * we can skip this and avoid slowing resume down. Devices without | ||
| 70 | * persist will just get reenumerated shortly after resume anyway. | ||
| 71 | */ | ||
| 72 | if (!usb_for_each_dev(NULL, persist_enabled_on_companion)) | ||
| 73 | return; | ||
| 74 | |||
| 59 | /* Make sure the ports are powered */ | 75 | /* Make sure the ports are powered */ |
| 60 | port = HCS_N_PORTS(ehci->hcs_params); | 76 | port = HCS_N_PORTS(ehci->hcs_params); |
| 61 | while (port--) { | 77 | while (port--) { |
diff --git a/include/linux/usb.h b/include/linux/usb.h index a0bee5a28d1a..b424e5318f20 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -717,6 +717,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, | |||
| 717 | extern int usb_match_one_id(struct usb_interface *interface, | 717 | extern int usb_match_one_id(struct usb_interface *interface, |
| 718 | const struct usb_device_id *id); | 718 | const struct usb_device_id *id); |
| 719 | 719 | ||
| 720 | extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *)); | ||
| 720 | extern struct usb_interface *usb_find_interface(struct usb_driver *drv, | 721 | extern struct usb_interface *usb_find_interface(struct usb_driver *drv, |
| 721 | int minor); | 722 | int minor); |
| 722 | extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, | 723 | extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, |
