From 140d8f687457c40a66af362838fac0d7893e7df5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:07:21 -0400 Subject: usbcore: rename usb_suspend_device to usb_port_suspend This revised patch (as715b) renames usb_suspend_device to usb_port_suspend, usb_resume_device to usb_port_resume, and finish_device_resume to finish_port_resume. There was no objection to the original version of the patch so this should be okay to apply. The revision was needed only because I have re-arranged the order of the earlier patches. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 26c8cb5..b00514d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1407,9 +1407,9 @@ int usb_new_device(struct usb_device *udev) * (Includes HNP test device.) */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - static int __usb_suspend_device(struct usb_device *, + static int __usb_port_suspend(struct usb_device *, int port1); - err = __usb_suspend_device(udev, udev->bus->otg_port); + err = __usb_port_suspend(udev, udev->bus->otg_port); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); } @@ -1684,7 +1684,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * the root hub for their bus goes into global suspend ... so we don't * (falsely) update the device power state to say it suspended. */ -static int __usb_suspend_device (struct usb_device *udev, int port1) +static int __usb_port_suspend (struct usb_device *udev, int port1) { int status = 0; @@ -1712,8 +1712,8 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) } } - /* we only change a device's upstream USB link. - * root hubs have no upstream USB link. + /* we change the device's upstream USB link, + * but root hubs have no upstream USB link. */ if (udev->parent) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, @@ -1727,14 +1727,14 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) #endif /* - * usb_suspend_device - suspend a usb device + * usb_port_suspend - suspend a usb device's upstream port * @udev: device that's no longer in active use * Context: must be able to sleep; device not locked; pm locks held * * Suspends a USB device that isn't in active use, conserving power. * Devices may wake out of a suspend, if anything important happens, * using the remote wakeup mechanism. They may also be taken out of - * suspend by the host, using usb_resume_device(). It's also routine + * suspend by the host, using usb_port_resume(). It's also routine * to disconnect devices while they are suspended. * * This only affects the USB hardware for a device; its interfaces @@ -1746,12 +1746,12 @@ static int __usb_suspend_device (struct usb_device *udev, int port1) * * Returns 0 on success, else negative errno. */ -int usb_suspend_device(struct usb_device *udev) +int usb_port_suspend(struct usb_device *udev) { #ifdef CONFIG_USB_SUSPEND if (udev->state == USB_STATE_NOTATTACHED) return -ENODEV; - return __usb_suspend_device(udev, udev->portnum); + return __usb_port_suspend(udev, udev->portnum); #else /* NOTE: udev->state unchanged, it's not lying ... */ udev->dev.power.power_state = PMSG_SUSPEND; @@ -1767,7 +1767,7 @@ int usb_suspend_device(struct usb_device *udev) * resume (by host) or remote wakeup (by device) ... now see what changed * in the tree that's rooted at this device. */ -static int finish_device_resume(struct usb_device *udev) +static int finish_port_resume(struct usb_device *udev) { int status; u16 devstatus; @@ -1891,7 +1891,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* TRSMRCY = 10 msec */ msleep(10); if (udev) - status = finish_device_resume(udev); + status = finish_port_resume(udev); } } if (status < 0) @@ -1903,7 +1903,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) #endif /* - * usb_resume_device - re-activate a suspended usb device + * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate * Context: must be able to sleep; device not locked; pm locks held * @@ -1915,14 +1915,16 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) * * Returns 0 on success, else negative errno. */ -int usb_resume_device(struct usb_device *udev) +int usb_port_resume(struct usb_device *udev) { int status; if (udev->state == USB_STATE_NOTATTACHED) return -ENODEV; - /* selective resume of one downstream hub-to-device port */ + /* we change the device's upstream USB link, + * but root hubs have no upstream USB link. + */ if (udev->parent) { #ifdef CONFIG_USB_SUSPEND if (udev->state == USB_STATE_SUSPENDED) { @@ -1934,7 +1936,7 @@ int usb_resume_device(struct usb_device *udev) #endif status = 0; } else - status = finish_device_resume(udev); + status = finish_port_resume(udev); if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", status); @@ -1962,7 +1964,7 @@ static int remote_wakeup(struct usb_device *udev) dev_dbg(&udev->dev, "RESUME (wakeup)\n"); /* TRSMRCY = 10 msec */ msleep(10); - status = finish_device_resume(udev); + status = finish_port_resume(udev); } usb_unlock_device(udev); #endif @@ -2069,7 +2071,7 @@ static int hub_resume(struct usb_interface *intf) if (portstat & USB_PORT_STAT_SUSPEND) status = hub_port_resume(hub, port1, udev); else { - status = finish_device_resume(udev); + status = finish_port_resume(udev); if (status < 0) { dev_dbg(&intf->dev, "resume port %d --> %d\n", port1, status); @@ -3128,6 +3130,7 @@ re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } +EXPORT_SYMBOL(usb_reset_device); /** * usb_reset_composite_device - warn interface drivers and perform a USB port reset @@ -3206,3 +3209,4 @@ int usb_reset_composite_device(struct usb_device *udev, return ret; } +EXPORT_SYMBOL(usb_reset_composite_device); -- cgit v1.1 From 782da727b0d59e93c84a627948b1535a3db90392 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:09:35 -0400 Subject: usbcore: make usb_generic a usb_device_driver This patch (as714b) makes usb_generic into a usb_device_driver capable of being probed and unbound, just like other drivers. A fair amount of the work that used to get done during discovery or removal of a USB device have been moved to the probe and disconnect methods of usb_generic: creating the sysfs attributes and selecting an initial configuration. However the normal behavior should continue to be the same as before. We will now have the possibility of creating other USB device drivers, They will assist with exporting devices to remote systems (USB-over-TCPIP) or to paravirtual guest operating systems. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 164 +++++-------------------------------------------- 1 file changed, 14 insertions(+), 150 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b00514d..a372332 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1148,144 +1148,28 @@ void usb_disconnect(struct usb_device **pdev) * cleaning up all state associated with the current configuration * so that the hardware is now fully quiesced. */ + dev_dbg (&udev->dev, "unregistering device\n"); usb_disable_device(udev, 0); - usb_notify_remove_device(udev); + usb_unlock_device(udev); + + /* Unregister the device. The device driver is responsible + * for removing the device files from usbfs and sysfs and for + * de-configuring the device. + */ + device_del(&udev->dev); - /* Free the device number, remove the /proc/bus/usb entry and - * the sysfs attributes, and delete the parent's children[] + /* Free the device number and delete the parent's children[] * (or root_hub) pointer. */ - dev_dbg (&udev->dev, "unregistering device\n"); release_address(udev); - usb_remove_sysfs_dev_files(udev); /* Avoid races with recursively_mark_NOTATTACHED() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); - usb_unlock_device(udev); - - device_unregister(&udev->dev); -} - -static inline const char *plural(int n) -{ - return (n == 1 ? "" : "s"); -} - -static int choose_configuration(struct usb_device *udev) -{ - int i; - int num_configs; - int insufficient_power = 0; - struct usb_host_config *c, *best; - - best = NULL; - c = udev->config; - num_configs = udev->descriptor.bNumConfigurations; - for (i = 0; i < num_configs; (i++, c++)) { - struct usb_interface_descriptor *desc = NULL; - - /* It's possible that a config has no interfaces! */ - if (c->desc.bNumInterfaces > 0) - desc = &c->intf_cache[0]->altsetting->desc; - - /* - * HP's USB bus-powered keyboard has only one configuration - * and it claims to be self-powered; other devices may have - * similar errors in their descriptors. If the next test - * were allowed to execute, such configurations would always - * be rejected and the devices would not work as expected. - * In the meantime, we run the risk of selecting a config - * that requires external power at a time when that power - * isn't available. It seems to be the lesser of two evils. - * - * Bugzilla #6448 reports a device that appears to crash - * when it receives a GET_DEVICE_STATUS request! We don't - * have any other way to tell whether a device is self-powered, - * but since we don't use that information anywhere but here, - * the call has been removed. - * - * Maybe the GET_DEVICE_STATUS call and the test below can - * be reinstated when device firmwares become more reliable. - * Don't hold your breath. - */ -#if 0 - /* Rule out self-powered configs for a bus-powered device */ - if (bus_powered && (c->desc.bmAttributes & - USB_CONFIG_ATT_SELFPOWER)) - continue; -#endif - - /* - * The next test may not be as effective as it should be. - * Some hubs have errors in their descriptor, claiming - * to be self-powered when they are really bus-powered. - * We will overestimate the amount of current such hubs - * make available for each port. - * - * This is a fairly benign sort of failure. It won't - * cause us to reject configurations that we should have - * accepted. - */ - - /* Rule out configs that draw too much bus current */ - if (c->desc.bMaxPower * 2 > udev->bus_mA) { - insufficient_power++; - continue; - } - - /* If the first config's first interface is COMM/2/0xff - * (MSFT RNDIS), rule it out unless Linux has host-side - * RNDIS support. */ - if (i == 0 && desc - && desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff) { -#ifndef CONFIG_USB_NET_RNDIS_HOST - continue; -#else - best = c; -#endif - } - - /* From the remaining configs, choose the first one whose - * first interface is for a non-vendor-specific class. - * Reason: Linux is more likely to have a class driver - * than a vendor-specific driver. */ - else if (udev->descriptor.bDeviceClass != - USB_CLASS_VENDOR_SPEC && - (!desc || desc->bInterfaceClass != - USB_CLASS_VENDOR_SPEC)) { - best = c; - break; - } - - /* If all the remaining configs are vendor-specific, - * choose the first one. */ - else if (!best) - best = c; - } - - if (insufficient_power > 0) - dev_info(&udev->dev, "rejected %d configuration%s " - "due to insufficient available bus power\n", - insufficient_power, plural(insufficient_power)); - - if (best) { - i = best->desc.bConfigurationValue; - dev_info(&udev->dev, - "configuration #%d chosen from %d choice%s\n", - i, num_configs, plural(num_configs)); - } else { - i = -1; - dev_warn(&udev->dev, - "no configuration chosen from %d choice%s\n", - num_configs, plural(num_configs)); - } - return i; + put_device(&udev->dev); } #ifdef DEBUG @@ -1328,7 +1212,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) int usb_new_device(struct usb_device *udev) { int err; - int c; err = usb_get_configuration(udev); if (err < 0) { @@ -1418,34 +1301,15 @@ int usb_new_device(struct usb_device *udev) } #endif - /* put device-specific files into sysfs */ + /* Register the device. The device driver is responsible + * for adding the device files to usbfs and sysfs and for + * configuring the device. + */ err = device_add (&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); goto fail; } - usb_create_sysfs_dev_files (udev); - - usb_lock_device(udev); - - /* choose and set the configuration. that registers the interfaces - * with the driver core, and lets usb device drivers bind to them. - */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", - c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ - } - } - - /* USB device state == configured ... usable */ - usb_notify_add_device(udev); - - usb_unlock_device(udev); return 0; -- cgit v1.1 From a8e7c5653562f88c0f5f53eac0a890c012655789 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:11:02 -0400 Subject: usbcore: resume device resume recursion This patch (as717b) removes the existing recursion in hub resume code: Resuming a hub will no longer automatically resume the devices attached to the hub. At the same time, it adds one level of recursion: Suspending a USB device will automatically suspend all the device's interfaces. Failure at an intermediate stage will cause all the already-suspended interfaces to be resumed. Attempts to suspend or resume an interface by itself will do nothing, although they won't return an error. Thus the regular system-suspend and system-resume procedures should continue to work as before; only runtime PM will be affected. The patch also removes the code that tests state of the interfaces before suspending a device. It's no longer needed, since everything gets suspended together. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 96 +++++++------------------------------------------- 1 file changed, 13 insertions(+), 83 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a372332..a391120 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1662,9 +1662,6 @@ static int finish_port_resume(struct usb_device *udev) "gone after usb resume? status %d\n", status); else if (udev->actconfig) { - unsigned i; - int (*resume)(struct device *); - le16_to_cpus(&devstatus); if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) && udev->parent) { @@ -1675,24 +1672,9 @@ static int finish_port_resume(struct usb_device *udev) USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (status) { + if (status) dev_dbg(&udev->dev, "disable remote " "wakeup, status %d\n", status); - status = 0; - } - } - - /* resume interface drivers; if this is a hub, it - * may have a child resume event to deal with soon - */ - resume = udev->dev.bus->resume; - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct device *dev = - &udev->actconfig->interface[i]->dev; - - down(&dev->sem); - (void) resume(dev); - up(&dev->sem); } status = 0; @@ -1802,15 +1784,7 @@ int usb_port_resume(struct usb_device *udev) } else status = finish_port_resume(udev); if (status < 0) - dev_dbg(&udev->dev, "can't resume, status %d\n", - status); - - /* rebind drivers that had no suspend() */ - if (status == 0) { - usb_unlock_device(udev); - bus_rescan_devices(&usb_bus_type); - usb_lock_device(udev); - } + dev_dbg(&udev->dev, "can't resume, status %d\n", status); return status; } @@ -1830,6 +1804,9 @@ static int remote_wakeup(struct usb_device *udev) msleep(10); status = finish_port_resume(udev); } + + if (status == 0) + usb_resume_both(udev); usb_unlock_device(udev); #endif return status; @@ -1901,51 +1878,8 @@ static int hub_resume(struct usb_interface *intf) } } + /* tell khubd to look for changes on this hub */ hub_activate(hub); - - /* REVISIT: this recursion probably shouldn't exist. Remove - * this code sometime, after retesting with different root and - * external hubs. - */ -#ifdef CONFIG_USB_SUSPEND - { - unsigned port1; - - for (port1 = 1; port1 <= hdev->maxchild; port1++) { - struct usb_device *udev; - u16 portstat, portchange; - - udev = hdev->children [port1-1]; - status = hub_port_status(hub, port1, &portstat, &portchange); - if (status == 0) { - if (portchange & USB_PORT_STAT_C_SUSPEND) { - clear_port_feature(hdev, port1, - USB_PORT_FEAT_C_SUSPEND); - portchange &= ~USB_PORT_STAT_C_SUSPEND; - } - - /* let khubd handle disconnects etc */ - if (portchange) - continue; - } - - if (!udev || status < 0) - continue; - usb_lock_device(udev); - if (portstat & USB_PORT_STAT_SUSPEND) - status = hub_port_resume(hub, port1, udev); - else { - status = finish_port_resume(udev); - if (status < 0) { - dev_dbg(&intf->dev, "resume port %d --> %d\n", - port1, status); - hub_port_logical_disconnect(hub, port1); - } - } - usb_unlock_device(udev); - } - } -#endif return 0; } @@ -2602,17 +2536,6 @@ static void hub_events(void) usb_get_intf(intf); spin_unlock_irq(&hub_event_lock); - /* Is this is a root hub wanting to reactivate the downstream - * ports? If so, be sure the interface resumes even if its - * stub "device" node was never suspended. - */ - if (i) { - dpm_runtime_resume(&hdev->dev); - dpm_runtime_resume(&intf->dev); - usb_put_intf(intf); - continue; - } - /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ if (locktree(hdev) < 0) { @@ -2629,6 +2552,13 @@ static void hub_events(void) goto loop; } + /* Is this is a root hub wanting to reactivate the downstream + * ports? If so, be sure the interface resumes even if its + * stub "device" node was never suspended. + */ + if (i) + usb_resume_both(hdev); + /* If this is an inactive or suspended hub, do nothing */ if (hub->quiescing) goto loop; -- cgit v1.1 From 2bf4086d7a7722b470aa24e1be725cc58619c6fe Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:12:19 -0400 Subject: usbcore: set device and power states properly This patch (as733) fixes up the places where device states and power states are set in usbcore. Right now things are duplicated or missing; this should straighten things out. The idea is that udev->state is USB_STATE_SUSPENDED exactly when the device's upstream port has been suspended, whereas udev->dev.power.power_state.event reflects the result of the last call to the suspend/resume routines (which might not actually change the device state, especially if CONFIG_USB_SUSPEND isn't set). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a391120..7af53db 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1582,9 +1582,10 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) if (udev->parent) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, udev); - - if (status == 0) - udev->dev.power.power_state = PMSG_SUSPEND; + else { + dev_dbg(&udev->dev, "usb suspend\n"); + usb_set_device_state(udev, USB_STATE_SUSPENDED); + } return status; } @@ -1617,8 +1618,6 @@ int usb_port_suspend(struct usb_device *udev) return -ENODEV; return __usb_port_suspend(udev, udev->portnum); #else - /* NOTE: udev->state unchanged, it's not lying ... */ - udev->dev.power.power_state = PMSG_SUSPEND; return 0; #endif } @@ -1647,7 +1646,6 @@ static int finish_port_resume(struct usb_device *udev) usb_set_device_state(udev, udev->actconfig ? USB_STATE_CONFIGURED : USB_STATE_ADDRESS); - udev->dev.power.power_state = PMSG_ON; /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, -- cgit v1.1 From 114b368c07964caa3f4e1fa575b16e87fa11936c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:13:04 -0400 Subject: usbcore: fix up device and power state tests This patch (as734) rationalizes the various tests of device state and power states. There are duplications and mistaken tests in several places. Perhaps the most interesting challenge is where the hub driver tests to see that all the child devices are suspended before allowing itself to be suspended. When CONFIG_USB_SUSPEND is set the test is straightforward, since we expect that the children _will_ be suspended. But when CONFIG_USB_SUSPEND isn't set, it's not so clear what should be done. The code compromises by checking the child's power.power_state.event field. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 47 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7af53db..a310c7c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1556,26 +1556,6 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) if (port1 < 0) return port1; - if (udev->state == USB_STATE_SUSPENDED - || udev->state == USB_STATE_NOTATTACHED) { - return 0; - } - - /* all interfaces must already be suspended */ - if (udev->actconfig) { - int i; - - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf; - - intf = udev->actconfig->interface[i]; - if (is_active(intf)) { - dev_dbg(&intf->dev, "nyet suspended\n"); - return -EBUSY; - } - } - } - /* we change the device's upstream USB link, * but root hubs have no upstream USB link. */ @@ -1614,8 +1594,6 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) int usb_port_suspend(struct usb_device *udev) { #ifdef CONFIG_USB_SUSPEND - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; return __usb_port_suspend(udev, udev->portnum); #else return 0; @@ -1761,24 +1739,17 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) */ int usb_port_resume(struct usb_device *udev) { - int status; - - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; + int status = 0; /* we change the device's upstream USB link, * but root hubs have no upstream USB link. */ if (udev->parent) { #ifdef CONFIG_USB_SUSPEND - if (udev->state == USB_STATE_SUSPENDED) { - // NOTE swsusp may bork us, device state being wrong... - // NOTE this fails if parent is also suspended... - status = hub_port_resume(hdev_to_hub(udev->parent), - udev->portnum, udev); - } else + // NOTE this fails if parent is also suspended... + status = hub_port_resume(hdev_to_hub(udev->parent), + udev->portnum, udev); #endif - status = 0; } else status = finish_port_resume(udev); if (status < 0) @@ -1821,12 +1792,14 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && (udev->dev.power.power_state.event - == PM_EVENT_ON + if (udev && msg.event == PM_EVENT_SUSPEND && #ifdef CONFIG_USB_SUSPEND - || udev->state != USB_STATE_SUSPENDED + udev->state != USB_STATE_SUSPENDED +#else + udev->dev.power.power_state.event + == PM_EVENT_ON #endif - )) { + ) { dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); return -EBUSY; } -- cgit v1.1 From d388dab7b562b76525761f89702246686747ba30 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 1 Jul 2006 22:14:24 -0400 Subject: hub driver: improve use of #ifdef This patch (as736) makes the hub driver more readable by improving the usage of "#ifdef CONFIG_PM" and "#ifdef CONFIG_USB_SUSPEND". Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 64 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 18 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a310c7c..64e80b9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1041,7 +1041,7 @@ void usb_set_device_state(struct usb_device *udev, } -#ifdef CONFIG_PM +#ifdef CONFIG_PM /** * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power @@ -1072,7 +1072,7 @@ void usb_root_hub_lost_power(struct usb_device *rhdev) } EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); -#endif +#endif /* CONFIG_PM */ static void choose_address(struct usb_device *udev) { @@ -1471,6 +1471,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) kick_khubd(hub); } +#ifdef CONFIG_PM #ifdef CONFIG_USB_SUSPEND @@ -1569,8 +1570,6 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) return status; } -#endif - /* * usb_port_suspend - suspend a usb device's upstream port * @udev: device that's no longer in active use @@ -1593,11 +1592,7 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) */ int usb_port_suspend(struct usb_device *udev) { -#ifdef CONFIG_USB_SUSPEND return __usb_port_suspend(udev, udev->portnum); -#else - return 0; -#endif } /* @@ -1661,8 +1656,6 @@ static int finish_port_resume(struct usb_device *udev) return status; } -#ifdef CONFIG_USB_SUSPEND - static int hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) { @@ -1722,8 +1715,6 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) return status; } -#endif - /* * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate @@ -1739,17 +1730,15 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) */ int usb_port_resume(struct usb_device *udev) { - int status = 0; + int status; /* we change the device's upstream USB link, * but root hubs have no upstream USB link. */ if (udev->parent) { -#ifdef CONFIG_USB_SUSPEND // NOTE this fails if parent is also suspended... status = hub_port_resume(hdev_to_hub(udev->parent), udev->portnum, udev); -#endif } else status = finish_port_resume(udev); if (status < 0) @@ -1761,8 +1750,6 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; -#ifdef CONFIG_USB_SUSPEND - /* don't repeat RESUME sequence if this device * was already woken up by some other task */ @@ -1777,10 +1764,42 @@ static int remote_wakeup(struct usb_device *udev) if (status == 0) usb_resume_both(udev); usb_unlock_device(udev); -#endif return status; } +#else /* CONFIG_USB_SUSPEND */ + +/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ + +int usb_port_suspend(struct usb_device *udev) +{ + return 0; +} + +static inline int +finish_port_resume(struct usb_device *udev) +{ + return 0; +} + +static inline int +hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) +{ + return 0; +} + +int usb_port_resume(struct usb_device *udev) +{ + return 0; +} + +static inline int remote_wakeup(struct usb_device *udev) +{ + return 0; +} + +#endif + static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -1854,6 +1873,15 @@ static int hub_resume(struct usb_interface *intf) return 0; } +#else /* CONFIG_PM */ + +static inline int remote_wakeup(struct usb_device *udev) +{ + return 0; +} + +#endif + void usb_suspend_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); -- cgit v1.1 From fbf81c29a3c05cd227cad89435d71c15e958feaf Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Wed, 27 Sep 2006 11:58:53 -0700 Subject: USB: hub: Use usb_endpoint_* functions. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 64e80b9..3924dd0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -868,13 +868,8 @@ descriptor_error: endpoint = &desc->endpoint[0].desc; - /* Output endpoint? Curiouser and curiouser.. */ - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - goto descriptor_error; - - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + /* If it's not an interrupt in endpoint, we'd better punt! */ + if (!usb_endpoint_is_int_in(endpoint)) goto descriptor_error; /* We found a hub */ -- cgit v1.1 From d5cbad4b8b37acfde3e63d31b92561b87288ad0f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 11 Aug 2006 16:52:39 -0400 Subject: usbcore: khubd and busy-port handling We don't want khubd to start interfering in the device-resume process merely because the PORT_STATUS_C_SUSPEND feature happens to be set. Ports need to be marked as busy while a resume is taking place. In addition, so long as ports are marked as busy, khubd won't be able to clear their various status-change features. On an interrupt-driven root hub this could lead to an interrupt storm. Root hub IRQs should not be re-enabled until the busy_bits value is equal to 0. This patch (as765) fixes these two potential problems. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3924dd0..bdf5be0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1658,6 +1658,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) // dev_dbg(hub->intfdev, "resume port %d\n", port1); + set_bit(port1, hub->busy_bits); + /* see 7.1.7.7; affects power usage, but not budgeting */ status = clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); @@ -1707,6 +1709,10 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) if (status < 0) hub_port_logical_disconnect(hub, port1); + clear_bit(port1, hub->busy_bits); + if (!hub->hdev->parent && !hub->busy_bits[0]) + usb_enable_root_hub_irq(hub->hdev->bus); + return status; } @@ -2690,7 +2696,7 @@ static void hub_events(void) /* If this is a root hub, tell the HCD it's okay to * re-enable port-change interrupts now. */ - if (!hdev->parent) + if (!hdev->parent && !hub->busy_bits[0]) usb_enable_root_hub_irq(hdev->bus); loop: @@ -2865,6 +2871,9 @@ int usb_reset_device(struct usb_device *udev) break; } clear_bit(port1, parent_hub->busy_bits); + if (!parent_hdev->parent && !parent_hub->busy_bits[0]) + usb_enable_root_hub_irq(parent_hdev->bus); + if (ret < 0) goto re_enumerate; -- cgit v1.1 From 0165de09747be76b09ef769fcfed3514fe5f6509 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 25 Aug 2006 19:35:29 -0700 Subject: wusb: hub code recognizes wusb ports This patch enables the USB stack to recognize WUSB devices (from a WUSB HCD) and assigns them the proper speed setting (USB_SPEED_VARIABLE). 1. Introduce usb_hcd->wireless to mark a host controller instance as being wireless, and thus having wireless 'fake' ports. [discarded previous model of using a reserved bit in the port_stat struct to do this; thanks to Alan Stern for indicating the proper way to do it]. 2. Introduce hub.c:hub_is_wusb() that tests if a hub is a WUSB root hub (WUSB doesn't have non-root hubs). New code being pushed to linuxuwb.org requires this patch to connect WUSB devices. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bdf5be0..db4a9be 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1331,6 +1331,18 @@ static int hub_port_status(struct usb_hub *hub, int port1, return ret; } + +/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ +static unsigned hub_is_wusb(struct usb_hub *hub) +{ + struct usb_hcd *hcd; + if (hub->hdev->parent != NULL) /* not a root hub? */ + return 0; + hcd = container_of(hub->hdev->bus, struct usb_hcd, self); + return hcd->wireless; +} + + #define PORT_RESET_TRIES 5 #define SET_ADDRESS_TRIES 2 #define GET_DESCRIPTOR_TRIES 2 @@ -1371,7 +1383,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, /* if we`ve finished resetting, then break out of the loop */ if (!(portstatus & USB_PORT_STAT_RESET) && (portstatus & USB_PORT_STAT_ENABLE)) { - if (portstatus & USB_PORT_STAT_HIGH_SPEED) + if (hub_is_wusb(hub)) + udev->speed = USB_SPEED_VARIABLE; + else if (portstatus & USB_PORT_STAT_HIGH_SPEED) udev->speed = USB_SPEED_HIGH; else if (portstatus & USB_PORT_STAT_LOW_SPEED) udev->speed = USB_SPEED_LOW; -- cgit v1.1 From 5bb6e0ae8f9f3a215d6a7f99c8486b0301cc5db9 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 25 Aug 2006 19:35:30 -0700 Subject: wusb: handle wusb device ep0 speed settings This patch teaches the USB stack handling of WUSB devices (those whose speed is USB_SPEED_VARIABLE). For these devices, we need to set ep0's maxpacketsize to 512 (even though the device descriptor reports it as 0xff). New code being pushed to linuxuwb.org requires this patch to connect WUSB devices. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index db4a9be..1bd5ee2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2060,8 +2060,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. + * For Wireless USB devices, ep0 max packet is always 512 (tho + * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. */ switch (udev->speed) { + case USB_SPEED_VARIABLE: /* fixed at 512 */ + udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512); + break; case USB_SPEED_HIGH: /* fixed at 64 */ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); break; @@ -2131,6 +2136,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * down tremendously by NAKing the unexpectedly * early status stage. Also, retry on all errors; * some devices are flakey. + * 255 is for WUSB devices, we actually need to use 512. + * WUSB1.0[4.8.1]. */ for (j = 0; j < 3; ++j) { buf->bMaxPacketSize0 = 0; @@ -2140,7 +2147,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, buf, GET_DESCRIPTOR_BUFSIZE, (i ? USB_CTRL_GET_TIMEOUT : 1000)); switch (buf->bMaxPacketSize0) { - case 8: case 16: case 32: case 64: + case 8: case 16: case 32: case 64: case 255: if (buf->bDescriptorType == USB_DT_DEVICE) { r = 0; @@ -2214,7 +2221,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval) goto fail; - i = udev->descriptor.bMaxPacketSize0; + i = udev->descriptor.bMaxPacketSize0 == 0xff? + 512 : udev->descriptor.bMaxPacketSize0; if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { if (udev->speed != USB_SPEED_FULL || !(i == 8 || i == 16 || i == 32 || i == 64)) { -- cgit v1.1 From 83a07196735dbf371b61d6dffbb7e6a696c633c2 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Fri, 25 Aug 2006 19:35:31 -0700 Subject: wusb: pretty print new wireless USB devices when they connect New code being pushed to linuxuwb.org requires this patch to connect WUSB devices. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1bd5ee2..65720f2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2028,6 +2028,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int i, j, retval; unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; + char *speed, *type; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2084,17 +2085,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } + type = ""; + switch (udev->speed) { + case USB_SPEED_LOW: speed = "low"; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + case USB_SPEED_VARIABLE: + speed = "variable"; + type = "Wireless "; + break; + default: speed = "?"; break; + } dev_info (&udev->dev, - "%s %s speed USB device using %s and address %d\n", - (udev->config) ? "reset" : "new", - ({ char *speed; switch (udev->speed) { - case USB_SPEED_LOW: speed = "low"; break; - case USB_SPEED_FULL: speed = "full"; break; - case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; - }; speed;}), - udev->bus->controller->driver->name, - udev->devnum); + "%s %s speed %sUSB device using %s and address %d\n", + (udev->config) ? "reset" : "new", speed, type, + udev->bus->controller->driver->name, udev->devnum); /* Set up TT records, if needed */ if (hdev->tt) { -- cgit v1.1 From 511366da534bad226e89d294c3b3e910a2aaba6b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 14 Aug 2006 23:11:02 -0700 Subject: USB: usb-hub-driver-improve-use-of-ifdef fix Fix CONFIG_PM=n build. Cc: Alan Stern Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 65720f2..f5adce0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1895,6 +1895,8 @@ static inline int remote_wakeup(struct usb_device *udev) return 0; } +#define hub_suspend NULL +#define hub_resume NULL #endif void usb_suspend_root_hub(struct usb_device *hdev) -- cgit v1.1 From b6956ffa595db97656d5901ca8fec77ef272d41a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:46:48 -0400 Subject: usbcore: store each usb_device's level in the tree This patch (as778) adds a field to struct usb_device to store the device's level in the USB tree. In itself this number isn't really important. But the overhead is very low, and in a later patch it will be used for preventing bogus warnings from the lockdep checker. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f5adce0..78e910b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2414,6 +2414,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, usb_set_device_state(udev, USB_STATE_POWERED); udev->speed = USB_SPEED_UNKNOWN; udev->bus_mA = hub->mA_per_port; + udev->level = hdev->level + 1; /* set the address */ choose_address(udev); -- cgit v1.1 From 645daaab0b6adc35c1838df2a82f9d729fdb1767 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:47:02 -0400 Subject: usbcore: add autosuspend/autoresume infrastructure This patch (as739) adds the basic infrastructure for USB autosuspend and autoresume. The main features are: PM usage counters added to struct usb_device and struct usb_interface, indicating whether it's okay to autosuspend them or they are currently in use. Flag added to usb_device indicating whether the current suspend/resume operation originated from outside or as an autosuspend/autoresume. Flag added to usb_driver indicating whether the driver supports autosuspend. If not, no device bound to the driver will be autosuspended. Mutex added to usb_device for protecting PM operations. Unlike the device semaphore, the locking rule for the pm_mutex is that you must acquire the locks going _up_ the device tree. New routines handling autosuspend/autoresume requests for interfaces and devices. Suspend and resume requests are propagated up the device tree (but not outside the USB subsystem). work_struct added to usb_device, for carrying out delayed autosuspend requests. Autoresume added (and autosuspend prevented) during probe and disconnect. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 78e910b..dee812b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1017,19 +1017,22 @@ void usb_set_device_state(struct usb_device *udev, if (udev->state == USB_STATE_NOTATTACHED) ; /* do nothing */ else if (new_state != USB_STATE_NOTATTACHED) { - udev->state = new_state; /* root hub wakeup capabilities are managed out-of-band * and may involve silicon errata ... ignore them here. */ if (udev->parent) { - if (new_state == USB_STATE_CONFIGURED) + if (udev->state == USB_STATE_SUSPENDED + || new_state == USB_STATE_SUSPENDED) + ; /* No change to wakeup settings */ + else if (new_state == USB_STATE_CONFIGURED) device_init_wakeup(&udev->dev, (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP)); - else if (new_state != USB_STATE_SUSPENDED) + else device_init_wakeup(&udev->dev, 0); } + udev->state = new_state; } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); @@ -1507,7 +1510,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, * NOTE: OTG devices may issue remote wakeup (or SRP) even when * we don't explicitly enable it here. */ - if (device_may_wakeup(&udev->dev)) { + if (udev->do_remote_wakeup) { status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, USB_DEVICE_REMOTE_WAKEUP, 0, @@ -1533,7 +1536,8 @@ static int hub_port_suspend(struct usb_hub *hub, int port1, USB_CTRL_SET_TIMEOUT); } else { /* device has up to 10 msec to fully suspend */ - dev_dbg(&udev->dev, "usb suspend\n"); + dev_dbg(&udev->dev, "usb %ssuspend\n", + udev->auto_pm ? "auto-" : ""); usb_set_device_state(udev, USB_STATE_SUSPENDED); msleep(10); } @@ -1573,7 +1577,8 @@ static int __usb_port_suspend (struct usb_device *udev, int port1) status = hub_port_suspend(hdev_to_hub(udev->parent), port1, udev); else { - dev_dbg(&udev->dev, "usb suspend\n"); + dev_dbg(&udev->dev, "usb %ssuspend\n", + udev->auto_pm ? "auto-" : ""); usb_set_device_state(udev, USB_STATE_SUSPENDED); } return status; @@ -1687,7 +1692,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) /* drive resume for at least 20 msec */ if (udev) - dev_dbg(&udev->dev, "RESUME\n"); + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); msleep(25); #define LIVE_FLAGS ( USB_PORT_STAT_POWER \ @@ -1754,8 +1760,11 @@ int usb_port_resume(struct usb_device *udev) // NOTE this fails if parent is also suspended... status = hub_port_resume(hdev_to_hub(udev->parent), udev->portnum, udev); - } else + } else { + dev_dbg(&udev->dev, "usb %sresume\n", + udev->auto_pm ? "auto-" : ""); status = finish_port_resume(udev); + } if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", status); return status; @@ -1765,19 +1774,23 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; - /* don't repeat RESUME sequence if this device - * was already woken up by some other task - */ + /* All this just to avoid sending a port-resume message + * to the parent hub! */ + usb_lock_device(udev); + mutex_lock_nested(&udev->pm_mutex, udev->level); if (udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); /* TRSMRCY = 10 msec */ msleep(10); status = finish_port_resume(udev); + if (status == 0) + udev->dev.power.power_state.event = PM_EVENT_ON; } + mutex_unlock(&udev->pm_mutex); if (status == 0) - usb_resume_both(udev); + usb_autoresume_device(udev, 0); usb_unlock_device(udev); return status; } @@ -1834,7 +1847,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) == PM_EVENT_ON #endif ) { - dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); + if (!hdev->auto_pm) + dev_dbg(&intf->dev, "port %d nyet suspended\n", + port1); return -EBUSY; } } @@ -2587,7 +2602,7 @@ static void hub_events(void) * stub "device" node was never suspended. */ if (i) - usb_resume_both(hdev); + usb_autoresume_device(hdev, 0); /* If this is an inactive or suspended hub, do nothing */ if (hub->quiescing) @@ -2993,6 +3008,9 @@ int usb_reset_composite_device(struct usb_device *udev, return -EINVAL; } + /* Prevent autosuspend during the reset */ + usb_autoresume_device(udev, 1); + if (iface && iface->condition != USB_INTERFACE_BINDING) iface = NULL; @@ -3034,6 +3052,7 @@ int usb_reset_composite_device(struct usb_device *udev, } } + usb_autosuspend_device(udev, 1); return ret; } EXPORT_SYMBOL(usb_reset_composite_device); -- cgit v1.1 From 02c399ee45a54987c152fe5f627ed949bb55f187 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:47:11 -0400 Subject: usbcore: remove usb_suspend_root_hub This patch (as740) removes the existing support for autosuspend of root hubs. That support fit in rather awkwardly with the rest of usbcore and it was used only by ohci-hcd. It won't be needed any more since the hub driver will take care of autosuspending all hubs, root or external. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dee812b..7479bd3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -452,18 +452,14 @@ static void hub_power_on(struct usb_hub *hub) msleep(max(pgood_delay, (unsigned) 100)); } -static inline void __hub_quiesce(struct usb_hub *hub) +static void hub_quiesce(struct usb_hub *hub) { /* (nonblocking) khubd and related activity won't re-trigger */ hub->quiescing = 1; hub->activating = 0; hub->resume_root_hub = 0; -} -static void hub_quiesce(struct usb_hub *hub) -{ /* (blocking) stop khubd and related activity */ - __hub_quiesce(hub); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work(&hub->leds); @@ -1914,18 +1910,6 @@ static inline int remote_wakeup(struct usb_device *udev) #define hub_resume NULL #endif -void usb_suspend_root_hub(struct usb_device *hdev) -{ - struct usb_hub *hub = hdev_to_hub(hdev); - - /* This also makes any led blinker stop retriggering. We're called - * from irq, so the blinker might still be scheduled. Caller promises - * that the root hub status URB will be canceled. - */ - __hub_quiesce(hub); - mark_quiesced(to_usb_interface(hub->intfdev)); -} - void usb_resume_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); -- cgit v1.1 From ec17cf1cfe0b557210b27313bd584e9b5187d4ca Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 13 Sep 2006 21:38:41 +0200 Subject: USB: Remove unneeded void * casts in core files The patch removes unneeded casts for the following (void *) pointers: - struct file: private - struct urb: context - struct usb_bus: hcpriv - return value of kmalloc() The patch also contains some whitespace cleanup in the relevant areas. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7479bd3..c74baad 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -293,7 +293,7 @@ void usb_kick_khubd(struct usb_device *hdev) /* completion function, fires on port status changes and various faults */ static void hub_irq(struct urb *urb, struct pt_regs *regs) { - struct usb_hub *hub = (struct usb_hub *)urb->context; + struct usb_hub *hub = urb->context; int status; int i; unsigned long bits; @@ -311,7 +311,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs) goto resubmit; hub->error = urb->status; /* FALL THROUGH */ - + /* let khubd handle things */ case 0: /* we got data: port status changed */ bits = 0; -- cgit v1.1 From 353a4098c61272b33a02ec5802fb3859fec91a0e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 19 Sep 2006 10:07:58 -0400 Subject: USB: force root hub resume after power loss This patch(as785) forces the PM core to resume a root hub after a power loss during system sleep. If the root hub had been suspended before the system sleep then normally the PM core would not resume it afterward. Without this resume, various sorts of wakeup events (like port change events) can get lost. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c74baad..00441cd 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1053,6 +1053,12 @@ void usb_root_hub_lost_power(struct usb_device *rhdev) unsigned long flags; dev_warn(&rhdev->dev, "root hub lost power or was reset\n"); + + /* Make sure no potential wakeup events get lost, + * by forcing the root hub to be resumed. + */ + rhdev->dev.power.prev_state.event = PM_EVENT_ON; + spin_lock_irqsave(&device_state_lock, flags); hub = hdev_to_hub(rhdev); for (port1 = 1; port1 <= rhdev->maxchild; ++port1) { -- cgit v1.1 From fc849b85fb14ccbbc10098d501a870bc9b44a641 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 18 Sep 2006 16:53:26 -0700 Subject: USB: remove OTG build warning Somewhere along the line, a variable in a USB-OTG codepath stopped being used; this removes the relevant compiler warning. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb/core/hub.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 00441cd..2a8cb3c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1254,8 +1254,7 @@ int usb_new_device(struct usb_device *udev) USB_DT_OTG, (void **) &desc) == 0) { if (desc->bmAttributes & USB_OTG_HNP) { unsigned port1 = udev->portnum; - struct usb_device *root = udev->parent; - + dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n", (port1 == bus->otg_port) -- cgit v1.1