diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/Kconfig | 42 | ||||
-rw-r--r-- | drivers/usb/core/config.c | 17 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 73 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 52 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 25 | ||||
-rw-r--r-- | drivers/usb/core/hcd.h | 9 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 396 | ||||
-rw-r--r-- | drivers/usb/core/hub.h | 9 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 17 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 14 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 22 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 26 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 2 |
15 files changed, 443 insertions, 280 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index a2b0aa48b8ea..cc9f397e8398 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -76,8 +76,8 @@ config USB_DEVICE_CLASS NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" config USB_DYNAMIC_MINORS - bool "Dynamic USB minor allocation (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL + bool "Dynamic USB minor allocation" + depends on USB help If you say Y here, the USB subsystem will use dynamic minor allocation for any device that uses the USB major number. @@ -102,31 +102,6 @@ config USB_SUSPEND If you are unsure about this, say N here. -config USB_PERSIST - bool "USB device persistence during system suspend (DANGEROUS)" - depends on USB && PM && EXPERIMENTAL - default n - help - - If you say Y here and enable the "power/persist" attribute - for a USB device, the device's data structures will remain - persistent across system suspend, even if the USB bus loses - power. (This includes hibernation, also known as swsusp or - suspend-to-disk.) The devices will reappear as if by magic - when the system wakes up, with no need to unmount USB - filesystems, rmmod host-controller drivers, or do anything - else. - - WARNING: This option can be dangerous! - - If a USB device is replaced by another of the same type while - the system is asleep, there's a good chance the kernel won't - detect the change. Likewise if the media in a USB storage - device is replaced. When this happens it's almost certain to - cause data corruption and maybe even crash your system. - - If you are unsure, say N here. - config USB_OTG bool depends on USB && EXPERIMENTAL @@ -136,14 +111,16 @@ config USB_OTG config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" - depends on USB_OTG - default y + depends on USB_OTG || EMBEDDED + default y if USB_OTG + default n if EMBEDDED help If you say Y here, the "otg_whitelist.h" file will be used as a product whitelist, so USB peripherals not listed there will be rejected during enumeration. This behavior is required by the USB OTG specification for all devices not on your product's - "Targeted Peripherals List". + "Targeted Peripherals List". "Embedded Hosts" are likewise + allowed to support only a limited number of peripherals. Otherwise, peripherals not listed there will only generate a warning and enumeration will continue. That's more like what @@ -152,9 +129,10 @@ config USB_OTG_WHITELIST config USB_OTG_BLACKLIST_HUB bool "Disable external hubs" - depends on USB_OTG + depends on USB_OTG || EMBEDDED help If you say Y here, then Linux will refuse to enumerate external hubs. OTG hosts are allowed to reduce hardware - and software costs by not supporting external hubs. + and software costs by not supporting external hubs. So + are "Emedded Hosts" that don't offer OTG support. diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index a92122a216bc..568244c99bdc 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -145,6 +145,23 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, endpoint->desc.wMaxPacketSize = cpu_to_le16(8); } + /* + * Some buggy high speed devices have bulk endpoints using + * maxpacket sizes other than 512. High speed HCDs may not + * be able to handle that particular bug, so let's warn... + */ + if (to_usb_device(ddev)->speed == USB_SPEED_HIGH + && usb_endpoint_xfer_bulk(d)) { + unsigned maxp; + + maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff; + if (maxp != 512) + dev_warn(ddev, "config %d interface %d altsetting %d " + "bulk endpoint 0x%X has invalid maxpacket %d\n", + cfgno, inum, asnum, d->bEndpointAddress, + maxp); + } + /* Skip over any Class Specific or Vendor Specific descriptors; * find the next endpoint or interface descriptor */ endpoint->extra = buffer; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ae94176c64e4..de17738f3acb 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -647,6 +647,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) struct usbdevfs_ctrltransfer ctrl; unsigned int tmo; unsigned char *tbuf; + unsigned wLength; int i, j, ret; if (copy_from_user(&ctrl, arg, sizeof(ctrl))) @@ -654,7 +655,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); if (ret) return ret; - if (ctrl.wLength > PAGE_SIZE) + wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ + if (wLength > PAGE_SIZE) return -EINVAL; tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); if (!tbuf) @@ -946,8 +948,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, int ret, ifnum = -1; int is_in; - if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| - URB_NO_FSBR|URB_ZERO_PACKET)) + if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | + USBDEVFS_URB_SHORT_NOT_OK | + USBDEVFS_URB_NO_FSBR | + USBDEVFS_URB_ZERO_PACKET | + USBDEVFS_URB_NO_INTERRUPT)) return -EINVAL; if (!uurb->buffer) return -EINVAL; @@ -1102,8 +1107,24 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags | - (is_in ? URB_DIR_IN : URB_DIR_OUT); + + /* This tedious sequence is necessary because the URB_* flags + * are internal to the kernel and subject to change, whereas + * the USBDEVFS_URB_* flags are a user API and must not be changed. + */ + u = (is_in ? URB_DIR_IN : URB_DIR_OUT); + if (uurb->flags & USBDEVFS_URB_ISO_ASAP) + u |= URB_ISO_ASAP; + if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) + u |= URB_SHORT_NOT_OK; + if (uurb->flags & USBDEVFS_URB_NO_FSBR) + u |= URB_NO_FSBR; + if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) + u |= URB_ZERO_PACKET; + if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) + u |= URB_NO_INTERRUPT; + as->urb->transfer_flags = u; + as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; as->urb->start_frame = uurb->start_frame; @@ -1509,60 +1530,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, switch (cmd) { case USBDEVFS_CONTROL: - snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__); + snoop(&dev->dev, "%s: CONTROL\n", __func__); ret = proc_control(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_BULK: - snoop(&dev->dev, "%s: BULK\n", __FUNCTION__); + snoop(&dev->dev, "%s: BULK\n", __func__); ret = proc_bulk(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESETEP: - snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__); + snoop(&dev->dev, "%s: RESETEP\n", __func__); ret = proc_resetep(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESET: - snoop(&dev->dev, "%s: RESET\n", __FUNCTION__); + snoop(&dev->dev, "%s: RESET\n", __func__); ret = proc_resetdevice(ps); break; case USBDEVFS_CLEAR_HALT: - snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__); + snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__); ret = proc_clearhalt(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_GETDRIVER: - snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__); + snoop(&dev->dev, "%s: GETDRIVER\n", __func__); ret = proc_getdriver(ps, p); break; case USBDEVFS_CONNECTINFO: - snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__); + snoop(&dev->dev, "%s: CONNECTINFO\n", __func__); ret = proc_connectinfo(ps, p); break; case USBDEVFS_SETINTERFACE: - snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__); + snoop(&dev->dev, "%s: SETINTERFACE\n", __func__); ret = proc_setintf(ps, p); break; case USBDEVFS_SETCONFIGURATION: - snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__); + snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__); ret = proc_setconfig(ps, p); break; case USBDEVFS_SUBMITURB: - snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__); + snoop(&dev->dev, "%s: SUBMITURB\n", __func__); ret = proc_submiturb(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; @@ -1571,60 +1592,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, #ifdef CONFIG_COMPAT case USBDEVFS_SUBMITURB32: - snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__); + snoop(&dev->dev, "%s: SUBMITURB32\n", __func__); ret = proc_submiturb_compat(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_REAPURB32: - snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURB32\n", __func__); ret = proc_reapurb_compat(ps, p); break; case USBDEVFS_REAPURBNDELAY32: - snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__); ret = proc_reapurbnonblock_compat(ps, p); break; case USBDEVFS_IOCTL32: - snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); + snoop(&dev->dev, "%s: IOCTL\n", __func__); ret = proc_ioctl_compat(ps, ptr_to_compat(p)); break; #endif case USBDEVFS_DISCARDURB: - snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__); + snoop(&dev->dev, "%s: DISCARDURB\n", __func__); ret = proc_unlinkurb(ps, p); break; case USBDEVFS_REAPURB: - snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURB\n", __func__); ret = proc_reapurb(ps, p); break; case USBDEVFS_REAPURBNDELAY: - snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__); ret = proc_reapurbnonblock(ps, p); break; case USBDEVFS_DISCSIGNAL: - snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__); + snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__); ret = proc_disconnectsignal(ps, p); break; case USBDEVFS_CLAIMINTERFACE: - snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__); + snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__); ret = proc_claiminterface(ps, p); break; case USBDEVFS_RELEASEINTERFACE: - snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__); + snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__); ret = proc_releaseinterface(ps, p); break; case USBDEVFS_IOCTL: - snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); + snoop(&dev->dev, "%s: IOCTL\n", __func__); ret = proc_ioctl_default(ps, p); break; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 801b6f142fa7..1e56f1cfa6dc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -157,7 +157,7 @@ static int usb_probe_device(struct device *dev) struct usb_device *udev; int error = -ENODEV; - dev_dbg(dev, "%s\n", __FUNCTION__); + dev_dbg(dev, "%s\n", __func__); if (!is_usb_device(dev)) /* Sanity check */ return error; @@ -194,7 +194,7 @@ static int usb_probe_interface(struct device *dev) const struct usb_device_id *id; int error = -ENODEV; - dev_dbg(dev, "%s\n", __FUNCTION__); + dev_dbg(dev, "%s\n", __func__); if (is_usb_device(dev)) /* Sanity check */ return error; @@ -211,7 +211,7 @@ static int usb_probe_interface(struct device *dev) if (!id) id = usb_match_dynamic_id(intf, driver); if (id) { - dev_dbg(dev, "%s - got id\n", __FUNCTION__); + dev_dbg(dev, "%s - got id\n", __func__); error = usb_autoresume_device(udev); if (error) @@ -793,9 +793,7 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) status = udriver->suspend(udev, msg); done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - if (status == 0) - udev->dev.power.power_state.event = msg.event; + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); return status; } @@ -823,11 +821,9 @@ static int usb_resume_device(struct usb_device *udev) status = udriver->resume(udev); done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - if (status == 0) { + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); + if (status == 0) udev->autoresume_disabled = 0; - udev->dev.power.power_state.event = PM_EVENT_ON; - } return status; } @@ -864,7 +860,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) } done: - dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); + dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); return status; } @@ -914,7 +910,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) } done: - dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); + dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); if (status == 0) mark_active(intf); @@ -936,7 +932,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule) * is disabled. Also fail if any interfaces require remote wakeup * but it isn't available. */ - udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->pm_usage_cnt > 0) return -EBUSY; if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) @@ -1098,7 +1093,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) } done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); return status; } @@ -1180,8 +1175,7 @@ static int usb_resume_both(struct usb_device *udev) } } else { - /* Needed for setting udev->dev.power.power_state.event, - * for possible debugging message, and for reset_resume. */ + /* Needed for reset-resume */ status = usb_resume_device(udev); } @@ -1193,8 +1187,9 @@ static int usb_resume_both(struct usb_device *udev) } done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - udev->reset_resume = 0; + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); + if (!status) + udev->reset_resume = 0; return status; } @@ -1262,7 +1257,7 @@ void usb_autosuspend_device(struct usb_device *udev) status = usb_autopm_do_device(udev, -1); dev_vdbg(&udev->dev, "%s: cnt %d\n", - __FUNCTION__, udev->pm_usage_cnt); + __func__, udev->pm_usage_cnt); } /** @@ -1282,7 +1277,7 @@ void usb_try_autosuspend_device(struct usb_device *udev) { usb_autopm_do_device(udev, 0); dev_vdbg(&udev->dev, "%s: cnt %d\n", - __FUNCTION__, udev->pm_usage_cnt); + __func__, udev->pm_usage_cnt); } /** @@ -1310,7 +1305,7 @@ int usb_autoresume_device(struct usb_device *udev) status = usb_autopm_do_device(udev, 1); dev_vdbg(&udev->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, udev->pm_usage_cnt); + __func__, status, udev->pm_usage_cnt); return status; } @@ -1382,7 +1377,7 @@ void usb_autopm_put_interface(struct usb_interface *intf) status = usb_autopm_do_interface(intf, -1); dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, intf->pm_usage_cnt); + __func__, status, intf->pm_usage_cnt); } EXPORT_SYMBOL_GPL(usb_autopm_put_interface); @@ -1426,7 +1421,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) status = usb_autopm_do_interface(intf, 1); dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, intf->pm_usage_cnt); + __func__, status, intf->pm_usage_cnt); return status; } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); @@ -1448,7 +1443,7 @@ int usb_autopm_set_interface(struct usb_interface *intf) status = usb_autopm_do_interface(intf, 0); dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, intf->pm_usage_cnt); + __func__, status, intf->pm_usage_cnt); return status; } EXPORT_SYMBOL_GPL(usb_autopm_set_interface); @@ -1523,9 +1518,14 @@ static int usb_suspend(struct device *dev, pm_message_t message) udev = to_usb_device(dev); /* If udev is already suspended, we can skip this suspend and - * we should also skip the upcoming system resume. */ + * we should also skip the upcoming system resume. High-speed + * root hubs are an exception; they need to resume whenever the + * system wakes up in order for USB-PERSIST port handover to work + * properly. + */ if (udev->state == USB_STATE_SUSPENDED) { - udev->skip_sys_resume = 1; + if (udev->parent || udev->speed != USB_SPEED_HIGH) + udev->skip_sys_resume = 1; return 0; } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 84760ddbc332..5b87ae7f0a6a 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -73,7 +73,6 @@ 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 = PCI_D0; - dev->dev.power.power_state = PMSG_ON; if (!dev->irq) { dev_err(&dev->dev, @@ -216,9 +215,9 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) hcd->state == HC_STATE_HALT)) return -EBUSY; - if (hcd->driver->suspend) { - retval = hcd->driver->suspend(hcd, message); - suspend_report_result(hcd->driver->suspend, retval); + if (hcd->driver->pci_suspend) { + retval = hcd->driver->pci_suspend(hcd, message); + suspend_report_result(hcd->driver->pci_suspend, retval); if (retval) goto done; } @@ -302,8 +301,6 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) done: if (retval == 0) { - dev->dev.power.power_state = PMSG_SUSPEND; - #ifdef CONFIG_PPC_PMAC /* Disable ASIC clocks for USB */ if (machine_is(powermac)) { @@ -406,12 +403,10 @@ int usb_hcd_pci_resume(struct pci_dev *dev) pci_set_master(dev); pci_restore_state(dev); - dev->dev.power.power_state = PMSG_ON; - clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - if (hcd->driver->resume) { - retval = hcd->driver->resume(hcd); + if (hcd->driver->pci_resume) { + retval = hcd->driver->pci_resume(hcd); if (retval) { dev_err(hcd->self.controller, "PCI post-resume error %d!\n", retval); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e52ed1663b3c..bf10e9c4195e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -129,7 +129,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ - 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ + 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ @@ -291,7 +291,6 @@ static int ascii2utf (char *s, u8 *utf, int utfmax) * rh_string - provides manufacturer, product and serial strings for root hub * @id: the string ID number (1: serial number, 2: product, 3: vendor) * @hcd: the host controller for this root hub - * @type: string describing our driver * @data: return packet in UTF-16 LE * @len: length of the return packet * @@ -355,9 +354,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) __attribute__((aligned(4))); const u8 *bufp = tbuf; int len = 0; - int patch_wakeup = 0; int status; int n; + u8 patch_wakeup = 0; + u8 patch_protocol = 0; might_sleep(); @@ -434,6 +434,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) else goto error; len = 18; + if (hcd->has_tt) + patch_protocol = 1; break; case USB_DT_CONFIG << 8: if (hcd->driver->flags & HCD_USB2) { @@ -528,6 +530,13 @@ error: bmAttributes)) ((struct usb_config_descriptor *)ubuf)->bmAttributes |= USB_CONFIG_ATT_WAKEUP; + + /* report whether RH hardware has an integrated TT */ + if (patch_protocol && + len > offsetof(struct usb_device_descriptor, + bDeviceProtocol)) + ((struct usb_device_descriptor *) ubuf)-> + bDeviceProtocol = 1; } /* any errors get returned through the urb completion */ @@ -915,15 +924,6 @@ static int register_root_hub(struct usb_hcd *hcd) return retval; } -void usb_enable_root_hub_irq (struct usb_bus *bus) -{ - struct usb_hcd *hcd; - - hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT) - hcd->driver->hub_irq_enable (hcd); -} - /*-------------------------------------------------------------------------*/ @@ -1677,7 +1677,6 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); * usb_hcd_irq - hook IRQs to HCD framework (bus glue) * @irq: the IRQ being raised * @__hcd: pointer to the HCD whose IRQ is being signaled - * @r: saved hardware registers * * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 2d1c3d5e47b8..1e4b81e9eb50 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -28,7 +28,7 @@ /* * USB Packet IDs (PIDs) */ -#define USB_PID_UNDEF_0 0xf0 +#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */ #define USB_PID_OUT 0xe1 #define USB_PID_ACK 0xd2 #define USB_PID_DATA0 0xc3 @@ -99,6 +99,7 @@ struct usb_hcd { unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ unsigned authorized_default:1; + unsigned has_tt:1; /* Integrated TT in root hub */ int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ @@ -177,10 +178,10 @@ struct hc_driver { * a whole, not just the root hub; they're for PCI bus glue. */ /* called after suspending the hub, before entering D3 etc */ - int (*suspend) (struct usb_hcd *hcd, pm_message_t message); + int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message); /* called after entering D0 (etc), before resuming the hub */ - int (*resume) (struct usb_hcd *hcd); + int (*pci_resume) (struct usb_hcd *hcd); /* cleanly make HCD stop writing memory and doing I/O */ void (*stop) (struct usb_hcd *hcd); @@ -209,8 +210,6 @@ struct hc_driver { int (*bus_suspend)(struct usb_hcd *); int (*bus_resume)(struct usb_hcd *); int (*start_port_reset)(struct usb_hcd *, unsigned port_num); - void (*hub_irq_enable)(struct usb_hcd *); - /* Needed only if port-change IRQs are level-triggered */ /* force handover of high-speed port to full-speed companion */ void (*relinquish_port)(struct usb_hcd *, int); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 57aeca160f38..eb57fcc701d7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -30,12 +30,6 @@ #include "hcd.h" #include "hub.h" -#ifdef CONFIG_USB_PERSIST -#define USB_PERSIST 1 -#else -#define USB_PERSIST 0 -#endif - /* if we are in debug mode, always announce new devices */ #ifdef DEBUG #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES @@ -333,6 +327,27 @@ static int get_port_status(struct usb_device *hdev, int port1, return status; } +static int hub_port_status(struct usb_hub *hub, int port1, + u16 *status, u16 *change) +{ + int ret; + + mutex_lock(&hub->status_mutex); + ret = get_port_status(hub->hdev, port1, &hub->status->port); + if (ret < 4) { + dev_err(hub->intfdev, + "%s failed (err = %d)\n", __func__, ret); + if (ret >= 0) + ret = -EIO; + } else { + *status = le16_to_cpu(hub->status->port.wPortStatus); + *change = le16_to_cpu(hub->status->port.wPortChange); + ret = 0; + } + mutex_unlock(&hub->status_mutex); + return ret; +} + static void kick_khubd(struct usb_hub *hub) { unsigned long flags; @@ -560,7 +575,7 @@ static int hub_hub_status(struct usb_hub *hub, ret = get_hub_status(hub->hdev, &hub->status->hub); if (ret < 0) dev_err (hub->intfdev, - "%s failed (err = %d)\n", __FUNCTION__, ret); + "%s failed (err = %d)\n", __func__, ret); else { *status = le16_to_cpu(hub->status->hub.wHubStatus); *change = le16_to_cpu(hub->status->hub.wHubChange); @@ -610,9 +625,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) } /* caller has locked the hub device */ -static int hub_pre_reset(struct usb_interface *intf) +static void hub_stop(struct usb_hub *hub) { - struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = hub->hdev; int i; @@ -622,6 +636,89 @@ static int hub_pre_reset(struct usb_interface *intf) usb_disconnect(&hdev->children[i]); } hub_quiesce(hub); +} + +#define HUB_RESET 1 +#define HUB_RESUME 2 +#define HUB_RESET_RESUME 3 + +#ifdef CONFIG_PM + +static void hub_restart(struct usb_hub *hub, int type) +{ + struct usb_device *hdev = hub->hdev; + int port1; + + /* Check each of the children to see if they require + * USB-PERSIST handling or disconnection. Also check + * each unoccupied port to make sure it is still disabled. + */ + for (port1 = 1; port1 <= hdev->maxchild; ++port1) { + struct usb_device *udev = hdev->children[port1-1]; + int status = 0; + u16 portstatus, portchange; + + if (!udev || udev->state == USB_STATE_NOTATTACHED) { + if (type != HUB_RESET) { + status = hub_port_status(hub, port1, + &portstatus, &portchange); + if (status == 0 && (portstatus & + USB_PORT_STAT_ENABLE)) + clear_port_feature(hdev, port1, + USB_PORT_FEAT_ENABLE); + } + continue; + } + + /* Was the power session lost while we were suspended? */ + switch (type) { + case HUB_RESET_RESUME: + portstatus = 0; + portchange = USB_PORT_STAT_C_CONNECTION; + break; + + case HUB_RESET: + case HUB_RESUME: + status = hub_port_status(hub, port1, + &portstatus, &portchange); + break; + } + + /* For "USB_PERSIST"-enabled children we must + * mark the child device for reset-resume and + * turn off the various status changes to prevent + * khubd from disconnecting it later. + */ + if (udev->persist_enabled && status == 0 && + !(portstatus & USB_PORT_STAT_ENABLE)) { + if (portchange & USB_PORT_STAT_C_ENABLE) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_ENABLE); + if (portchange & USB_PORT_STAT_C_CONNECTION) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_CONNECTION); + udev->reset_resume = 1; + } + + /* Otherwise for a reset_resume we must disconnect the child, + * but as we may not lock the child device here + * we have to do a "logical" disconnect. + */ + else if (type == HUB_RESET_RESUME) + hub_port_logical_disconnect(hub, port1); + } + + hub_activate(hub); +} + +#endif /* CONFIG_PM */ + +/* caller has locked the hub device */ +static int hub_pre_reset(struct usb_interface *intf) +{ + struct usb_hub *hub = usb_get_intfdata(intf); + + hub_stop(hub); return 0; } @@ -910,7 +1007,7 @@ static void hub_disconnect(struct usb_interface *intf) /* Disconnect all children and quiesce the hub */ hub->error = 0; - hub_pre_reset(intf); + hub_stop(hub); usb_set_intfdata (intf, NULL); @@ -1098,21 +1195,42 @@ void usb_set_device_state(struct usb_device *udev, spin_unlock_irqrestore(&device_state_lock, flags); } +/* + * WUSB devices are simple: they have no hubs behind, so the mapping + * device <-> virtual port number becomes 1:1. Why? to simplify the + * life of the device connection logic in + * drivers/usb/wusbcore/devconnect.c. When we do the initial secret + * handshake we need to assign a temporary address in the unauthorized + * space. For simplicity we use the first virtual port number found to + * be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()] + * and that becomes it's address [X < 128] or its unauthorized address + * [X | 0x80]. + * + * We add 1 as an offset to the one-based USB-stack port number + * (zero-based wusb virtual port index) for two reasons: (a) dev addr + * 0 is reserved by USB for default address; (b) Linux's USB stack + * uses always #1 for the root hub of the controller. So USB stack's + * port #1, which is wusb virtual-port #0 has address #2. + */ static void choose_address(struct usb_device *udev) { int devnum; struct usb_bus *bus = udev->bus; /* If khubd ever becomes multithreaded, this will need a lock */ - - /* Try to allocate the next devnum beginning at bus->devnum_next. */ - devnum = find_next_zero_bit(bus->devmap.devicemap, 128, - bus->devnum_next); - if (devnum >= 128) - devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); - + if (udev->wusb) { + devnum = udev->portnum + 1; + BUG_ON(test_bit(devnum, bus->devmap.devicemap)); + } else { + /* Try to allocate the next devnum beginning at + * bus->devnum_next. */ + devnum = find_next_zero_bit(bus->devmap.devicemap, 128, + bus->devnum_next); + if (devnum >= 128) + devnum = find_next_zero_bit(bus->devmap.devicemap, + 128, 1); + bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + } if (devnum < 128) { set_bit(devnum, bus->devmap.devicemap); udev->devnum = devnum; @@ -1127,6 +1245,13 @@ static void release_address(struct usb_device *udev) } } +static void update_address(struct usb_device *udev, int devnum) +{ + /* The address for a WUSB device is managed by wusbcore. */ + if (!udev->wusb) + udev->devnum = devnum; +} + #ifdef CONFIG_USB_SUSPEND static void usb_stop_pm(struct usb_device *udev) @@ -1173,7 +1298,7 @@ void usb_disconnect(struct usb_device **pdev) int i; if (!udev) { - pr_debug ("%s nodev\n", __FUNCTION__); + pr_debug ("%s nodev\n", __func__); return; } @@ -1510,28 +1635,6 @@ out_authorized: } -static int hub_port_status(struct usb_hub *hub, int port1, - u16 *status, u16 *change) -{ - int ret; - - mutex_lock(&hub->status_mutex); - ret = get_port_status(hub->hdev, port1, &hub->status->port); - if (ret < 4) { - dev_err (hub->intfdev, - "%s failed (err = %d)\n", __FUNCTION__, ret); - if (ret >= 0) - ret = -EIO; - } else { - *status = le16_to_cpu(hub->status->port.wPortStatus); - *change = le16_to_cpu(hub->status->port.wPortChange); - ret = 0; - } - mutex_unlock(&hub->status_mutex); - return ret; -} - - /* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ static unsigned hub_is_wusb(struct usb_hub *hub) { @@ -1637,7 +1740,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, case 0: /* TRSTRCY = 10 ms; plus some extra */ msleep(10 + 40); - udev->devnum = 0; /* Device now at address 0 */ + update_address(udev, 0); /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: @@ -1842,9 +1945,8 @@ static int finish_port_resume(struct usb_device *udev) * the host and the device is the same as it was when the device * suspended. * - * If CONFIG_USB_PERSIST and @udev->reset_resume are both set then this - * routine won't check that the port is still enabled. Furthermore, - * if @udev->reset_resume is set then finish_port_resume() above will + * If @udev->reset_resume is set then this routine won't check that the + * port is still enabled. Furthermore, finish_port_resume() above will * reset @udev. The end result is that a broken power session can be * recovered and @udev will appear to persist across a loss of VBUS power. * @@ -1856,8 +1958,8 @@ static int finish_port_resume(struct usb_device *udev) * to it will be lost. Using the USB_PERSIST facility, the device can be * made to appear as if it had not disconnected. * - * This facility is inherently dangerous. Although usb_reset_device() - * makes every effort to insure that the same device is present after the + * This facility can be dangerous. Although usb_reset_device() makes + * every effort to insure that the same device is present after the * reset as before, it cannot provide a 100% guarantee. Furthermore it's * quite possible for a device to remain unaltered but its media to be * changed. If the user replaces a flash memory card while the system is @@ -1902,7 +2004,7 @@ int usb_port_resume(struct usb_device *udev) status = hub_port_status(hub, port1, &portstatus, &portchange); SuspendCleared: - if (USB_PERSIST && udev->reset_resume) + if (udev->reset_resume) want_flags = USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION; else @@ -1927,8 +2029,6 @@ int usb_port_resume(struct usb_device *udev) } clear_bit(port1, hub->busy_bits); - if (!hub->hdev->parent && !hub->busy_bits[0]) - usb_enable_root_hub_irq(hub->hdev->bus); if (status == 0) status = finish_port_resume(udev); @@ -2000,7 +2100,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) } } - dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + dev_dbg(&intf->dev, "%s\n", __func__); /* stop khubd and related activity */ hub_quiesce(hub); @@ -2009,49 +2109,20 @@ 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); - - dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + struct usb_hub *hub = usb_get_intfdata(intf); - /* tell khubd to look for changes on this hub */ - hub_activate(hub); + dev_dbg(&intf->dev, "%s\n", __func__); + hub_restart(hub, HUB_RESUME); return 0; } static int hub_reset_resume(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); - struct usb_device *hdev = hub->hdev; - int port1; + dev_dbg(&intf->dev, "%s\n", __func__); hub_power_on(hub); - - for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *child = hdev->children[port1-1]; - - if (child) { - - /* For "USB_PERSIST"-enabled children we must - * mark the child device for reset-resume and - * turn off the connect-change status to prevent - * khubd from disconnecting it later. - */ - if (USB_PERSIST && child->persist_enabled) { - child->reset_resume = 1; - clear_port_feature(hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - - /* Otherwise we must disconnect the child, - * but as we may not lock the child device here - * we have to do a "logical" disconnect. - */ - } else { - hub_port_logical_disconnect(hub, port1); - } - } - } - - hub_activate(hub); + hub_restart(hub, HUB_RESET_RESUME); return 0; } @@ -2061,10 +2132,10 @@ static int hub_reset_resume(struct usb_interface *intf) * * The USB host controller driver calls this function when its root hub * is resumed and Vbus power has been interrupted or the controller - * has been reset. The routine marks @rhdev as having lost power. When - * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST - * is enabled then it will carry out power-session recovery, otherwise - * it will disconnect all the child devices. + * has been reset. The routine marks @rhdev as having lost power. + * When the hub driver is resumed it will take notice and carry out + * power-session recovery for all the "USB-PERSIST"-enabled child devices; + * the others will be disconnected. */ void usb_root_hub_lost_power(struct usb_device *rhdev) { @@ -2147,12 +2218,13 @@ static int hub_port_debounce(struct usb_hub *hub, int port1) return portstatus; } -static void ep0_reinit(struct usb_device *udev) +void usb_ep0_reinit(struct usb_device *udev) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); usb_enable_endpoint(udev, &udev->ep0); } +EXPORT_SYMBOL_GPL(usb_ep0_reinit); #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) #define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) @@ -2171,9 +2243,10 @@ static int hub_set_address(struct usb_device *udev, int devnum) USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { - udev->devnum = devnum; /* Device now using proper address */ + /* Device now using proper address. */ + update_address(udev, devnum); usb_set_device_state(udev, USB_STATE_ADDRESS); - ep0_reinit(udev); + usb_ep0_reinit(udev); } return retval; } @@ -2355,26 +2428,33 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, #undef GET_DESCRIPTOR_BUFSIZE } - for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev, devnum); - if (retval >= 0) + /* + * If device is WUSB, we already assigned an + * unauthorized address in the Connect Ack sequence; + * authorization will assign the final address. + */ + if (udev->wusb == 0) { + for (j = 0; j < SET_ADDRESS_TRIES; ++j) { + retval = hub_set_address(udev, devnum); + if (retval >= 0) + break; + msleep(200); + } + if (retval < 0) { + dev_err(&udev->dev, + "device not accepting address %d, error %d\n", + devnum, retval); + goto fail; + } + + /* cope with hardware quirkiness: + * - let SET_ADDRESS settle, some device hardware wants it + * - read ep0 maxpacket even for high and low speed, + */ + msleep(10); + if (USE_NEW_SCHEME(retry_counter)) break; - msleep(200); - } - if (retval < 0) { - dev_err(&udev->dev, - "device not accepting address %d, error %d\n", - devnum, retval); - goto fail; - } - - /* cope with hardware quirkiness: - * - let SET_ADDRESS settle, some device hardware wants it - * - read ep0 maxpacket even for high and low speed, - */ - msleep(10); - if (USE_NEW_SCHEME(retry_counter)) - break; + } retval = usb_get_device_descriptor(udev, 8); if (retval < 8) { @@ -2391,7 +2471,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval) goto fail; - i = udev->descriptor.bMaxPacketSize0 == 0xff? + i = udev->descriptor.bMaxPacketSize0 == 0xff? /* wusb device? */ 512 : udev->descriptor.bMaxPacketSize0; if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { if (udev->speed != USB_SPEED_FULL || @@ -2402,7 +2482,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, } dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i); udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); - ep0_reinit(udev); + usb_ep0_reinit(udev); } retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); @@ -2419,7 +2499,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, fail: if (retval) { hub_port_disable(hub, port1, 0); - udev->devnum = devnum; /* for disconnect processing */ + update_address(udev, devnum); /* for disconnect processing */ } mutex_unlock(&usb_address0_mutex); return retval; @@ -2568,6 +2648,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, udev->speed = USB_SPEED_UNKNOWN; udev->bus_mA = hub->mA_per_port; udev->level = hdev->level + 1; + udev->wusb = hub_is_wusb(hub); /* set the address */ choose_address(udev); @@ -2657,12 +2738,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, loop_disable: hub_port_disable(hub, port1, 1); loop: - ep0_reinit(udev); + usb_ep0_reinit(udev); release_address(udev); usb_put_dev(udev); if ((status == -ENOTCONN) || (status == -ENOTSUPP)) break; } + dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); done: hub_port_disable(hub, port1, 1); @@ -2726,7 +2808,7 @@ static void hub_events(void) /* If the hub has died, clean up after it */ if (hdev->state == USB_STATE_NOTATTACHED) { hub->error = -ENODEV; - hub_pre_reset(intf); + hub_stop(hub); goto loop; } @@ -2872,11 +2954,6 @@ static void hub_events(void) hub->activating = 0; - /* If this is a root hub, tell the HCD it's okay to - * re-enable port-change interrupts now. */ - if (!hdev->parent && !hub->busy_bits[0]) - usb_enable_root_hub_irq(hdev->bus); - loop_autopm: /* Allow autosuspend if we're not going to run again */ if (list_empty(&hub->event_list)) @@ -2890,7 +2967,13 @@ loop: static int hub_thread(void *__unused) { + /* khubd needs to be freezable to avoid intefering with USB-PERSIST + * port handover. Otherwise it might see that a full-speed device + * was gone before the EHCI controller had handed its port over to + * the companion full-speed controller. + */ set_freezable(); + do { hub_events(); wait_event_freezable(khubd_wait, @@ -2959,16 +3042,36 @@ void usb_hub_cleanup(void) usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ -static int config_descriptors_changed(struct usb_device *udev) +static int descriptors_changed(struct usb_device *udev, + struct usb_device_descriptor *old_device_descriptor) { - unsigned index; - unsigned len = 0; - struct usb_config_descriptor *buf; + int changed = 0; + unsigned index; + unsigned serial_len = 0; + unsigned len; + unsigned old_length; + int length; + char *buf; + + if (memcmp(&udev->descriptor, old_device_descriptor, + sizeof(*old_device_descriptor)) != 0) + return 1; + /* Since the idVendor, idProduct, and bcdDevice values in the + * device descriptor haven't changed, we will assume the + * Manufacturer and Product strings haven't changed either. + * But the SerialNumber string could be different (e.g., a + * different flash card of the same brand). + */ + if (udev->serial) + serial_len = strlen(udev->serial) + 1; + + len = serial_len; for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) - len = le16_to_cpu(udev->config[index].desc.wTotalLength); + old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); + len = max(len, old_length); } + buf = kmalloc(len, GFP_NOIO); if (buf == NULL) { dev_err(&udev->dev, "no mem to re-read configs after reset\n"); @@ -2976,25 +3079,41 @@ static int config_descriptors_changed(struct usb_device *udev) return 1; } for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - int length; - int old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - + old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, old_length); - if (length < old_length) { + if (length != old_length) { dev_dbg(&udev->dev, "config index %d, error %d\n", index, length); + changed = 1; break; } if (memcmp (buf, udev->rawdescriptors[index], old_length) != 0) { dev_dbg(&udev->dev, "config index %d changed (#%d)\n", - index, buf->bConfigurationValue); + index, + ((struct usb_config_descriptor *) buf)-> + bConfigurationValue); + changed = 1; break; } } + + if (!changed && serial_len) { + length = usb_string(udev, udev->descriptor.iSerialNumber, + buf, serial_len); + if (length + 1 != serial_len) { + dev_dbg(&udev->dev, "serial string error %d\n", + length); + changed = 1; + } else if (memcmp(buf, udev->serial, length) != 0) { + dev_dbg(&udev->dev, "serial string changed\n"); + changed = 1; + } + } + kfree(buf); - return index != udev->descriptor.bNumConfigurations; + return changed; } /** @@ -3044,7 +3163,7 @@ int usb_reset_device(struct usb_device *udev) if (!parent_hdev) { /* this requires hcd-specific logic; see OHCI hc_restart() */ - dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__); + dev_dbg(&udev->dev, "%s for root hub!\n", __func__); return -EISDIR; } parent_hub = hdev_to_hub(parent_hdev); @@ -3054,21 +3173,18 @@ int usb_reset_device(struct usb_device *udev) /* ep0 maxpacket size may change; let the HCD know about it. * Other endpoints will be handled by re-enumeration. */ - ep0_reinit(udev); + usb_ep0_reinit(udev); ret = hub_port_init(parent_hub, udev, port1, i); if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV) break; } clear_bit(port1, parent_hub->busy_bits); - if (!parent_hdev->parent && !parent_hub->busy_bits[0]) - usb_enable_root_hub_irq(parent_hdev->bus); if (ret < 0) goto re_enumerate; /* Device might have changed firmware (DFU or similar) */ - if (memcmp(&udev->descriptor, &descriptor, sizeof descriptor) - || config_descriptors_changed (udev)) { + if (descriptors_changed(udev, &descriptor)) { dev_info(&udev->dev, "device firmware changed\n"); udev->descriptor = descriptor; /* for disconnect() calls */ goto re_enumerate; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 1551aed65e05..2a116ce53c9b 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -41,9 +41,10 @@ */ #define USB_PORT_FEAT_CONNECTION 0 #define USB_PORT_FEAT_ENABLE 1 -#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */ #define USB_PORT_FEAT_OVER_CURRENT 3 #define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_L1 5 /* L1 suspend */ #define USB_PORT_FEAT_POWER 8 #define USB_PORT_FEAT_LOWSPEED 9 #define USB_PORT_FEAT_HIGHSPEED 10 @@ -54,6 +55,7 @@ #define USB_PORT_FEAT_C_RESET 20 #define USB_PORT_FEAT_TEST 21 #define USB_PORT_FEAT_INDICATOR 22 +#define USB_PORT_FEAT_C_PORT_L1 23 /* * Hub Status and Hub Change results @@ -73,7 +75,8 @@ struct usb_port_status { #define USB_PORT_STAT_SUSPEND 0x0004 #define USB_PORT_STAT_OVERCURRENT 0x0008 #define USB_PORT_STAT_RESET 0x0010 -/* bits 5 to 7 are reserved */ +#define USB_PORT_STAT_L1 0x0020 +/* bits 6 to 7 are reserved */ #define USB_PORT_STAT_POWER 0x0100 #define USB_PORT_STAT_LOW_SPEED 0x0200 #define USB_PORT_STAT_HIGH_SPEED 0x0400 @@ -91,6 +94,7 @@ struct usb_port_status { #define USB_PORT_STAT_C_SUSPEND 0x0004 #define USB_PORT_STAT_C_OVERCURRENT 0x0008 #define USB_PORT_STAT_C_RESET 0x0010 +#define USB_PORT_STAT_C_L1 0x0020 /* * wHubCharacteristics (masks) @@ -191,5 +195,6 @@ struct usb_tt_clear { }; extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe); +extern void usb_ep0_reinit(struct usb_device *); #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 83a373e9cc36..8607846e3c3f 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -463,13 +463,13 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent) inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); if (!inode) { - dbg("%s: could not get inode!",__FUNCTION__); + dbg("%s: could not get inode!",__func__); return -ENOMEM; } root = d_alloc_root(inode); if (!root) { - dbg("%s: could not get root dentry!",__FUNCTION__); + dbg("%s: could not get root dentry!",__func__); iput(inode); return -ENOMEM; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c311f67b7f08..e819e5359d57 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -312,7 +312,7 @@ static void sg_complete(struct urb *urb) retval != -EBUSY) dev_err(&io->dev->dev, "%s, unlink --> %d\n", - __FUNCTION__, retval); + __func__, retval); } else if (urb == io->urbs [i]) found = 1; } @@ -550,7 +550,7 @@ void usb_sg_wait(struct usb_sg_request *io) io->urbs[i]->dev = NULL; io->urbs[i]->status = retval; dev_dbg(&io->dev->dev, "%s, submit --> %d\n", - __FUNCTION__, retval); + __func__, retval); usb_sg_cancel(io); } spin_lock_irq(&io->lock); @@ -600,7 +600,7 @@ void usb_sg_cancel(struct usb_sg_request *io) retval = usb_unlink_urb(io->urbs [i]); if (retval != -EINPROGRESS && retval != -EBUSY) dev_warn(&io->dev->dev, "%s, unlink --> %d\n", - __FUNCTION__, retval); + __func__, retval); } spin_lock(&io->lock); } @@ -784,7 +784,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (size <= 0 || !buf || !index) return -EINVAL; buf[0] = 0; - tbuf = kmalloc(256, GFP_KERNEL); + tbuf = kmalloc(256, GFP_NOIO); if (!tbuf) return -ENOMEM; @@ -1068,7 +1068,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) { int i; - dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__, + dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__, skip_ep0 ? "non-ep0" : "all"); for (i = skip_ep0; i < 16; ++i) { usb_disable_endpoint(dev, i); @@ -1089,8 +1089,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) continue; dev_dbg(&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); - usb_remove_sysfs_intf_files(interface); device_del(&interface->dev); + usb_remove_sysfs_intf_files(interface); } /* Now that the interfaces are unbound, nobody should @@ -1231,7 +1231,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ - if (iface->cur_altsetting != alt && device_is_registered(&iface->dev)) + if (iface->cur_altsetting != alt) usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); @@ -1330,8 +1330,7 @@ int usb_reset_configuration(struct usb_device *dev) struct usb_interface *intf = config->interface[i]; struct usb_host_interface *alt; - if (device_is_registered(&intf->dev)) - usb_remove_sysfs_intf_files(intf); + usb_remove_sysfs_intf_files(intf); alt = usb_altnum_to_altsetting(intf, 0); /* No altsetting 0? We'll assume the first altsetting. diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index dfc5418ea10c..2e2019390290 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -97,4 +97,18 @@ void usb_detect_quirks(struct usb_device *udev) if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) udev->autosuspend_disabled = 1; #endif + + /* For the present, all devices default to USB-PERSIST enabled */ +#if 0 /* was: #ifdef CONFIG_PM */ + /* Hubs are automatically enabled for USB-PERSIST */ + if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) + udev->persist_enabled = 1; + +#else + /* In the absence of PM, we can safely enable USB-PERSIST + * for all devices. It will affect things like hub resets + * and EMF-related port disables. + */ + udev->persist_enabled = 1; +#endif /* CONFIG_PM */ } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index a37ccbd1e007..5b20a60de8ba 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -180,11 +180,9 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); -#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) -static const char power_group[] = "power"; -#endif +#ifdef CONFIG_PM -#ifdef CONFIG_USB_PERSIST +static const char power_group[] = "power"; static ssize_t show_persist(struct device *dev, struct device_attribute *attr, char *buf) @@ -222,12 +220,13 @@ static int add_persist_attributes(struct device *dev) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - /* Hubs are automatically enabled for USB_PERSIST */ - if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) - udev->persist_enabled = 1; - rc = sysfs_add_file_to_group(&dev->kobj, - &dev_attr_persist.attr, - power_group); + /* Hubs are automatically enabled for USB_PERSIST, + * no point in creating the attribute file. + */ + if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_persist.attr, + power_group); } return rc; } @@ -238,13 +237,12 @@ static void remove_persist_attributes(struct device *dev) &dev_attr_persist.attr, power_group); } - #else #define add_persist_attributes(dev) 0 #define remove_persist_attributes(dev) do {} while (0) -#endif /* CONFIG_USB_PERSIST */ +#endif /* CONFIG_PM */ #ifdef CONFIG_USB_SUSPEND diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9d7e63292c01..c0b1ae25ae2a 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -334,7 +334,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", usb_endpoint_num(&ep->desc), is_out ? "out" : "in", - __FUNCTION__, max); + __func__, max); return -EMSGSIZE; } @@ -590,6 +590,30 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor) EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); /** + * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse + * @anchor: anchor the requests are bound to + * + * this allows all outstanding URBs to be unlinked starting + * from the back of the queue. This function is asynchronous. + * The unlinking is just tiggered. It may happen after this + * function has returned. + */ +void usb_unlink_anchored_urbs(struct usb_anchor *anchor) +{ + struct urb *victim; + + spin_lock_irq(&anchor->lock); + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, struct urb, + anchor_list); + /* this will unanchor the URB */ + usb_unlink_urb(victim); + } + spin_unlock_irq(&anchor->lock); +} +EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); + +/** * usb_wait_anchor_empty_timeout - wait for an anchor to be unused * @anchor: the anchor you want to become unused * @timeout: how long you are willing to wait in milliseconds diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 2375194a9d43..1bf8ccb9c58d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -114,13 +114,11 @@ static inline int is_usb_device_driver(struct device_driver *drv) static inline void mark_active(struct usb_interface *f) { f->is_active = 1; - f->dev.power.power_state.event = PM_EVENT_ON; } static inline void mark_quiesced(struct usb_interface *f) { f->is_active = 0; - f->dev.power.power_state.event = PM_EVENT_SUSPEND; } static inline int is_active(const struct usb_interface *f) |