aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-07-01 22:13:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:58:50 -0400
commit114b368c07964caa3f4e1fa575b16e87fa11936c (patch)
tree74500e47040be3bf4923eebd60404fc7b62004a9 /drivers/usb/core
parent2bf4086d7a7722b470aa24e1be725cc58619c6fe (diff)
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 <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/driver.c40
-rw-r--r--drivers/usb/core/generic.c3
-rw-r--r--drivers/usb/core/hub.c47
3 files changed, 29 insertions, 61 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 92ecc4eb1e8..affbfb53eb5 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -757,11 +757,13 @@ static int suspend_device(struct usb_device *udev, pm_message_t msg)
757 struct usb_device_driver *udriver; 757 struct usb_device_driver *udriver;
758 int status = 0; 758 int status = 0;
759 759
760 if (udev->state == USB_STATE_NOTATTACHED ||
761 udev->state == USB_STATE_SUSPENDED)
762 goto done;
763
760 if (udev->dev.driver == NULL) 764 if (udev->dev.driver == NULL)
761 goto done; 765 goto done;
762 udriver = to_usb_device_driver(udev->dev.driver); 766 udriver = to_usb_device_driver(udev->dev.driver);
763 if (udev->dev.power.power_state.event == msg.event)
764 goto done;
765 status = udriver->suspend(udev, msg); 767 status = udriver->suspend(udev, msg);
766 768
767done: 769done:
@@ -776,14 +778,13 @@ static int resume_device(struct usb_device *udev)
776 struct usb_device_driver *udriver; 778 struct usb_device_driver *udriver;
777 int status = 0; 779 int status = 0;
778 780
779 if (udev->dev.power.power_state.event == PM_EVENT_ON) 781 if (udev->state == USB_STATE_NOTATTACHED ||
782 udev->state != USB_STATE_SUSPENDED)
780 goto done; 783 goto done;
781 784
782 if (udev->dev.driver == NULL) 785 if (udev->dev.driver == NULL)
783 goto done; 786 goto done;
784 udriver = to_usb_device_driver(udev->dev.driver); 787 udriver = to_usb_device_driver(udev->dev.driver);
785 if (udev->state == USB_STATE_NOTATTACHED)
786 goto done;
787 status = udriver->resume(udev); 788 status = udriver->resume(udev);
788 789
789done: 790done:
@@ -798,14 +799,14 @@ static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
798 struct usb_driver *driver; 799 struct usb_driver *driver;
799 int status = 0; 800 int status = 0;
800 801
801 if (intf->dev.driver == NULL) 802 /* with no hardware, USB interfaces only use FREEZE and ON states */
803 if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
804 !is_active(intf))
802 goto done; 805 goto done;
803 806
804 driver = to_usb_driver(intf->dev.driver); 807 if (intf->dev.driver == NULL)
805
806 /* with no hardware, USB interfaces only use FREEZE and ON states */
807 if (!is_active(intf))
808 goto done; 808 goto done;
809 driver = to_usb_driver(intf->dev.driver);
809 810
810 if (driver->suspend && driver->resume) { 811 if (driver->suspend && driver->resume) {
811 status = driver->suspend(intf, msg); 812 status = driver->suspend(intf, msg);
@@ -831,25 +832,16 @@ done:
831static int resume_interface(struct usb_interface *intf) 832static int resume_interface(struct usb_interface *intf)
832{ 833{
833 struct usb_driver *driver; 834 struct usb_driver *driver;
834 struct usb_device *udev;
835 int status = 0; 835 int status = 0;
836 836
837 if (intf->dev.power.power_state.event == PM_EVENT_ON) 837 if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
838 is_active(intf))
838 goto done; 839 goto done;
839 840
840 if (intf->dev.driver == NULL) 841 if (intf->dev.driver == NULL)
841 goto done; 842 goto done;
842
843 driver = to_usb_driver(intf->dev.driver); 843 driver = to_usb_driver(intf->dev.driver);
844 844
845 udev = interface_to_usbdev(intf);
846 if (udev->state == USB_STATE_NOTATTACHED)
847 goto done;
848
849 /* if driver was suspended, it has a resume method;
850 * however, sysfs can wrongly mark things as suspended
851 * (on the "no suspend method" FIXME path above)
852 */
853 if (driver->resume) { 845 if (driver->resume) {
854 status = driver->resume(intf); 846 status = driver->resume(intf);
855 if (status) 847 if (status)
@@ -904,6 +896,12 @@ int usb_resume_both(struct usb_device *udev)
904 int i; 896 int i;
905 struct usb_interface *intf; 897 struct usb_interface *intf;
906 898
899 /* Can't resume if the parent is suspended */
900 if (udev->parent && udev->parent->state == USB_STATE_SUSPENDED) {
901 dev_warn(&udev->dev, "can't resume; parent is suspended\n");
902 return -EHOSTUNREACH;
903 }
904
907 status = resume_device(udev); 905 status = resume_device(udev);
908 if (status == 0 && udev->actconfig) { 906 if (status == 0 && udev->actconfig) {
909 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { 907 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index b6dacd7551d..5358e656477 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -195,9 +195,6 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
195 195
196static int generic_resume(struct usb_device *udev) 196static int generic_resume(struct usb_device *udev)
197{ 197{
198 if (udev->state == USB_STATE_NOTATTACHED)
199 return 0;
200
201 return usb_port_resume(udev); 198 return usb_port_resume(udev);
202} 199}
203 200
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 7af53db4d76..a310c7cede9 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)
1556 if (port1 < 0) 1556 if (port1 < 0)
1557 return port1; 1557 return port1;
1558 1558
1559 if (udev->state == USB_STATE_SUSPENDED
1560 || udev->state == USB_STATE_NOTATTACHED) {
1561 return 0;
1562 }
1563
1564 /* all interfaces must already be suspended */
1565 if (udev->actconfig) {
1566 int i;
1567
1568 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
1569 struct usb_interface *intf;
1570
1571 intf = udev->actconfig->interface[i];
1572 if (is_active(intf)) {
1573 dev_dbg(&intf->dev, "nyet suspended\n");
1574 return -EBUSY;
1575 }
1576 }
1577 }
1578
1579 /* we change the device's upstream USB link, 1559 /* we change the device's upstream USB link,
1580 * but root hubs have no upstream USB link. 1560 * but root hubs have no upstream USB link.
1581 */ 1561 */
@@ -1614,8 +1594,6 @@ static int __usb_port_suspend (struct usb_device *udev, int port1)
1614int usb_port_suspend(struct usb_device *udev) 1594int usb_port_suspend(struct usb_device *udev)
1615{ 1595{
1616#ifdef CONFIG_USB_SUSPEND 1596#ifdef CONFIG_USB_SUSPEND
1617 if (udev->state == USB_STATE_NOTATTACHED)
1618 return -ENODEV;
1619 return __usb_port_suspend(udev, udev->portnum); 1597 return __usb_port_suspend(udev, udev->portnum);
1620#else 1598#else
1621 return 0; 1599 return 0;
@@ -1761,24 +1739,17 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
1761 */ 1739 */
1762int usb_port_resume(struct usb_device *udev) 1740int usb_port_resume(struct usb_device *udev)
1763{ 1741{
1764 int status; 1742 int status = 0;
1765
1766 if (udev->state == USB_STATE_NOTATTACHED)
1767 return -ENODEV;
1768 1743
1769 /* we change the device's upstream USB link, 1744 /* we change the device's upstream USB link,
1770 * but root hubs have no upstream USB link. 1745 * but root hubs have no upstream USB link.
1771 */ 1746 */
1772 if (udev->parent) { 1747 if (udev->parent) {
1773#ifdef CONFIG_USB_SUSPEND 1748#ifdef CONFIG_USB_SUSPEND
1774 if (udev->state == USB_STATE_SUSPENDED) { 1749 // NOTE this fails if parent is also suspended...
1775 // NOTE swsusp may bork us, device state being wrong... 1750 status = hub_port_resume(hdev_to_hub(udev->parent),
1776 // NOTE this fails if parent is also suspended... 1751 udev->portnum, udev);
1777 status = hub_port_resume(hdev_to_hub(udev->parent),
1778 udev->portnum, udev);
1779 } else
1780#endif 1752#endif
1781 status = 0;
1782 } else 1753 } else
1783 status = finish_port_resume(udev); 1754 status = finish_port_resume(udev);
1784 if (status < 0) 1755 if (status < 0)
@@ -1821,12 +1792,14 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
1821 struct usb_device *udev; 1792 struct usb_device *udev;
1822 1793
1823 udev = hdev->children [port1-1]; 1794 udev = hdev->children [port1-1];
1824 if (udev && (udev->dev.power.power_state.event 1795 if (udev && msg.event == PM_EVENT_SUSPEND &&
1825 == PM_EVENT_ON
1826#ifdef CONFIG_USB_SUSPEND 1796#ifdef CONFIG_USB_SUSPEND
1827 || udev->state != USB_STATE_SUSPENDED 1797 udev->state != USB_STATE_SUSPENDED
1798#else
1799 udev->dev.power.power_state.event
1800 == PM_EVENT_ON
1828#endif 1801#endif
1829 )) { 1802 ) {
1830 dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); 1803 dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
1831 return -EBUSY; 1804 return -EBUSY;
1832 } 1805 }