diff options
-rw-r--r-- | drivers/usb/core/driver.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 9 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 1 | ||||
-rw-r--r-- | include/linux/usb.h | 1 |
6 files changed, 17 insertions, 12 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ca43a6f824ab..ba5bbc7eedcc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -1102,9 +1102,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1102 | if (udev->auto_pm) | 1102 | if (udev->auto_pm) |
1103 | autosuspend_check(udev); | 1103 | autosuspend_check(udev); |
1104 | 1104 | ||
1105 | /* 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 | */ | ||
1106 | } else { | 1108 | } else { |
1107 | cancel_delayed_work(&udev->autosuspend); | 1109 | cancel_delayed_work(&udev->autosuspend); |
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 | } | ||
1108 | if (parent) | 1115 | if (parent) |
1109 | usb_autosuspend_device(parent); | 1116 | usb_autosuspend_device(parent); |
1110 | } | 1117 | } |
@@ -1154,6 +1161,7 @@ static int usb_resume_both(struct usb_device *udev) | |||
1154 | status = -ENODEV; | 1161 | status = -ENODEV; |
1155 | goto done; | 1162 | goto done; |
1156 | } | 1163 | } |
1164 | udev->can_submit = 1; | ||
1157 | 1165 | ||
1158 | /* Propagate the resume up the tree, if necessary */ | 1166 | /* Propagate the resume up the tree, if necessary */ |
1159 | if (udev->state == USB_STATE_SUSPENDED) { | 1167 | if (udev->state == USB_STATE_SUSPENDED) { |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e5874e8b8cbc..2c79aa6ca2b4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1014,6 +1014,11 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) | |||
1014 | goto done; | 1014 | goto done; |
1015 | } | 1015 | } |
1016 | 1016 | ||
1017 | if (unlikely(!urb->dev->can_submit)) { | ||
1018 | rc = -EHOSTUNREACH; | ||
1019 | goto done; | ||
1020 | } | ||
1021 | |||
1017 | /* | 1022 | /* |
1018 | * Check the host controller's state and add the URB to the | 1023 | * Check the host controller's state and add the URB to the |
1019 | * endpoint's queue. | 1024 | * endpoint's queue. |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bd08d51d7f41..691acf2223c2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1955,14 +1955,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
1955 | struct usb_device *udev; | 1955 | struct usb_device *udev; |
1956 | 1956 | ||
1957 | udev = hdev->children [port1-1]; | 1957 | udev = hdev->children [port1-1]; |
1958 | if (udev && msg.event == PM_EVENT_SUSPEND && | 1958 | if (udev && udev->can_submit) { |
1959 | #ifdef CONFIG_USB_SUSPEND | ||
1960 | udev->state != USB_STATE_SUSPENDED | ||
1961 | #else | ||
1962 | udev->dev.power.power_state.event | ||
1963 | == PM_EVENT_ON | ||
1964 | #endif | ||
1965 | ) { | ||
1966 | if (!hdev->auto_pm) | 1959 | if (!hdev->auto_pm) |
1967 | dev_dbg(&intf->dev, "port %d nyet suspended\n", | 1960 | dev_dbg(&intf->dev, "port %d nyet suspended\n", |
1968 | port1); | 1961 | port1); |
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 76db76fdb4ec..c20c03aaf012 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c | |||
@@ -286,9 +286,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) | |||
286 | return -EINVAL; | 286 | return -EINVAL; |
287 | if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) | 287 | if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) |
288 | return -ENODEV; | 288 | return -ENODEV; |
289 | if (dev->bus->controller->power.power_state.event != PM_EVENT_ON | ||
290 | || dev->state == USB_STATE_SUSPENDED) | ||
291 | return -EHOSTUNREACH; | ||
292 | 289 | ||
293 | /* For now, get the endpoint from the pipe. Eventually drivers | 290 | /* For now, get the endpoint from the pipe. Eventually drivers |
294 | * will be required to set urb->ep directly and we will eliminate | 291 | * will be required to set urb->ep directly and we will eliminate |
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e5ff161776fa..8121edbd1494 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
@@ -272,6 +272,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) | |||
272 | dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; | 272 | dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; |
273 | /* ep0 maxpacket comes later, from device descriptor */ | 273 | /* ep0 maxpacket comes later, from device descriptor */ |
274 | usb_enable_endpoint(dev, &dev->ep0); | 274 | usb_enable_endpoint(dev, &dev->ep0); |
275 | dev->can_submit = 1; | ||
275 | 276 | ||
276 | /* Save readable and stable topology id, distinguishing devices | 277 | /* Save readable and stable topology id, distinguishing devices |
277 | * by location for diagnostics, tools, driver model, etc. The | 278 | * by location for diagnostics, tools, driver model, etc. The |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 5b14b4c81fd6..e5b35e0dca23 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -383,6 +383,7 @@ struct usb_device { | |||
383 | u8 portnum; /* Parent port number (origin 1) */ | 383 | u8 portnum; /* Parent port number (origin 1) */ |
384 | u8 level; /* Number of USB hub ancestors */ | 384 | u8 level; /* Number of USB hub ancestors */ |
385 | 385 | ||
386 | unsigned can_submit:1; /* URBs may be submitted */ | ||
386 | unsigned discon_suspended:1; /* Disconnected while suspended */ | 387 | unsigned discon_suspended:1; /* Disconnected while suspended */ |
387 | unsigned have_langid:1; /* whether string_langid is valid */ | 388 | unsigned have_langid:1; /* whether string_langid is valid */ |
388 | unsigned authorized:1; /* Policy has determined we can use it */ | 389 | unsigned authorized:1; /* Policy has determined we can use it */ |