diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/config.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/devices.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 61 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 27 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 27 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 19 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 8 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 6 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 31 |
10 files changed, 127 insertions, 59 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index a16c538d0132..0d3af6a6ee49 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -105,7 +105,7 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ep->ss_ep_comp->extralen = i; buffer += i; size -= i; - retval = buffer - buffer_start + i; + retval = buffer - buffer_start; if (num_skipped > 0) dev_dbg(ddev, "skipped %d descriptor%s after %s\n", num_skipped, plural(num_skipped), diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 96f11715cd26..355dffcc23b0 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -494,7 +494,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, return 0; /* allocate 2^1 pages = 8K (on i386); * should be more than enough for one device */ - pages_start = (char *)__get_free_pages(GFP_KERNEL, 1); + pages_start = (char *)__get_free_pages(GFP_NOIO, 1); if (!pages_start) return -ENOMEM; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4247eccf858c..5ae4099fb4c1 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1139,6 +1139,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, free_async(as); return -ENOMEM; } + /* Isochronous input data may end up being discontiguous + * if some of the packets are short. Clear the buffer so + * that the gaps don't leak kernel data to userspace. + */ + if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO) + memset(as->urb->transfer_buffer, 0, + uurb->buffer_length); } as->urb->dev = ps->dev; as->urb->pipe = (uurb->type << 30) | @@ -1240,10 +1247,14 @@ static int processcompl(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; - if (as->userbuffer) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, - urb->transfer_buffer_length)) + if (as->userbuffer && urb->actual_length) { + if (urb->number_of_packets > 0) /* Isochronous */ + i = urb->transfer_buffer_length; + else /* Non-Isoc */ + i = urb->actual_length; + if (copy_to_user(as->userbuffer, urb->transfer_buffer, i)) goto err_out; + } if (put_user(as->status, &userurb->status)) goto err_out; if (put_user(urb->actual_length, &userurb->actual_length)) @@ -1262,14 +1273,11 @@ static int processcompl(struct async *as, void __user * __user *arg) } } - free_async(as); - if (put_user(addr, (void __user * __user *)arg)) return -EFAULT; return 0; err_out: - free_async(as); return -EFAULT; } @@ -1299,8 +1307,11 @@ static struct async *reap_as(struct dev_state *ps) static int proc_reapurb(struct dev_state *ps, void __user *arg) { struct async *as = reap_as(ps); - if (as) - return processcompl(as, (void __user * __user *)arg); + if (as) { + int retval = processcompl(as, (void __user * __user *)arg); + free_async(as); + return retval; + } if (signal_pending(current)) return -EINTR; return -EIO; @@ -1308,11 +1319,16 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg) static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) { + int retval; struct async *as; - if (!(as = async_getcompleted(ps))) - return -EAGAIN; - return processcompl(as, (void __user * __user *)arg); + as = async_getcompleted(ps); + retval = -EAGAIN; + if (as) { + retval = processcompl(as, (void __user * __user *)arg); + free_async(as); + } + return retval; } #ifdef CONFIG_COMPAT @@ -1363,9 +1379,9 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; - if (as->userbuffer) + if (as->userbuffer && urb->actual_length) if (copy_to_user(as->userbuffer, urb->transfer_buffer, - urb->transfer_buffer_length)) + urb->actual_length)) return -EFAULT; if (put_user(as->status, &userurb->status)) return -EFAULT; @@ -1385,7 +1401,6 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) } } - free_async(as); if (put_user(ptr_to_compat(addr), (u32 __user *)arg)) return -EFAULT; return 0; @@ -1394,8 +1409,11 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) { struct async *as = reap_as(ps); - if (as) - return processcompl_compat(as, (void __user * __user *)arg); + if (as) { + int retval = processcompl_compat(as, (void __user * __user *)arg); + free_async(as); + return retval; + } if (signal_pending(current)) return -EINTR; return -EIO; @@ -1403,11 +1421,16 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) { + int retval; struct async *as; - if (!(as = async_getcompleted(ps))) - return -EAGAIN; - return processcompl_compat(as, (void __user * __user *)arg); + retval = -EAGAIN; + as = async_getcompleted(ps); + if (as) { + retval = processcompl_compat(as, (void __user * __user *)arg); + free_async(as); + } + return retval; } #endif diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 07f503aa9078..c209dbe4f6c6 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1754,9 +1754,6 @@ int usb_resume(struct device *dev, pm_message_t msg) udev = to_usb_device(dev); -/* At otg mode, if it is a device wakeup interrupt, the host should do nothing */ - if (udev->bus->is_b_host) - return 0; /* If udev->skip_sys_resume is set then udev was already suspended * when the system sleep started, so we don't want to resume it * during this system wakeup. diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 539a2c0dde00..66e8a424c9f4 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -196,6 +196,7 @@ extern void usb_host_set_wakeup(struct device *wkup_dev, bool para); static int generic_suspend(struct usb_device *udev, pm_message_t msg) { int rc; + u32 temp; /* Normal USB devices suspend through their upstream port. * Root hubs don't have upstream ports to suspend, @@ -203,7 +204,25 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) * interfaces manually by doing a bus (or "global") suspend. */ if (!udev->parent) { + struct usb_hcd *hcd = + container_of(udev->bus, struct usb_hcd, self); + struct fsl_usb2_platform_data *pdata; + pdata = hcd->self.controller->platform_data; + rc = hcd_bus_suspend(udev, msg); + + if (device_may_wakeup(hcd->self.controller)) { + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* enable remote wake up irq */ + usb_host_set_wakeup(hcd->self.controller, true); + + /* Put PHY into low power mode */ + temp = readl(hcd->regs + 0x184); + writel(temp | (1 << 23), (hcd->regs + 0x184)); + + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); + } /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ } else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) @@ -217,6 +236,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) static int generic_resume(struct usb_device *udev, pm_message_t msg) { int rc; + u32 temp; /* Normal USB devices resume/reset through their upstream port. * Root hubs don't have upstream ports to resume or reset, @@ -224,6 +244,13 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg) * interfaces manually by doing a bus (or "global") resume. */ if (!udev->parent) { + struct usb_hcd *hcd = + container_of(udev->bus, struct usb_hcd, self); + + if (device_may_wakeup(hcd->self.controller)) { + temp = readl(hcd->regs + 0x184); + writel(temp & (~(1 << 23)), (hcd->regs + 0x184)); + } rc = hcd_bus_resume(udev, msg); } else rc = usb_port_resume(udev, msg); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2f47bdc7c93a..d27ad104731c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1739,7 +1739,6 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) int status; int old_state = hcd->state; - printk("%s\n", __func__); dev_dbg(&rhdev->dev, "bus %s%s\n", (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend"); if (!hcd->driver->bus_suspend) { @@ -1877,6 +1876,7 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; + struct fsl_usb2_platform_data *pdata; unsigned long flags; irqreturn_t rc; @@ -1885,14 +1885,25 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) * assume it's never used. */ local_irq_save(flags); - /* At otg mode, the host does need to handle device interrupt */ - if (hcd->self.is_b_host){ - local_irq_restore(flags); - return IRQ_NONE; - } - else if (unlikely(hcd->state == HC_STATE_HALT || - !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + /* Need open clock for register access */ + pdata = hcd->self.controller->platform_data; + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(true); + + /* if receive a remote wakeup interrrupt after suspend */ + if (usb_host_wakeup_irq(hcd->self.controller)) { + /* disable remote wake up irq */ + usb_host_set_wakeup(hcd->self.controller, false); + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + hcd->driver->irq(hcd); + rc = IRQ_HANDLED; + } else rc = IRQ_NONE; + } else if (unlikely(hcd->state == HC_STATE_HALT)) { + rc = IRQ_NONE; } else if (hcd->driver->irq(hcd) == IRQ_NONE) { rc = IRQ_NONE; } else { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index cc8f911afbc4..3bcd08fbfb71 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -457,7 +457,7 @@ resubmit: static inline int hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) { - return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), + return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo, tt, NULL, 0, 1000); } @@ -1177,6 +1177,12 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) "Unsupported bus topology: hub nested too deep\n"); return -E2BIG; } +#ifdef CONFIG_PM + /* Defaultly disable autosuspend for hub and reley on sys + * to enable it. + */ + hdev->autosuspend_disabled = 1; +#endif #ifdef CONFIG_USB_OTG_BLACKLIST_HUB if (hdev->parent) { @@ -2298,6 +2304,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; + /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; @@ -2321,15 +2328,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) static int hub_resume(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); - struct usb_hcd *hcd = bus_to_hcd(hub->hdev->bus); dev_dbg(&intf->dev, "%s\n", __func__); - /* At otg mode, if the hcd which the hub is attached to is not accessible, - * It should do nothing. - */ - if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) - return 0; - hub_activate(hub, HUB_RESUME); return 0; } @@ -3286,6 +3286,9 @@ static void hub_events(void) USB_PORT_FEAT_C_SUSPEND); udev = hdev->children[i-1]; if (udev) { + /* TRSMRCY = 10 msec */ + msleep(10); + usb_lock_device(udev); ret = remote_wakeup(hdev-> children[i-1]); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 9720e699f472..8c929daa71f2 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -923,11 +923,11 @@ char *usb_cache_string(struct usb_device *udev, int index) if (index <= 0) return NULL; - buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL); + buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO); if (buf) { len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE); if (len > 0) { - smallbuf = kmalloc(++len, GFP_KERNEL); + smallbuf = kmalloc(++len, GFP_NOIO); if (!smallbuf) return buf; memcpy(smallbuf, buf, len); @@ -1694,7 +1694,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp) { nintf = cp->desc.bNumInterfaces; new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), - GFP_KERNEL); + GFP_NOIO); if (!new_interfaces) { dev_err(&dev->dev, "Out of memory\n"); return -ENOMEM; @@ -1703,7 +1703,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) for (; n < nintf; ++n) { new_interfaces[n] = kzalloc( sizeof(struct usb_interface), - GFP_KERNEL); + GFP_NOIO); if (!new_interfaces[n]) { dev_err(&dev->dev, "Out of memory\n"); ret = -ENOMEM; diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index b5c72e458943..7bc1469c8f0e 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -111,6 +111,12 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf) case USB_SPEED_HIGH: speed = "480"; break; + case USB_SPEED_VARIABLE: + speed = "480"; + break; + case USB_SPEED_SUPER: + speed = "5000"; + break; default: speed = "unknown"; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a26f73880c32..b661dbd93208 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting); struct find_interface_arg { int minor; - struct usb_interface *interface; + struct device_driver *drv; }; static int __find_interface(struct device *dev, void *data) @@ -143,12 +143,10 @@ static int __find_interface(struct device *dev, void *data) if (!is_usb_interface(dev)) return 0; + if (dev->driver != arg->drv) + return 0; intf = to_usb_interface(dev); - if (intf->minor != -1 && intf->minor == arg->minor) { - arg->interface = intf; - return 1; - } - return 0; + return intf->minor == arg->minor; } /** @@ -156,21 +154,24 @@ static int __find_interface(struct device *dev, void *data) * @drv: the driver whose current configuration is considered * @minor: the minor number of the desired device * - * This walks the driver device list and returns a pointer to the interface - * with the matching minor. Note, this only works for devices that share the - * USB major number. + * This walks the bus device list and returns a pointer to the interface + * with the matching minor and driver. Note, this only works for devices + * that share the USB major number. */ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { struct find_interface_arg argb; - int retval; + struct device *dev; argb.minor = minor; - argb.interface = NULL; - /* eat the error, it will be in argb.interface */ - retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb, - __find_interface); - return argb.interface; + argb.drv = &drv->drvwrap.driver; + + dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface); + + /* Drop reference count from bus_find_device */ + put_device(dev); + + return dev ? to_usb_interface(dev) : NULL; } EXPORT_SYMBOL_GPL(usb_find_interface); |