diff options
Diffstat (limited to 'kernel/drivers/usb/core')
-rw-r--r-- | kernel/drivers/usb/core/Kconfig | 23 | ||||
-rw-r--r-- | kernel/drivers/usb/core/buffer.c | 3 | ||||
-rw-r--r-- | kernel/drivers/usb/core/config.c | 12 | ||||
-rw-r--r-- | kernel/drivers/usb/core/devio.c | 19 | ||||
-rw-r--r-- | kernel/drivers/usb/core/driver.c | 15 | ||||
-rw-r--r-- | kernel/drivers/usb/core/endpoint.c | 2 | ||||
-rw-r--r-- | kernel/drivers/usb/core/hcd.c | 132 | ||||
-rw-r--r-- | kernel/drivers/usb/core/hub.c | 276 | ||||
-rw-r--r-- | kernel/drivers/usb/core/message.c | 41 | ||||
-rw-r--r-- | kernel/drivers/usb/core/otg_whitelist.h | 2 | ||||
-rw-r--r-- | kernel/drivers/usb/core/port.c | 4 | ||||
-rw-r--r-- | kernel/drivers/usb/core/quirks.c | 22 | ||||
-rw-r--r-- | kernel/drivers/usb/core/sysfs.c | 88 | ||||
-rw-r--r-- | kernel/drivers/usb/core/urb.c | 3 | ||||
-rw-r--r-- | kernel/drivers/usb/core/usb.c | 2 | ||||
-rw-r--r-- | kernel/drivers/usb/core/usb.h | 2 |
16 files changed, 483 insertions, 163 deletions
diff --git a/kernel/drivers/usb/core/Kconfig b/kernel/drivers/usb/core/Kconfig index cc0ced08b..dd2801087 100644 --- a/kernel/drivers/usb/core/Kconfig +++ b/kernel/drivers/usb/core/Kconfig @@ -77,10 +77,29 @@ config USB_OTG_BLACKLIST_HUB config USB_OTG_FSM tristate "USB 2.0 OTG FSM implementation" - depends on USB - select USB_OTG + depends on USB && USB_OTG select USB_PHY help Implements OTG Finite State Machine as specified in On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification. +config USB_ULPI_BUS + tristate "USB ULPI PHY interface support" + depends on USB_SUPPORT + help + UTMI+ Low Pin Interface (ULPI) is specification for a commonly used + USB 2.0 PHY interface. The ULPI specification defines a standard set + of registers that can be used to detect the vendor and product which + allows ULPI to be handled as a bus. This module is the driver for that + bus. + + The ULPI interfaces (the buses) are registered by the drivers for USB + controllers which support ULPI register access and have ULPI PHY + attached to them. The ULPI PHY drivers themselves are normal PHY + drivers. + + ULPI PHYs provide often functions such as ADP sensing/probing (OTG + protocol) and USB charger detection. + + To compile this driver as a module, choose M here: the module will + be called ulpi. diff --git a/kernel/drivers/usb/core/buffer.c b/kernel/drivers/usb/core/buffer.c index 506b969ea..89f2e7765 100644 --- a/kernel/drivers/usb/core/buffer.c +++ b/kernel/drivers/usb/core/buffer.c @@ -70,7 +70,7 @@ int hcd_buffer_create(struct usb_hcd *hcd) size = pool_max[i]; if (!size) continue; - snprintf(name, sizeof name, "buffer-%d", size); + snprintf(name, sizeof(name), "buffer-%d", size); hcd->pool[i] = dma_pool_create(name, hcd->self.controller, size, size, 0); if (!hcd->pool[i]) { @@ -95,6 +95,7 @@ void hcd_buffer_destroy(struct usb_hcd *hcd) for (i = 0; i < HCD_BUFFER_POOLS; i++) { struct dma_pool *pool = hcd->pool[i]; + if (pool) { dma_pool_destroy(pool); hcd->pool[i] = NULL; diff --git a/kernel/drivers/usb/core/config.c b/kernel/drivers/usb/core/config.c index b2a540b43..5050760f5 100644 --- a/kernel/drivers/usb/core/config.c +++ b/kernel/drivers/usb/core/config.c @@ -112,16 +112,18 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 16; } else if (usb_endpoint_xfer_isoc(&ep->desc) && - desc->bmAttributes > 2) { + USB_SS_MULT(desc->bmAttributes) > 3) { dev_warn(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " - "setting to 3\n", desc->bmAttributes + 1, + "setting to 3\n", + USB_SS_MULT(desc->bmAttributes), cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 2; } if (usb_endpoint_xfer_isoc(&ep->desc)) - max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) * + max_tx = (desc->bMaxBurst + 1) * + (USB_SS_MULT(desc->bmAttributes)) * usb_endpoint_maxp(&ep->desc); else if (usb_endpoint_xfer_int(&ep->desc)) max_tx = usb_endpoint_maxp(&ep->desc) * @@ -852,6 +854,10 @@ int usb_get_bos_descriptor(struct usb_device *dev) dev->bos->ss_cap = (struct usb_ss_cap_descriptor *)buffer; break; + case USB_SSP_CAP_TYPE: + dev->bos->ssp_cap = + (struct usb_ssp_cap_descriptor *)buffer; + break; case CONTAINER_ID_TYPE: dev->bos->ss_id = (struct usb_ss_container_id_descriptor *)buffer; diff --git a/kernel/drivers/usb/core/devio.c b/kernel/drivers/usb/core/devio.c index 986abde07..38ae877c4 100644 --- a/kernel/drivers/usb/core/devio.c +++ b/kernel/drivers/usb/core/devio.c @@ -103,7 +103,7 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); #define snoop(dev, format, arg...) \ do { \ if (usbfs_snoop) \ - dev_info(dev , format , ## arg); \ + dev_info(dev, format, ## arg); \ } while (0) enum snoop_when { @@ -1082,7 +1082,8 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) return ret; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { + tbuf = kmalloc(len1, GFP_KERNEL); + if (!tbuf) { ret = -ENOMEM; goto done; } @@ -1224,7 +1225,8 @@ static int proc_setintf(struct usb_dev_state *ps, void __user *arg) if (copy_from_user(&setintf, arg, sizeof(setintf))) return -EFAULT; - if ((ret = checkintf(ps, setintf.interface))) + ret = checkintf(ps, setintf.interface); + if (ret) return ret; destroy_async_on_interface(ps, setintf.interface); @@ -1319,7 +1321,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0; u = 0; - switch(uurb->type) { + switch (uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; @@ -1393,7 +1395,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb number_of_packets = uurb->number_of_packets; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * number_of_packets; - if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) + isopkt = kmalloc(isofrmlen, GFP_KERNEL); + if (!isopkt) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { ret = -EFAULT; @@ -1904,7 +1907,8 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg) if (get_user(ifnum, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = releaseintf(ps, ifnum)) < 0) + ret = releaseintf(ps, ifnum); + if (ret < 0) return ret; destroy_async_on_interface (ps, ifnum); return 0; @@ -1919,7 +1923,8 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl) struct usb_driver *driver = NULL; /* alloc buffer */ - if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) { + size = _IOC_SIZE(ctl->ioctl_code); + if (size > 0) { buf = kmalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; diff --git a/kernel/drivers/usb/core/driver.c b/kernel/drivers/usb/core/driver.c index 818369aff..56593a9a8 100644 --- a/kernel/drivers/usb/core/driver.c +++ b/kernel/drivers/usb/core/driver.c @@ -160,6 +160,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf, spin_lock(&usb_driver->dynids.lock); list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) { struct usb_device_id *id = &dynid->id; + if ((id->idVendor == idVendor) && (id->idProduct == idProduct)) { list_del(&dynid->node); @@ -295,6 +296,10 @@ static int usb_probe_interface(struct device *dev) if (udev->authorized == 0) { dev_err(&intf->dev, "Device is not authorized for usage\n"); return error; + } else if (intf->authorized == 0) { + dev_err(&intf->dev, "Interface %d is not authorized for usage\n", + intf->altsetting->desc.bInterfaceNumber); + return error; } id = usb_match_dynamic_id(intf, driver); @@ -416,12 +421,10 @@ static int usb_unbind_interface(struct device *dev) if (ep->streams == 0) continue; if (j == 0) { - eps = kmalloc(USB_MAXENDPOINTS * sizeof(void *), + eps = kmalloc_array(USB_MAXENDPOINTS, sizeof(void *), GFP_KERNEL); - if (!eps) { - dev_warn(dev, "oom, leaking streams\n"); + if (!eps) break; - } } eps[j++] = ep; } @@ -507,6 +510,10 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (dev->driver) return -EBUSY; + /* reject claim if interface is not authorized */ + if (!iface->authorized) + return -ENODEV; + udev = interface_to_usbdev(iface); dev->driver = &driver->drvwrap.driver; diff --git a/kernel/drivers/usb/core/endpoint.c b/kernel/drivers/usb/core/endpoint.c index 39a24021f..101983b7e 100644 --- a/kernel/drivers/usb/core/endpoint.c +++ b/kernel/drivers/usb/core/endpoint.c @@ -51,7 +51,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev, { struct ep_device *ep = to_ep_device(dev); return sprintf(buf, "%04x\n", - usb_endpoint_maxp(ep->desc) & 0x07ff); + usb_endpoint_maxp(ep->desc) & 0x07ff); } static DEVICE_ATTR_RO(wMaxPacketSize); diff --git a/kernel/drivers/usb/core/hcd.c b/kernel/drivers/usb/core/hcd.c index ab14f8471..a8f2f5bf2 100644 --- a/kernel/drivers/usb/core/hcd.c +++ b/kernel/drivers/usb/core/hcd.c @@ -131,7 +131,7 @@ static inline int is_root_hub(struct usb_device *udev) /* usb 3.0 root hub device descriptor */ static const u8 usb3_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ + USB_DT_DEVICE, /* __u8 bDescriptorType; Device */ 0x00, 0x03, /* __le16 bcdUSB; v3.0 */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ @@ -152,7 +152,7 @@ static const u8 usb3_rh_dev_descriptor[18] = { /* usb 2.5 (wireless USB 1.0) root hub device descriptor */ static const u8 usb25_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ + USB_DT_DEVICE, /* __u8 bDescriptorType; Device */ 0x50, 0x02, /* __le16 bcdUSB; v2.5 */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ @@ -173,7 +173,7 @@ static const u8 usb25_rh_dev_descriptor[18] = { /* usb 2.0 root hub device descriptor */ static const u8 usb2_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ + USB_DT_DEVICE, /* __u8 bDescriptorType; Device */ 0x00, 0x02, /* __le16 bcdUSB; v2.0 */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ @@ -196,7 +196,7 @@ static const u8 usb2_rh_dev_descriptor[18] = { /* usb 1.1 root hub device descriptor */ static const u8 usb11_rh_dev_descriptor[18] = { 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ + USB_DT_DEVICE, /* __u8 bDescriptorType; Device */ 0x10, 0x01, /* __le16 bcdUSB; v1.1 */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ @@ -223,7 +223,7 @@ static const u8 fs_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ + USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */ 0x19, 0x00, /* __le16 wTotalLength; */ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ @@ -248,7 +248,7 @@ static const u8 fs_rh_config_descriptor[] = { /* one interface */ 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ + USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */ 0x00, /* __u8 if_bInterfaceNumber; */ 0x00, /* __u8 if_bAlternateSetting; */ 0x01, /* __u8 if_bNumEndpoints; */ @@ -259,7 +259,7 @@ static const u8 fs_rh_config_descriptor[] = { /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ @@ -270,7 +270,7 @@ static const u8 hs_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ + USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */ 0x19, 0x00, /* __le16 wTotalLength; */ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ @@ -295,7 +295,7 @@ static const u8 hs_rh_config_descriptor[] = { /* one interface */ 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ + USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */ 0x00, /* __u8 if_bInterfaceNumber; */ 0x00, /* __u8 if_bAlternateSetting; */ 0x01, /* __u8 if_bNumEndpoints; */ @@ -306,7 +306,7 @@ static const u8 hs_rh_config_descriptor[] = { /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) @@ -318,7 +318,7 @@ static const u8 hs_rh_config_descriptor[] = { static const u8 ss_rh_config_descriptor[] = { /* one configuration */ 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ + USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */ 0x1f, 0x00, /* __le16 wTotalLength; */ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ @@ -332,7 +332,7 @@ static const u8 ss_rh_config_descriptor[] = { /* one interface */ 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ + USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */ 0x00, /* __u8 if_bInterfaceNumber; */ 0x00, /* __u8 if_bAlternateSetting; */ 0x01, /* __u8 if_bNumEndpoints; */ @@ -343,7 +343,7 @@ static const u8 ss_rh_config_descriptor[] = { /* one endpoint (status change endpoint) */ 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) @@ -353,7 +353,8 @@ static const u8 ss_rh_config_descriptor[] = { /* one SuperSpeed endpoint companion descriptor */ 0x06, /* __u8 ss_bLength */ - 0x30, /* __u8 ss_bDescriptorType; SuperSpeed EP Companion */ + USB_DT_SS_ENDPOINT_COMP, /* __u8 ss_bDescriptorType; SuperSpeed EP */ + /* Companion */ 0x00, /* __u8 ss_bMaxBurst; allows 1 TX between ACKs */ 0x00, /* __u8 ss_bmAttributes; 1 packet per service interval */ 0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */ @@ -555,6 +556,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) switch (wValue & 0xff00) { case USB_DT_DEVICE << 8: switch (hcd->speed) { + case HCD_USB31: case HCD_USB3: bufp = usb3_rh_dev_descriptor; break; @@ -576,6 +578,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) break; case USB_DT_CONFIG << 8: switch (hcd->speed) { + case HCD_USB31: case HCD_USB3: bufp = ss_rh_config_descriptor; len = sizeof ss_rh_config_descriptor; @@ -854,10 +857,10 @@ static ssize_t authorized_default_show(struct device *dev, { struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *usb_hcd; + struct usb_hcd *hcd; - usb_hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); + hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd)); } static ssize_t authorized_default_store(struct device *dev, @@ -868,12 +871,16 @@ static ssize_t authorized_default_store(struct device *dev, unsigned val; struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *usb_hcd; + struct usb_hcd *hcd; - usb_hcd = bus_to_hcd(usb_bus); + hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - usb_hcd->authorized_default = val ? 1 : 0; + if (val) + set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + else + clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + result = size; } else { result = -EINVAL; @@ -882,9 +889,53 @@ static ssize_t authorized_default_store(struct device *dev, } static DEVICE_ATTR_RW(authorized_default); +/* + * interface_authorized_default_show - show default authorization status + * for USB interfaces + * + * note: interface_authorized_default is the default value + * for initializing the authorized attribute of interfaces + */ +static ssize_t interface_authorized_default_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); + + return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd)); +} + +/* + * interface_authorized_default_store - store default authorization status + * for USB interfaces + * + * note: interface_authorized_default is the default value + * for initializing the authorized attribute of interfaces + */ +static ssize_t interface_authorized_default_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_device *usb_dev = to_usb_device(dev); + struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); + int rc = count; + bool val; + + if (strtobool(buf, &val) != 0) + return -EINVAL; + + if (val) + set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); + else + clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); + + return rc; +} +static DEVICE_ATTR_RW(interface_authorized_default); + /* Group all the USB bus attributes */ static struct attribute *usb_bus_attrs[] = { &dev_attr_authorized_default.attr, + &dev_attr_interface_authorized_default.attr, NULL, }; @@ -2676,25 +2727,38 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); /* Keep old behaviour if authorized_default is not in [0, 1]. */ - if (authorized_default < 0 || authorized_default > 1) - hcd->authorized_default = hcd->wireless ? 0 : 1; - else - hcd->authorized_default = authorized_default; + if (authorized_default < 0 || authorized_default > 1) { + if (hcd->wireless) + clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + else + set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + } else { + if (authorized_default) + set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + else + clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + } set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* per default all interfaces are authorized */ + set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); + /* HC is in reset state, but accessible. Now do the one-time init, * bottom up so that hcds can customize the root hubs before hub_wq * starts talking to them. (Note, bus id is assigned early too.) */ - if ((retval = hcd_buffer_create(hcd)) != 0) { + retval = hcd_buffer_create(hcd); + if (retval != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); goto err_create_buf; } - if ((retval = usb_register_bus(&hcd->self)) < 0) + retval = usb_register_bus(&hcd->self); + if (retval < 0) goto err_register_bus; - if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { + rhdev = usb_alloc_dev(NULL, &hcd->self, 0); + if (rhdev == NULL) { dev_err(hcd->self.controller, "unable to allocate root hub\n"); retval = -ENOMEM; goto err_allocate_root_hub; @@ -2714,6 +2778,7 @@ int usb_add_hcd(struct usb_hcd *hcd, rhdev->speed = USB_SPEED_WIRELESS; break; case HCD_USB3: + case HCD_USB31: rhdev->speed = USB_SPEED_SUPER; break; default: @@ -2736,9 +2801,13 @@ int usb_add_hcd(struct usb_hcd *hcd, /* "reset" is misnamed; its role is now one-time init. the controller * should already have been reset (and boot firmware kicked off etc). */ - if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't setup: %d\n", retval); - goto err_hcd_driver_setup; + if (hcd->driver->reset) { + retval = hcd->driver->reset(hcd); + if (retval < 0) { + dev_err(hcd->self.controller, "can't setup: %d\n", + retval); + goto err_hcd_driver_setup; + } } hcd->rh_pollable = 1; @@ -2768,7 +2837,8 @@ int usb_add_hcd(struct usb_hcd *hcd, } /* starting here, usbcore will pay attention to this root hub */ - if ((retval = register_root_hub(hcd)) != 0) + retval = register_root_hub(hcd); + if (retval != 0) goto err_register_root_hub; retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); diff --git a/kernel/drivers/usb/core/hub.c b/kernel/drivers/usb/core/hub.c index 1e9a8c9aa..1560f3f3e 100644 --- a/kernel/drivers/usb/core/hub.c +++ b/kernel/drivers/usb/core/hub.c @@ -50,8 +50,8 @@ DEFINE_MUTEX(usb_port_peer_mutex); /* cycle leds on hubs that aren't blinking for attention */ static bool blinkenlights = 0; -module_param (blinkenlights, bool, S_IRUGO); -MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); +module_param(blinkenlights, bool, S_IRUGO); +MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs"); /* * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about @@ -124,10 +124,14 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) int usb_device_supports_lpm(struct usb_device *udev) { + /* Some devices have trouble with LPM */ + if (udev->quirks & USB_QUIRK_NO_LPM) + return 0; + /* USB 2.1 (and greater) devices indicate LPM support through * their USB 2.0 Extended Capabilities BOS descriptor. */ - if (udev->speed == USB_SPEED_HIGH) { + if (udev->speed == USB_SPEED_HIGH || udev->speed == USB_SPEED_FULL) { if (udev->bos->ext_cap && (USB_LPM_SUPPORT & le32_to_cpu(udev->bos->ext_cap->bmAttributes))) @@ -439,7 +443,7 @@ static void set_port_led(struct usb_hub *hub, int port1, int selector) #define LED_CYCLE_PERIOD ((2*HZ)/3) -static void led_work (struct work_struct *work) +static void led_work(struct work_struct *work) { struct usb_hub *hub = container_of(work, struct usb_hub, leds.work); @@ -646,7 +650,7 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", status); + dev_dbg(hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; hub->error = status; @@ -671,14 +675,14 @@ resubmit: if (hub->quiescing) return; - if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 - && status != -ENODEV && status != -EPERM) - dev_err (hub->intfdev, "resubmit --> %d\n", status); + status = usb_submit_urb(hub->urb, GFP_ATOMIC); + if (status != 0 && status != -ENODEV && status != -EPERM) + dev_err(hub->intfdev, "resubmit --> %d\n", status); } /* USB 2.0 spec Section 11.24.2.3 */ static inline int -hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) +hub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt) { /* Need to clear both directions for control ep */ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) == @@ -706,7 +710,7 @@ static void hub_tt_work(struct work_struct *work) container_of(work, struct usb_hub, tt.clear_work); unsigned long flags; - spin_lock_irqsave (&hub->tt.lock, flags); + spin_lock_irqsave(&hub->tt.lock, flags); while (!list_empty(&hub->tt.clear_list)) { struct list_head *next; struct usb_tt_clear *clear; @@ -715,14 +719,14 @@ static void hub_tt_work(struct work_struct *work) int status; next = hub->tt.clear_list.next; - clear = list_entry (next, struct usb_tt_clear, clear_list); - list_del (&clear->clear_list); + clear = list_entry(next, struct usb_tt_clear, clear_list); + list_del(&clear->clear_list); /* drop lock so HCD can concurrently report other TT errors */ - spin_unlock_irqrestore (&hub->tt.lock, flags); - status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); + spin_unlock_irqrestore(&hub->tt.lock, flags); + status = hub_clear_tt_buffer(hdev, clear->devinfo, clear->tt); if (status && status != -ENODEV) - dev_err (&hdev->dev, + dev_err(&hdev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); @@ -734,7 +738,7 @@ static void hub_tt_work(struct work_struct *work) kfree(clear); spin_lock_irqsave(&hub->tt.lock, flags); } - spin_unlock_irqrestore (&hub->tt.lock, flags); + spin_unlock_irqrestore(&hub->tt.lock, flags); } /** @@ -795,8 +799,9 @@ int usb_hub_clear_tt_buffer(struct urb *urb) * since each TT has "at least two" buffers that can need it (and * there can be many TTs per hub). even if they're uncommon. */ - if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { - dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); + clear = kmalloc(sizeof *clear, GFP_ATOMIC); + if (clear == NULL) { + dev_err(&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return -ENOMEM; } @@ -805,10 +810,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb) clear->tt = tt->multi ? udev->ttport : 1; clear->devinfo = usb_pipeendpoint (pipe); clear->devinfo |= udev->devnum << 4; - clear->devinfo |= usb_pipecontrol (pipe) + clear->devinfo |= usb_pipecontrol(pipe) ? (USB_ENDPOINT_XFER_CONTROL << 11) : (USB_ENDPOINT_XFER_BULK << 11); - if (usb_pipein (pipe)) + if (usb_pipein(pipe)) clear->devinfo |= 1 << 15; /* info for completion callback */ @@ -816,10 +821,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb) clear->ep = urb->ep; /* tell keventd to clear state for this TT */ - spin_lock_irqsave (&tt->lock, flags); - list_add_tail (&clear->clear_list, &tt->clear_list); + spin_lock_irqsave(&tt->lock, flags); + list_add_tail(&clear->clear_list, &tt->clear_list); schedule_work(&tt->clear_work); - spin_unlock_irqrestore (&tt->lock, flags); + spin_unlock_irqrestore(&tt->lock, flags); return 0; } EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); @@ -1030,10 +1035,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) unsigned delay; /* Continue a partial initialization */ - if (type == HUB_INIT2) - goto init2; - if (type == HUB_INIT3) + if (type == HUB_INIT2 || type == HUB_INIT3) { + device_lock(hub->intfdev); + + /* Was the hub disconnected while we were waiting? */ + if (hub->disconnected) { + device_unlock(hub->intfdev); + kref_put(&hub->kref, hub_release); + return; + } + if (type == HUB_INIT2) + goto init2; goto init3; + } + kref_get(&hub->kref); /* The superspeed hub except for root hub has to use Hub Depth * value as an offset into the route string to locate the bits @@ -1069,7 +1084,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * for HUB_POST_RESET, but it's easier not to. */ if (type == HUB_INIT) { - unsigned delay = hub_power_on_good_delay(hub); + delay = hub_power_on_good_delay(hub); hub_power_on(hub, false); INIT_DELAYED_WORK(&hub->init_work, hub_init_func2); @@ -1231,6 +1246,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) queue_delayed_work(system_power_efficient_wq, &hub->init_work, msecs_to_jiffies(delay)); + device_unlock(hub->intfdev); return; /* Continues at init3: below */ } else { msleep(delay); @@ -1252,6 +1268,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Allow autosuspend if it was suppressed */ if (type <= HUB_INIT3) usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); + + if (type == HUB_INIT2 || type == HUB_INIT3) + device_unlock(hub->intfdev); + + kref_put(&hub->kref, hub_release); } /* Implement the continuations for the delays above */ @@ -1403,7 +1424,6 @@ static int hub_configure(struct usb_hub *hub, /* FIXME for USB 3.0, skip for now */ if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && !(hub_is_superspeed(hdev))) { - int i; char portstr[USB_MAXCHILDREN + 1]; for (i = 0; i < maxchild; i++) @@ -1441,8 +1461,8 @@ static int hub_configure(struct usb_hub *hub, break; } - spin_lock_init (&hub->tt.lock); - INIT_LIST_HEAD (&hub->tt.clear_list); + spin_lock_init(&hub->tt.lock); + INIT_LIST_HEAD(&hub->tt.clear_list); INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { case USB_HUB_PR_FS: @@ -1631,7 +1651,7 @@ static int hub_configure(struct usb_hub *hub, return 0; fail: - dev_err (hub_dev, "config failed, %s (err %d)\n", + dev_err(hub_dev, "config failed, %s (err %d)\n", message, ret); /* hub_disconnect() frees urb and descriptor */ return ret; @@ -1774,7 +1794,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) if ((desc->desc.bInterfaceSubClass != 0) && (desc->desc.bInterfaceSubClass != 1)) { descriptor_error: - dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); + dev_err(&intf->dev, "bad descriptor, ignoring hub\n"); return -EIO; } @@ -1789,11 +1809,11 @@ descriptor_error: goto descriptor_error; /* We found a hub */ - dev_info (&intf->dev, "USB hub found\n"); + dev_info(&intf->dev, "USB hub found\n"); hub = kzalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { - dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); + dev_dbg(&intf->dev, "couldn't kmalloc hub struct\n"); return -ENOMEM; } @@ -1806,7 +1826,7 @@ descriptor_error: usb_get_intf(intf); usb_get_dev(hdev); - usb_set_intfdata (intf, hub); + usb_set_intfdata(intf, hub); intf->needs_remote_wakeup = 1; pm_suspend_ignore_children(&intf->dev, true); @@ -1819,14 +1839,14 @@ descriptor_error: if (hub_configure(hub, endpoint) >= 0) return 0; - hub_disconnect (intf); + hub_disconnect(intf); return -ENODEV; } static int hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) { - struct usb_device *hdev = interface_to_usbdev (intf); + struct usb_device *hdev = interface_to_usbdev(intf); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); /* assert ifno == 0 (part of hub spec) */ @@ -2142,7 +2162,7 @@ void usb_disconnect(struct usb_device **pdev) * cleaning up all state associated with the current configuration * so that the hardware is now fully quiesced. */ - dev_dbg (&udev->dev, "unregistering device\n"); + dev_dbg(&udev->dev, "unregistering device\n"); usb_disable_device(udev, 0); usb_hcd_synchronize_unlinks(udev); @@ -2239,39 +2259,49 @@ static int usb_enumerate_device_otg(struct usb_device *udev) && udev->parent == udev->bus->root_hub) { struct usb_otg_descriptor *desc = NULL; struct usb_bus *bus = udev->bus; + unsigned port1 = udev->portnum; /* descriptor may appear anywhere in config */ - if (__usb_get_extra_descriptor (udev->rawdescriptors[0], - le16_to_cpu(udev->config[0].desc.wTotalLength), - USB_DT_OTG, (void **) &desc) == 0) { - if (desc->bmAttributes & USB_OTG_HNP) { - unsigned port1 = udev->portnum; + err = __usb_get_extra_descriptor(udev->rawdescriptors[0], + le16_to_cpu(udev->config[0].desc.wTotalLength), + USB_DT_OTG, (void **) &desc); + if (err || !(desc->bmAttributes & USB_OTG_HNP)) + return 0; - dev_info(&udev->dev, - "Dual-Role OTG device on %sHNP port\n", - (port1 == bus->otg_port) - ? "" : "non-"); - - /* enable HNP before suspend, it's simpler */ - if (port1 == bus->otg_port) - bus->b_hnp_enable = 1; - err = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, 0, - bus->b_hnp_enable - ? USB_DEVICE_B_HNP_ENABLE - : USB_DEVICE_A_ALT_HNP_SUPPORT, - 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (err < 0) { - /* OTG MESSAGE: report errors here, - * customize to match your product. - */ - dev_info(&udev->dev, - "can't set HNP mode: %d\n", - err); - bus->b_hnp_enable = 0; - } + dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n", + (port1 == bus->otg_port) ? "" : "non-"); + + /* enable HNP before suspend, it's simpler */ + if (port1 == bus->otg_port) { + bus->b_hnp_enable = 1; + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_B_HNP_ENABLE, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (err < 0) { + /* + * OTG MESSAGE: report errors here, + * customize to match your product. + */ + dev_err(&udev->dev, "can't set HNP mode: %d\n", + err); + bus->b_hnp_enable = 0; } + } else if (desc->bLength == sizeof + (struct usb_otg_descriptor)) { + /* Set a_alt_hnp_support for legacy otg device */ + err = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_A_ALT_HNP_SUPPORT, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (err < 0) + dev_err(&udev->dev, + "set a_alt_hnp_support failed: %d\n", + err); } } #endif @@ -2350,6 +2380,26 @@ static void set_usb_port_removable(struct usb_device *udev) hub = usb_hub_to_struct_hub(udev->parent); + /* + * If the platform firmware has provided information about a port, + * use that to determine whether it's removable. + */ + switch (hub->ports[udev->portnum - 1]->connect_type) { + case USB_PORT_CONNECT_TYPE_HOT_PLUG: + udev->removable = USB_DEVICE_REMOVABLE; + return; + case USB_PORT_CONNECT_TYPE_HARD_WIRED: + case USB_PORT_NOT_USED: + udev->removable = USB_DEVICE_FIXED; + return; + default: + break; + } + + /* + * Otherwise, check whether the hub knows whether a port is removable + * or not + */ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); if (!(wHubCharacteristics & HUB_CHAR_COMPOUND)) @@ -2369,21 +2419,6 @@ static void set_usb_port_removable(struct usb_device *udev) else udev->removable = USB_DEVICE_FIXED; - /* - * Platform firmware may have populated an alternative value for - * removable. If the parent port has a known connect_type use - * that instead. - */ - switch (hub->ports[udev->portnum - 1]->connect_type) { - case USB_PORT_CONNECT_TYPE_HOT_PLUG: - udev->removable = USB_DEVICE_REMOVABLE; - break; - case USB_PORT_CONNECT_TYPE_HARD_WIRED: - udev->removable = USB_DEVICE_FIXED; - break; - default: /* use what was set above */ - break; - } } /** @@ -3520,7 +3555,7 @@ static int check_ports_changed(struct usb_hub *hub) static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { - struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = hub->hdev; unsigned port1; int status; @@ -3860,17 +3895,30 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, return; } - if (usb_set_lpm_timeout(udev, state, timeout)) + if (usb_set_lpm_timeout(udev, state, timeout)) { /* If we can't set the parent hub U1/U2 timeout, * device-initiated LPM won't be allowed either, so let the xHCI * host know that this link state won't be enabled. */ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state); + } else { + /* Only a configured device will accept the Set Feature + * U1/U2_ENABLE + */ + if (udev->actconfig) + usb_set_device_initiated_lpm(udev, state, true); - /* Only a configured device will accept the Set Feature U1/U2_ENABLE */ - else if (udev->actconfig) - usb_set_device_initiated_lpm(udev, state, true); - + /* As soon as usb_set_lpm_timeout(timeout) returns 0, the + * hub-initiated LPM is enabled. Thus, LPM is enabled no + * matter the result of usb_set_device_initiated_lpm(). + * The only difference is whether device is able to initiate + * LPM. + */ + if (state == USB3_LPM_U1) + udev->usb3_lpm_u1_enabled = 1; + else if (state == USB3_LPM_U2) + udev->usb3_lpm_u2_enabled = 1; + } } /* @@ -3910,6 +3958,18 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev, dev_warn(&udev->dev, "Could not disable xHCI %s timeout, " "bus schedule bandwidth may be impacted.\n", usb3_lpm_names[state]); + + /* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM + * is disabled. Hub will disallows link to enter U1/U2 as well, + * even device is initiating LPM. Hence LPM is disabled if hub LPM + * timeout set to 0, no matter device-initiated LPM is disabled or + * not. + */ + if (state == USB3_LPM_U1) + udev->usb3_lpm_u1_enabled = 0; + else if (state == USB3_LPM_U2) + udev->usb3_lpm_u2_enabled = 0; + return 0; } @@ -4212,7 +4272,7 @@ static int hub_enable_device(struct usb_device *udev) * but it is still necessary to lock the port. */ static int -hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, +hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { struct usb_device *hdev = hub->hdev; @@ -4493,6 +4553,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } + usb_detect_quirks(udev); + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { retval = usb_get_bos_descriptor(udev); if (!retval) { @@ -4516,7 +4578,7 @@ fail: } static void -check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) +check_highspeed(struct usb_hub *hub, struct usb_device *udev, int port1) { struct usb_qualifier_descriptor *qual; int status; @@ -4524,11 +4586,11 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) if (udev->quirks & USB_QUIRK_DEVICE_QUALIFIER) return; - qual = kmalloc (sizeof *qual, GFP_KERNEL); + qual = kmalloc(sizeof *qual, GFP_KERNEL); if (qual == NULL) return; - status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0, + status = usb_get_descriptor(udev, USB_DT_DEVICE_QUALIFIER, 0, qual, sizeof *qual); if (status == sizeof *qual) { dev_info(&udev->dev, "not running at top speed; " @@ -4544,7 +4606,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) } static unsigned -hub_power_remaining (struct usb_hub *hub) +hub_power_remaining(struct usb_hub *hub) { struct usb_device *hdev = hub->hdev; int remaining; @@ -4691,7 +4753,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, if (status < 0) goto loop; - usb_detect_quirks(udev); if (udev->quirks & USB_QUIRK_DELAY_INIT) msleep(1000); @@ -4731,7 +4792,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 && udev->speed == USB_SPEED_FULL && highspeed_hubs != 0) - check_highspeed (hub, udev, port1); + check_highspeed(hub, udev, port1); /* Store the parent's children[] pointer. At this point * udev becomes globally accessible, although presumably @@ -5105,7 +5166,7 @@ static const struct usb_device_id hub_id_table[] = { { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, hub_id_table); +MODULE_DEVICE_TABLE(usb, hub_id_table); static struct usb_driver hub_driver = { .name = "hub", @@ -5217,7 +5278,7 @@ static int descriptors_changed(struct usb_device *udev, changed = 1; break; } - if (memcmp (buf, udev->rawdescriptors[index], old_length) + if (memcmp(buf, udev->rawdescriptors[index], old_length) != 0) { dev_dbg(&udev->dev, "config index %d changed (#%d)\n", index, @@ -5307,9 +5368,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); - bos = udev->bos; - udev->bos = NULL; - /* Disable LPM and LTM while we reset the device and reinstall the alt * settings. Device-initiated LPM settings, and system exit latency * settings are cleared when the device is reset, so we have to set @@ -5318,15 +5376,17 @@ static int usb_reset_and_verify_device(struct usb_device *udev) ret = usb_unlocked_disable_lpm(udev); if (ret) { dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); - goto re_enumerate; + goto re_enumerate_no_bos; } ret = usb_disable_ltm(udev); if (ret) { dev_err(&udev->dev, "%s Failed to disable LTM\n.", __func__); - goto re_enumerate; + goto re_enumerate_no_bos; } + bos = udev->bos; + for (i = 0; i < SET_CONFIG_TRIES; ++i) { /* ep0 maxpacket size may change; let the HCD know about it. @@ -5418,15 +5478,19 @@ done: usb_set_usb2_hardware_lpm(udev, 1); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); - usb_release_bos_descriptor(udev); - udev->bos = bos; + /* release the new BOS descriptor allocated by hub_port_init() */ + if (udev->bos != bos) { + usb_release_bos_descriptor(udev); + udev->bos = bos; + } return 0; re_enumerate: - /* LPM state doesn't matter when we're about to destroy the device. */ - hub_port_logical_disconnect(parent_hub, port1); usb_release_bos_descriptor(udev); udev->bos = bos; +re_enumerate_no_bos: + /* LPM state doesn't matter when we're about to destroy the device. */ + hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } diff --git a/kernel/drivers/usb/core/message.c b/kernel/drivers/usb/core/message.c index f368d2053..8e641b589 100644 --- a/kernel/drivers/usb/core/message.c +++ b/kernel/drivers/usb/core/message.c @@ -1387,8 +1387,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * new altsetting. */ if (manual) { - int i; - for (i = 0; i < alt->desc.bNumEndpoints; i++) { epaddr = alt->endpoint[i].desc.bEndpointAddress; pipe = __create_pipe(dev, @@ -1555,6 +1553,44 @@ static void usb_release_interface(struct device *dev) kfree(intf); } +/* + * usb_deauthorize_interface - deauthorize an USB interface + * + * @intf: USB interface structure + */ +void usb_deauthorize_interface(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + + device_lock(dev->parent); + + if (intf->authorized) { + device_lock(dev); + intf->authorized = 0; + device_unlock(dev); + + usb_forced_unbind_intf(intf); + } + + device_unlock(dev->parent); +} + +/* + * usb_authorize_interface - authorize an USB interface + * + * @intf: USB interface structure + */ +void usb_authorize_interface(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + + if (!intf->authorized) { + device_lock(dev); + intf->authorized = 1; /* authorize interface */ + device_unlock(dev); + } +} + static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; @@ -1807,6 +1843,7 @@ free_interfaces: intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; + intf->authorized = !!HCD_INTF_AUTHORIZED(hcd); kref_get(&intfc->ref); alt = usb_altnum_to_altsetting(intf, 0); diff --git a/kernel/drivers/usb/core/otg_whitelist.h b/kernel/drivers/usb/core/otg_whitelist.h index a6315abe7..a95b0c989 100644 --- a/kernel/drivers/usb/core/otg_whitelist.h +++ b/kernel/drivers/usb/core/otg_whitelist.h @@ -16,7 +16,7 @@ * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! */ -static struct usb_device_id whitelist_table [] = { +static struct usb_device_id whitelist_table[] = { /* hubs are optional in OTG, but very handy ... */ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, diff --git a/kernel/drivers/usb/core/port.c b/kernel/drivers/usb/core/port.c index 210618319..5487fe308 100644 --- a/kernel/drivers/usb/core/port.c +++ b/kernel/drivers/usb/core/port.c @@ -206,7 +206,7 @@ static int link_peers(struct usb_port *left, struct usb_port *right) else method = "default"; - pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", + pr_debug("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", dev_name(&left->dev), dev_name(&right->dev), method, dev_name(&left->dev), lpeer ? dev_name(&lpeer->dev) : "none", @@ -265,7 +265,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right) if (rc == 0) { dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev)); } else { - dev_warn(&left->dev, "failed to peer to %s (%d)\n", + dev_dbg(&left->dev, "failed to peer to %s (%d)\n", dev_name(&right->dev), rc); pr_warn_once("usb: port power management may be unreliable\n"); usb_port_block_power_off = 1; diff --git a/kernel/drivers/usb/core/quirks.c b/kernel/drivers/usb/core/quirks.c index d85abfed8..6dc810bce 100644 --- a/kernel/drivers/usb/core/quirks.c +++ b/kernel/drivers/usb/core/quirks.c @@ -54,6 +54,13 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech ConferenceCam CC3000e */ + { USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x0848), .driver_info = USB_QUIRK_DELAY_INIT }, + + /* Logitech PTZ Pro Camera */ + { USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Logitech Quickcam Fusion */ { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -78,6 +85,12 @@ static const struct usb_device_id usb_quirk_list[] = { /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Plantronic Audio 655 DSP */ + { USB_DEVICE(0x047f, 0xc008), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Plantronic Audio 648 USB */ + { USB_DEVICE(0x047f, 0xc013), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Artisman Watchdog Dongle */ { USB_DEVICE(0x04b4, 0x0526), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -112,6 +125,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04f3, 0x016f), .driver_info = USB_QUIRK_DEVICE_QUALIFIER }, + { USB_DEVICE(0x04f3, 0x21b8), .driver_info = + USB_QUIRK_DEVICE_QUALIFIER }, + /* Roland SC-8820 */ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -186,6 +202,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Blackmagic Design Intensity Shuttle */ + { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM }, + + /* Blackmagic Design UltraStudio SDI */ + { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, + { } /* terminating entry must be last */ }; diff --git a/kernel/drivers/usb/core/sysfs.c b/kernel/drivers/usb/core/sysfs.c index d26973844..65b6e6b84 100644 --- a/kernel/drivers/usb/core/sysfs.c +++ b/kernel/drivers/usb/core/sysfs.c @@ -531,6 +531,44 @@ static ssize_t usb2_lpm_besl_store(struct device *dev, } static DEVICE_ATTR_RW(usb2_lpm_besl); +static ssize_t usb3_hardware_lpm_u1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_u1_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm_u1); + +static ssize_t usb3_hardware_lpm_u2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_u2_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm_u2); + static struct attribute *usb2_hardware_lpm_attr[] = { &dev_attr_usb2_hardware_lpm.attr, &dev_attr_usb2_lpm_l1_timeout.attr, @@ -542,6 +580,16 @@ static struct attribute_group usb2_hardware_lpm_attr_group = { .attrs = usb2_hardware_lpm_attr, }; +static struct attribute *usb3_hardware_lpm_attr[] = { + &dev_attr_usb3_hardware_lpm_u1.attr, + &dev_attr_usb3_hardware_lpm_u2.attr, + NULL, +}; +static struct attribute_group usb3_hardware_lpm_attr_group = { + .name = power_group_name, + .attrs = usb3_hardware_lpm_attr, +}; + static struct attribute *power_attrs[] = { &dev_attr_autosuspend.attr, &dev_attr_level.attr, @@ -564,6 +612,10 @@ static int add_power_attributes(struct device *dev) if (udev->usb2_hw_lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); + if (udev->speed == USB_SPEED_SUPER && + udev->lpm_capable == 1) + rc = sysfs_merge_group(&dev->kobj, + &usb3_hardware_lpm_attr_group); } return rc; @@ -926,6 +978,41 @@ static ssize_t supports_autosuspend_show(struct device *dev, } static DEVICE_ATTR_RO(supports_autosuspend); +/* + * interface_authorized_show - show authorization status of an USB interface + * 1 is authorized, 0 is deauthorized + */ +static ssize_t interface_authorized_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + + return sprintf(buf, "%u\n", intf->authorized); +} + +/* + * interface_authorized_store - authorize or deauthorize an USB interface + */ +static ssize_t interface_authorized_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + bool val; + + if (strtobool(buf, &val) != 0) + return -EINVAL; + + if (val) + usb_authorize_interface(intf); + else + usb_deauthorize_interface(intf); + + return count; +} +static struct device_attribute dev_attr_interface_authorized = + __ATTR(authorized, S_IRUGO | S_IWUSR, + interface_authorized_show, interface_authorized_store); + static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceNumber.attr, &dev_attr_bAlternateSetting.attr, @@ -935,6 +1022,7 @@ static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceProtocol.attr, &dev_attr_modalias.attr, &dev_attr_supports_autosuspend.attr, + &dev_attr_interface_authorized.attr, NULL, }; static struct attribute_group intf_attr_grp = { diff --git a/kernel/drivers/usb/core/urb.c b/kernel/drivers/usb/core/urb.c index c9e8ee81b..3d274778c 100644 --- a/kernel/drivers/usb/core/urb.c +++ b/kernel/drivers/usb/core/urb.c @@ -129,9 +129,8 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) list_add_tail(&urb->anchor_list, &anchor->urb_list); urb->anchor = anchor; - if (unlikely(anchor->poisoned)) { + if (unlikely(anchor->poisoned)) atomic_inc(&urb->reject); - } spin_unlock_irqrestore(&anchor->lock, flags); } diff --git a/kernel/drivers/usb/core/usb.c b/kernel/drivers/usb/core/usb.c index 8d5b2f411..f8bbd0b6d 100644 --- a/kernel/drivers/usb/core/usb.c +++ b/kernel/drivers/usb/core/usb.c @@ -510,7 +510,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, if (root_hub) /* Root hub always ok [and always wired] */ dev->authorized = 1; else { - dev->authorized = usb_hcd->authorized_default; + dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; } return dev; diff --git a/kernel/drivers/usb/core/usb.h b/kernel/drivers/usb/core/usb.h index 457255a33..05b5e17ab 100644 --- a/kernel/drivers/usb/core/usb.h +++ b/kernel/drivers/usb/core/usb.h @@ -27,6 +27,8 @@ extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device(struct usb_device *dev, int skip_ep0); extern int usb_deauthorize_device(struct usb_device *); extern int usb_authorize_device(struct usb_device *); +extern void usb_deauthorize_interface(struct usb_interface *); +extern void usb_authorize_interface(struct usb_interface *); extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev); extern int usb_remove_device(struct usb_device *udev); |