aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/driver.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-12 18:49:10 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-12 18:49:10 -0400
commit117494a1b65183f0e3fcc817b07944bc5c465050 (patch)
treec375cf06bdf869f2b870fe61808b060c4fadab45 /drivers/usb/core/driver.c
parent4d5709a7b7d54fc5882d2943a14988a92d48c00a (diff)
parentd1aa3e6aa8edfeb864af7c930523d9e588b28bea (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (142 commits) USB: fix race in autosuspend reschedule atmel_usba_udc: Keep track of the device status USB: Nikon D40X unusual_devs entry USB: serial core should respect driver requirements USB: documentation for USB power management USB: skip autosuspended devices during system resume USB: mutual exclusion for EHCI init and port resets USB: allow usbstorage to have LUNS greater than 2Tb USB: Adding support for SHARP WS011SH to ipaq.c USB: add atmel_usba_udc driver USB: ohci SSB bus glue USB: ehci build fixes on au1xxx, ppc-soc USB: add runtime frame_no quirk for big-endian OHCI USB: funsoft: Fix termios USB: visor: termios bits USB: unusual_devs entry for Nikon DSC D2Xs USB: re-remove <linux/usb_sl811.h> USB: move <linux/usb_gadget.h> to <linux/usb/gadget.h> USB: Export URB statistics for powertop USB: serial gadget: Disable endpoints on unload ...
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r--drivers/usb/core/driver.c90
1 files changed, 57 insertions, 33 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 63b1243a913..c27bc080d84 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
202 intf = to_usb_interface(dev); 202 intf = to_usb_interface(dev);
203 udev = interface_to_usbdev(intf); 203 udev = interface_to_usbdev(intf);
204 204
205 if (udev->authorized == 0) {
206 dev_err(&intf->dev, "Device is not authorized for usage\n");
207 return -ENODEV;
208 }
209
205 id = usb_match_id(intf, driver->id_table); 210 id = usb_match_id(intf, driver->id_table);
206 if (!id) 211 if (!id)
207 id = usb_match_dynamic_id(intf, driver); 212 id = usb_match_dynamic_id(intf, driver);
@@ -945,11 +950,11 @@ done:
945#ifdef CONFIG_USB_SUSPEND 950#ifdef CONFIG_USB_SUSPEND
946 951
947/* Internal routine to check whether we may autosuspend a device. */ 952/* Internal routine to check whether we may autosuspend a device. */
948static int autosuspend_check(struct usb_device *udev) 953static int autosuspend_check(struct usb_device *udev, int reschedule)
949{ 954{
950 int i; 955 int i;
951 struct usb_interface *intf; 956 struct usb_interface *intf;
952 unsigned long suspend_time; 957 unsigned long suspend_time, j;
953 958
954 /* For autosuspend, fail fast if anything is in use or autosuspend 959 /* For autosuspend, fail fast if anything is in use or autosuspend
955 * is disabled. Also fail if any interfaces require remote wakeup 960 * is disabled. Also fail if any interfaces require remote wakeup
@@ -991,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev)
991 } 996 }
992 997
993 /* If everything is okay but the device hasn't been idle for long 998 /* If everything is okay but the device hasn't been idle for long
994 * enough, queue a delayed autosuspend request. 999 * enough, queue a delayed autosuspend request. If the device
1000 * _has_ been idle for long enough and the reschedule flag is set,
1001 * likewise queue a delayed (1 second) autosuspend request.
995 */ 1002 */
996 if (time_after(suspend_time, jiffies)) { 1003 j = jiffies;
1004 if (time_before(j, suspend_time))
1005 reschedule = 1;
1006 else
1007 suspend_time = j + HZ;
1008 if (reschedule) {
997 if (!timer_pending(&udev->autosuspend.timer)) { 1009 if (!timer_pending(&udev->autosuspend.timer)) {
998
999 /* The value of jiffies may change between the
1000 * time_after() comparison above and the subtraction
1001 * below. That's okay; the system behaves sanely
1002 * when a timer is registered for the present moment
1003 * or for the past.
1004 */
1005 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, 1010 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1006 round_jiffies_relative(suspend_time - jiffies)); 1011 round_jiffies_relative(suspend_time - j));
1007 } 1012 }
1008 return -EAGAIN; 1013 return -EAGAIN;
1009 } 1014 }
1010 return 0; 1015 return 0;
@@ -1012,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev)
1012 1017
1013#else 1018#else
1014 1019
1015static inline int autosuspend_check(struct usb_device *udev) 1020static inline int autosuspend_check(struct usb_device *udev, int reschedule)
1016{ 1021{
1017 return 0; 1022 return 0;
1018} 1023}
@@ -1069,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
1069 udev->do_remote_wakeup = device_may_wakeup(&udev->dev); 1074 udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
1070 1075
1071 if (udev->auto_pm) { 1076 if (udev->auto_pm) {
1072 status = autosuspend_check(udev); 1077 status = autosuspend_check(udev, 0);
1073 if (status < 0) 1078 if (status < 0)
1074 goto done; 1079 goto done;
1075 } 1080 }
@@ -1083,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
1083 break; 1088 break;
1084 } 1089 }
1085 } 1090 }
1086 if (status == 0) { 1091 if (status == 0)
1087
1088 /* Non-root devices don't need to do anything for FREEZE
1089 * or PRETHAW. */
1090 if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
1091 msg.event == PM_EVENT_PRETHAW))
1092 goto done;
1093 status = usb_suspend_device(udev, msg); 1092 status = usb_suspend_device(udev, msg);
1094 }
1095 1093
1096 /* If the suspend failed, resume interfaces that did get suspended */ 1094 /* If the suspend failed, resume interfaces that did get suspended */
1097 if (status != 0) { 1095 if (status != 0) {
@@ -1102,12 +1100,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
1102 1100
1103 /* Try another autosuspend when the interfaces aren't busy */ 1101 /* Try another autosuspend when the interfaces aren't busy */
1104 if (udev->auto_pm) 1102 if (udev->auto_pm)
1105 autosuspend_check(udev); 1103 autosuspend_check(udev, status == -EBUSY);
1106 1104
1107 /* If the suspend succeeded, propagate it up the tree */ 1105 /* If the suspend succeeded then prevent any more URB submissions,
1106 * flush any outstanding URBs, and propagate the suspend up the tree.
1107 */
1108 } else { 1108 } else {
1109 cancel_delayed_work(&udev->autosuspend); 1109 cancel_delayed_work(&udev->autosuspend);
1110 if (parent) 1110 udev->can_submit = 0;
1111 for (i = 0; i < 16; ++i) {
1112 usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
1113 usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
1114 }
1115
1116 /* If this is just a FREEZE or a PRETHAW, udev might
1117 * not really be suspended. Only true suspends get
1118 * propagated up the device tree.
1119 */
1120 if (parent && udev->state == USB_STATE_SUSPENDED)
1111 usb_autosuspend_device(parent); 1121 usb_autosuspend_device(parent);
1112 } 1122 }
1113 1123
@@ -1156,6 +1166,7 @@ static int usb_resume_both(struct usb_device *udev)
1156 status = -ENODEV; 1166 status = -ENODEV;
1157 goto done; 1167 goto done;
1158 } 1168 }
1169 udev->can_submit = 1;
1159 1170
1160 /* Propagate the resume up the tree, if necessary */ 1171 /* Propagate the resume up the tree, if necessary */
1161 if (udev->state == USB_STATE_SUSPENDED) { 1172 if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
1529 1540
1530static int usb_suspend(struct device *dev, pm_message_t message) 1541static int usb_suspend(struct device *dev, pm_message_t message)
1531{ 1542{
1543 struct usb_device *udev;
1544
1532 if (!is_usb_device(dev)) /* Ignore PM for interfaces */ 1545 if (!is_usb_device(dev)) /* Ignore PM for interfaces */
1533 return 0; 1546 return 0;
1534 return usb_external_suspend_device(to_usb_device(dev), message); 1547 udev = to_usb_device(dev);
1548
1549 /* If udev is already suspended, we can skip this suspend and
1550 * we should also skip the upcoming system resume. */
1551 if (udev->state == USB_STATE_SUSPENDED) {
1552 udev->skip_sys_resume = 1;
1553 return 0;
1554 }
1555
1556 udev->skip_sys_resume = 0;
1557 return usb_external_suspend_device(udev, message);
1535} 1558}
1536 1559
1537static int usb_resume(struct device *dev) 1560static int usb_resume(struct device *dev)
@@ -1542,13 +1565,14 @@ static int usb_resume(struct device *dev)
1542 return 0; 1565 return 0;
1543 udev = to_usb_device(dev); 1566 udev = to_usb_device(dev);
1544 1567
1545 /* If autoresume is disabled then we also want to prevent resume 1568 /* If udev->skip_sys_resume is set then udev was already suspended
1546 * during system wakeup. However, a "persistent-device" reset-resume 1569 * when the system suspend started, so we don't want to resume
1547 * after power loss counts as a wakeup event. So allow a 1570 * udev during this system wakeup. However a reset-resume counts
1548 * reset-resume to occur if remote wakeup is enabled. */ 1571 * as a wakeup event, so allow a reset-resume to occur if remote
1549 if (udev->autoresume_disabled) { 1572 * wakeup is enabled. */
1573 if (udev->skip_sys_resume) {
1550 if (!(udev->reset_resume && udev->do_remote_wakeup)) 1574 if (!(udev->reset_resume && udev->do_remote_wakeup))
1551 return -EPERM; 1575 return -EHOSTUNREACH;
1552 } 1576 }
1553 return usb_external_resume_device(udev); 1577 return usb_external_resume_device(udev);
1554} 1578}