summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/config.c3
-rw-r--r--drivers/usb/core/devices.c8
-rw-r--r--drivers/usb/core/devio.c72
-rw-r--r--drivers/usb/core/file.c2
-rw-r--r--drivers/usb/core/hcd-pci.c151
-rw-r--r--drivers/usb/core/hcd.h4
-rw-r--r--drivers/usb/core/hub.c24
-rw-r--r--drivers/usb/core/inode.c1
-rw-r--r--drivers/usb/core/message.c25
-rw-r--r--drivers/usb/core/urb.c16
-rw-r--r--drivers/usb/core/usb.c13
-rw-r--r--drivers/usb/core/usb.h8
12 files changed, 167 insertions, 160 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 0b092bd..99595e0 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -10,7 +10,8 @@
#include <linux/slab.h>
#include <linux/device.h>
#include <asm/byteorder.h>
-
+#include "usb.h"
+#include "hcd.h"
#define USB_MAXALTSETTING 128 /* Hard limit */
#define USB_MAXENDPOINTS 30 /* Hard limit */
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 8b61bcd..ef0b357 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -59,6 +59,7 @@
#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
+#include "usb.h"
#include "hcd.h"
#define MAX_TOPO_LEVEL 6
@@ -636,11 +637,8 @@ static int usb_device_open(struct inode *inode, struct file *file)
static int usb_device_release(struct inode *inode, struct file *file)
{
- if (file->private_data) {
- kfree(file->private_data);
- file->private_data = NULL;
- }
-
+ kfree(file->private_data);
+ file->private_data = NULL;
return 0;
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index a047bc3..6bfab4b 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -213,12 +213,10 @@ static struct async *alloc_async(unsigned int numisoframes)
static void free_async(struct async *as)
{
- if (as->urb->transfer_buffer)
- kfree(as->urb->transfer_buffer);
- if (as->urb->setup_packet)
- kfree(as->urb->setup_packet);
+ kfree(as->urb->transfer_buffer);
+ kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
- kfree(as);
+ kfree(as);
}
static inline void async_newpending(struct async *as)
@@ -938,17 +936,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL;
}
if (!(as = alloc_async(uurb->number_of_packets))) {
- if (isopkt)
- kfree(isopkt);
- if (dr)
- kfree(dr);
+ kfree(isopkt);
+ kfree(dr);
return -ENOMEM;
}
if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) {
- if (isopkt)
- kfree(isopkt);
- if (dr)
- kfree(dr);
+ kfree(isopkt);
+ kfree(dr);
free_async(as);
return -ENOMEM;
}
@@ -967,8 +961,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->urb->iso_frame_desc[u].length = isopkt[u].length;
totlen += isopkt[u].length;
}
- if (isopkt)
- kfree(isopkt);
+ kfree(isopkt);
as->ps = ps;
as->userurb = arg;
if (uurb->endpoint & USB_DIR_IN)
@@ -1032,15 +1025,15 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (!(usb_pipeisoc(urb->pipe)))
- return 0;
- for (i = 0; i < urb->number_of_packets; i++) {
- if (put_user(urb->iso_frame_desc[i].actual_length,
- &userurb->iso_frame_desc[i].actual_length))
- return -EFAULT;
- if (put_user(urb->iso_frame_desc[i].status,
- &userurb->iso_frame_desc[i].status))
- return -EFAULT;
+ if (usb_pipeisoc(urb->pipe)) {
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (put_user(urb->iso_frame_desc[i].actual_length,
+ &userurb->iso_frame_desc[i].actual_length))
+ return -EFAULT;
+ if (put_user(urb->iso_frame_desc[i].status,
+ &userurb->iso_frame_desc[i].status))
+ return -EFAULT;
+ }
}
free_async(as);
@@ -1126,7 +1119,7 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb __user *)arg)->iso_frame_desc, arg);
+ return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
}
static int processcompl_compat(struct async *as, void __user * __user *arg)
@@ -1146,15 +1139,15 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (!(usb_pipeisoc(urb->pipe)))
- return 0;
- for (i = 0; i < urb->number_of_packets; i++) {
- if (put_user(urb->iso_frame_desc[i].actual_length,
- &userurb->iso_frame_desc[i].actual_length))
- return -EFAULT;
- if (put_user(urb->iso_frame_desc[i].status,
- &userurb->iso_frame_desc[i].status))
- return -EFAULT;
+ if (usb_pipeisoc(urb->pipe)) {
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (put_user(urb->iso_frame_desc[i].actual_length,
+ &userurb->iso_frame_desc[i].actual_length))
+ return -EFAULT;
+ if (put_user(urb->iso_frame_desc[i].status,
+ &userurb->iso_frame_desc[i].status))
+ return -EFAULT;
+ }
}
free_async(as);
@@ -1177,10 +1170,8 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
{
struct async *as;
- printk("reapurbnblock\n");
if (!(as = async_getcompleted(ps)))
return -EAGAIN;
- printk("reap got as %p\n", as);
return processcompl_compat(as, (void __user * __user *)arg);
}
@@ -1239,7 +1230,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
return -ENOMEM;
if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) {
if (copy_from_user (buf, ctrl.data, size)) {
- kfree (buf);
+ kfree(buf);
return -EFAULT;
}
} else {
@@ -1248,8 +1239,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
}
if (!connected(ps->dev)) {
- if (buf)
- kfree(buf);
+ kfree(buf);
return -ENODEV;
}
@@ -1311,8 +1301,8 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
&& size > 0
&& copy_to_user (ctrl.data, buf, size) != 0)
retval = -EFAULT;
- if (buf != NULL)
- kfree (buf);
+
+ kfree(buf);
return retval;
}
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 80ce964..38ed222 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -28,6 +28,8 @@
#endif
#include <linux/usb.h>
+#include "usb.h"
+
#define MAX_USB_MINORS 256
static struct file_operations *usb_minors[MAX_USB_MINORS];
static DEFINE_SPINLOCK(minor_lock);
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index b9a3dae..71b4a8d 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -33,7 +33,7 @@
#include "hcd.h"
-/* PCI-based HCs are normal, but custom bus glue should be ok */
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
/*-------------------------------------------------------------------------*/
@@ -67,8 +67,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
if (pci_enable_device (dev) < 0)
return -ENODEV;
- dev->current_state = 0;
- dev->dev.power.power_state = 0;
+ dev->current_state = PCI_D0;
+ dev->dev.power.power_state = PMSG_ON;
if (!dev->irq) {
dev_err (&dev->dev,
@@ -186,26 +186,14 @@ EXPORT_SYMBOL (usb_hcd_pci_remove);
#ifdef CONFIG_PM
-static char __attribute_used__ *pci_state(u32 state)
-{
- switch (state) {
- case 0: return "D0";
- case 1: return "D1";
- case 2: return "D2";
- case 3: return "D3hot";
- case 4: return "D3cold";
- }
- return NULL;
-}
-
/**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended
- * @state: state that the controller is going into
+ * @message: semantics in flux
*
* Store this function in the HCD's struct pci_driver as suspend().
*/
-int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
{
struct usb_hcd *hcd;
int retval = 0;
@@ -213,13 +201,23 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
hcd = pci_get_drvdata(dev);
+ /* FIXME until the generic PM interfaces change a lot more, this
+ * can't use PCI D1 and D2 states. For example, the confusion
+ * between messages and states will need to vanish, and messages
+ * will need to provide a target system state again.
+ *
+ * It'll be important to learn characteristics of the target state,
+ * especially on embedded hardware where the HCD will often be in
+ * charge of an external VBUS power supply and one or more clocks.
+ * Some target system states will leave them active; others won't.
+ * (With PCI, that's often handled by platform BIOS code.)
+ */
+
/* even when the PCI layer rejects some of the PCI calls
* below, HCs can try global suspend and reduce DMA traffic.
* PM-sensitive HCDs may already have done this.
*/
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- if (state > 4)
- state = 4;
switch (hcd->state) {
@@ -228,7 +226,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
*/
case HC_STATE_RUNNING:
hcd->state = HC_STATE_QUIESCING;
- retval = hcd->driver->suspend (hcd, state);
+ retval = hcd->driver->suspend (hcd, message);
if (retval) {
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
@@ -246,14 +244,11 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
* have been called, otherwise root hub timers still run ...
*/
case HC_STATE_SUSPENDED:
- if (state <= dev->current_state)
- break;
-
- /* no DMA or IRQs except in D0 */
- if (!dev->current_state) {
+ /* no DMA or IRQs except when HC is active */
+ if (dev->current_state == PCI_D0) {
+ free_irq (hcd->irq, hcd);
pci_save_state (dev);
pci_disable_device (dev);
- free_irq (hcd->irq, hcd);
}
if (!has_pci_pm) {
@@ -261,25 +256,19 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
break;
}
- /* POLICY: ignore D1/D2/D3hot differences;
- * we know D3hot will always work.
+ /* NOTE: dev->current_state becomes nonzero only here, and
+ * only for devices that support PCI PM. Also, exiting
+ * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
+ * some device state (e.g. as part of clock reinit).
*/
- retval = pci_set_power_state (dev, state);
- if (retval < 0 && state < 3) {
- retval = pci_set_power_state (dev, 3);
- if (retval == 0)
- state = 3;
- }
+ retval = pci_set_power_state (dev, PCI_D3hot);
if (retval == 0) {
- dev_dbg (hcd->self.controller, "--> PCI %s\n",
- pci_state(dev->current_state));
-#ifdef CONFIG_USB_SUSPEND
- pci_enable_wake (dev, state, hcd->remote_wakeup);
- pci_enable_wake (dev, 4, hcd->remote_wakeup);
-#endif
+ dev_dbg (hcd->self.controller, "--> PCI D3\n");
+ pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
+ pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
} else if (retval < 0) {
- dev_dbg (&dev->dev, "PCI %s suspend fail, %d\n",
- pci_state(state), retval);
+ dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
+ retval);
(void) usb_hcd_pci_resume (dev);
break;
}
@@ -287,13 +276,14 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
default:
dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
hcd->state);
+ WARN_ON(1);
retval = -EINVAL;
break;
}
/* update power_state **ONLY** to make sysfs happier */
if (retval == 0)
- dev->dev.power.power_state = state;
+ dev->dev.power.power_state = message;
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -308,7 +298,6 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
{
struct usb_hcd *hcd;
int retval;
- int has_pci_pm;
hcd = pci_get_drvdata(dev);
if (hcd->state != HC_STATE_SUSPENDED) {
@@ -316,31 +305,73 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
"can't resume, not suspended!\n");
return 0;
}
- has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- /* D3cold resume isn't usually reported this way... */
- dev_dbg(hcd->self.controller, "resume from PCI %s%s\n",
- pci_state(dev->current_state),
- has_pci_pm ? "" : " (legacy)");
+ /* NOTE: chip docs cover clean "real suspend" cases (what Linux
+ * calls "standby", "suspend to RAM", and so on). There are also
+ * dirty cases when swsusp fakes a suspend in "shutdown" mode.
+ */
+ if (dev->current_state != PCI_D0) {
+#ifdef DEBUG
+ int pci_pm;
+ u16 pmcr;
+
+ pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ pci_read_config_word(dev, pci_pm + PCI_PM_CTRL, &pmcr);
+ pmcr &= PCI_PM_CTRL_STATE_MASK;
+ if (pmcr) {
+ /* Clean case: power to USB and to HC registers was
+ * maintained; remote wakeup is easy.
+ */
+ dev_dbg(hcd->self.controller, "resume from PCI D%d\n",
+ pmcr);
+ } else {
+ /* Clean: HC lost Vcc power, D0 uninitialized
+ * + Vaux may have preserved port and transceiver
+ * state ... for remote wakeup from D3cold
+ * + or not; HCD must reinit + re-enumerate
+ *
+ * Dirty: D0 semi-initialized cases with swsusp
+ * + after BIOS init
+ * + after Linux init (HCD statically linked)
+ */
+ dev_dbg(hcd->self.controller,
+ "PCI D0, from previous PCI D%d\n",
+ dev->current_state);
+ }
+#endif
+ pci_enable_wake (dev, dev->current_state, 0);
+ pci_enable_wake (dev, PCI_D3cold, 0);
+ } else {
+ /* Same basic cases: clean (powered/not), dirty */
+ dev_dbg(hcd->self.controller, "PCI legacy resume\n");
+ }
+
+ /* NOTE: the PCI API itself is asymmetric here. We don't need to
+ * pci_set_power_state(PCI_D0) since that's part of re-enabling;
+ * but that won't re-enable bus mastering. Yet pci_disable_device()
+ * explicitly disables bus mastering...
+ */
+ retval = pci_enable_device (dev);
+ if (retval < 0) {
+ dev_err (hcd->self.controller,
+ "can't re-enable after resume, %d!\n", retval);
+ return retval;
+ }
+ pci_set_master (dev);
+ pci_restore_state (dev);
+
+ dev->dev.power.power_state = PMSG_ON;
hcd->state = HC_STATE_RESUMING;
-
- if (has_pci_pm)
- pci_set_power_state (dev, 0);
- dev->dev.power.power_state = 0;
+ hcd->saw_irq = 0;
retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
- hcd->driver->description, hcd);
+ hcd->irq_descr, hcd);
if (retval < 0) {
dev_err (hcd->self.controller,
"can't restore IRQ after resume!\n");
+ usb_hc_died (hcd);
return retval;
}
- hcd->saw_irq = 0;
- pci_restore_state (dev);
-#ifdef CONFIG_USB_SUSPEND
- pci_enable_wake (dev, dev->current_state, 0);
- pci_enable_wake (dev, 4, 0);
-#endif
retval = hcd->driver->resume (hcd);
if (!HC_IS_RUNNING (hcd->state)) {
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 6c625b3..f67cf1e 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -177,7 +177,7 @@ struct hc_driver {
* a whole, not just the root hub; they're for bus glue.
*/
/* called after all devices were suspended */
- int (*suspend) (struct usb_hcd *hcd, u32 state);
+ int (*suspend) (struct usb_hcd *hcd, pm_message_t message);
/* called before any devices get resumed */
int (*resume) (struct usb_hcd *hcd);
@@ -226,7 +226,7 @@ extern int usb_hcd_pci_probe (struct pci_dev *dev,
extern void usb_hcd_pci_remove (struct pci_dev *dev);
#ifdef CONFIG_PM
-extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
extern int usb_hcd_pci_resume (struct pci_dev *dev);
#endif /* CONFIG_PM */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index fa0dc4f..d2d648e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -381,7 +381,7 @@ static void hub_tt_kevent (void *arg)
dev_err (&hdev->dev,
"clear tt %d (%04x) error %d\n",
clear->tt, clear->devinfo, status);
- kfree (clear);
+ kfree(clear);
}
spin_unlock_irqrestore (&hub->tt.lock, flags);
}
@@ -728,15 +728,11 @@ static void hub_disconnect(struct usb_interface *intf)
list_del_init(&hub->event_list);
spin_unlock_irq(&hub_event_lock);
- if (hub->descriptor) {
- kfree(hub->descriptor);
- hub->descriptor = NULL;
- }
+ kfree(hub->descriptor);
+ hub->descriptor = NULL;
- if (hub->status) {
- kfree(hub->status);
- hub->status = NULL;
- }
+ kfree(hub->status);
+ hub->status = NULL;
if (hub->buffer) {
usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer,
@@ -1456,7 +1452,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
/* FIXME let caller ask to power down the port:
* - some devices won't enumerate without a VBUS power cycle
* - SRP saves power that way
- * - usb_suspend_device(dev,PM_SUSPEND_DISK)
+ * - usb_suspend_device(dev, PMSG_SUSPEND)
* That's easy if this hub can switch power per-port, and
* khubd reactivates the port later (timer, SRP, etc).
* Powerdown must be optional, because of reset/DFU.
@@ -1531,7 +1527,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
/*
* Devices on USB hub ports have only one "suspend" state, corresponding
- * to ACPI D2 (PM_SUSPEND_MEM), "may cause the device to lose some context".
+ * to ACPI D2, "may cause the device to lose some context".
* State transitions include:
*
* - suspend, resume ... when the VBUS power link stays live
@@ -1731,7 +1727,7 @@ static int finish_port_resume(struct usb_device *udev)
struct usb_driver *driver;
intf = udev->actconfig->interface[i];
- if (intf->dev.power.power_state == PM_SUSPEND_ON)
+ if (intf->dev.power.power_state == PMSG_SUSPEND)
continue;
if (!intf->dev.driver) {
/* FIXME maybe force to alt 0 */
@@ -1745,7 +1741,7 @@ static int finish_port_resume(struct usb_device *udev)
/* can we do better than just logging errors? */
status = driver->resume(intf);
- if (intf->dev.power.power_state != PM_SUSPEND_ON
+ if (intf->dev.power.power_state != PMSG_ON
|| status)
dev_dbg(&intf->dev,
"resume fail, state %d code %d\n",
@@ -2354,7 +2350,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
schedule_work (&hub->leds);
}
}
- kfree (qual);
+ kfree(qual);
}
static unsigned
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index d913407..f9f9561 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -41,6 +41,7 @@
#include <linux/parser.h>
#include <asm/byteorder.h>
#include "usb.h"
+#include "hcd.h"
static struct super_operations usbfs_ops;
static struct file_operations default_file_operations;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 40bdb38..e12c5be 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1133,29 +1133,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
/* prevent submissions using previous endpoint settings */
usb_disable_interface(dev, iface);
- /* 9.1.1.5 says:
- *
- * Configuring a device or changing an alternate setting
- * causes all of the status and configuration values
- * associated with endpoints in the affected interfaces to
- * be set to their default values. This includes setting
- * the data toggle of any endpoint using data toggles to
- * the value DATA0.
- *
- * Some devices take this too literally and don't reset the data
- * toggles if the new altsetting is the same as the old one (the
- * command isn't "changing" an alternate setting). We will manually
- * reset the toggles when the new and old altsettings are the same.
- * Most devices won't need this, but fortunately it doesn't happen
- * often.
- */
- if (iface->cur_altsetting == alt)
- manual = 1;
iface->cur_altsetting = alt;
/* If the interface only has one altsetting and the device didn't
- * accept the request (or whenever the old altsetting is the same
- * as the new one), we attempt to carry out the equivalent action
+ * accept the request, we attempt to carry out the equivalent action
* by manually clearing the HALT feature for each endpoint in the
* new altsetting.
*/
@@ -1202,7 +1183,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*
* Because this affects multiple interfaces, avoid using this with composite
* (multi-interface) devices. Instead, the driver for each interface may
- * use usb_set_interface() on the interfaces it claims. Resetting the whole
+ * use usb_set_interface() on the interfaces it claims. Be careful though;
+ * some devices don't support the SET_INTERFACE request, and others won't
+ * reset all the interface state (notably data toggles). Resetting the whole
* configuration would affect other drivers' interfaces.
*
* The caller must own the device lock.
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index dc838f8..1697215 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -420,12 +420,16 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
*
* Host Controller Drivers (HCDs) place all the URBs for a particular
* endpoint in a queue. Normally the queue advances as the controller
- * hardware processes each request. But when an URB terminates with any
- * fault (such as an error, or being unlinked) its queue stops, at least
- * until that URB's completion routine returns. It is guaranteed that
- * the queue will not restart until all its unlinked URBs have been fully
- * retired, with their completion routines run, even if that's not until
- * some time after the original completion handler returns.
+ * hardware processes each request. But when an URB terminates with an
+ * error its queue stops, at least until that URB's completion routine
+ * returns. It is guaranteed that the queue will not restart until all
+ * its unlinked URBs have been fully retired, with their completion
+ * routines run, even if that's not until some time after the original
+ * completion handler returns. Normally the same behavior and guarantees
+ * apply when an URB terminates because it was unlinked; however if an
+ * URB is unlinked before the hardware has started to execute it, then
+ * its queue is not guaranteed to stop until all the preceding URBs have
+ * completed.
*
* This means that USB device drivers can safely build deep queues for
* large or complex transfers, and clean them up reliably after any sort
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index f0534ee..c231b4b 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -50,13 +50,6 @@
#include "hcd.h"
#include "usb.h"
-extern int usb_hub_init(void);
-extern void usb_hub_cleanup(void);
-extern int usb_major_init(void);
-extern void usb_major_cleanup(void);
-extern int usb_host_init(void);
-extern void usb_host_cleanup(void);
-
const char *usbcore_name = "usbcore";
@@ -1382,13 +1375,13 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
-static int usb_generic_suspend(struct device *dev, u32 state)
+static int usb_generic_suspend(struct device *dev, pm_message_t message)
{
struct usb_interface *intf;
struct usb_driver *driver;
if (dev->driver == &usb_generic_driver)
- return usb_suspend_device (to_usb_device(dev), state);
+ return usb_suspend_device (to_usb_device(dev), message);
if ((dev->driver == NULL) ||
(dev->driver_data == &usb_generic_driver_data))
@@ -1402,7 +1395,7 @@ static int usb_generic_suspend(struct device *dev, u32 state)
return 0;
if (driver->suspend)
- return driver->suspend(intf, state);
+ return driver->suspend(intf, message);
return 0;
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 4c33eee..2c690f6 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -21,6 +21,13 @@ extern void usb_unlock_all_devices(void);
extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_resume_root_hub(struct usb_device *dev);
+extern int usb_hub_init(void);
+extern void usb_hub_cleanup(void);
+extern int usb_major_init(void);
+extern void usb_major_cleanup(void);
+extern int usb_host_init(void);
+extern void usb_host_cleanup(void);
+
/* for labeling diagnostics */
extern const char *usbcore_name;
@@ -30,6 +37,7 @@ extern struct file_operations usbfs_devices_fops;
extern struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);
+
struct dev_state {
struct list_head list; /* state list */
struct usb_device *dev;
OpenPOWER on IntegriCloud