summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/Kconfig3
-rw-r--r--drivers/usb/core/config.c7
-rw-r--r--drivers/usb/core/driver.c14
-rw-r--r--drivers/usb/core/hcd.c110
-rw-r--r--drivers/usb/core/hub.c131
-rw-r--r--drivers/usb/core/message.c41
-rw-r--r--drivers/usb/core/port.c4
-rw-r--r--drivers/usb/core/quirks.c9
-rw-r--r--drivers/usb/core/sysfs.c36
-rw-r--r--drivers/usb/core/urb.c3
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/core/usb.h2
12 files changed, 274 insertions, 88 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a99c89e78..dd2801087 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -77,8 +77,7 @@ 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
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index b9ddf0c1f..5050760f5 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -115,7 +115,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
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;
}
@@ -853,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/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 6b5063e79..56593a9a8 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -296,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);
@@ -417,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;
}
@@ -508,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/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 4d64e5c49..1c102d60c 100644
--- a/drivers/usb/core/hcd.c
+++ b/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,12 +2727,22 @@ 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.)
@@ -2717,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:
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 431839bd2..ddbf32d59 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -124,6 +124,10 @@ 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.
*/
@@ -1031,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
@@ -1070,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);
@@ -1232,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);
@@ -1253,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 */
@@ -1404,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++)
@@ -2240,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
@@ -4222,7 +4251,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;
@@ -4503,6 +4532,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) {
@@ -4526,7 +4557,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;
@@ -4534,11 +4565,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; "
@@ -4554,7 +4585,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;
@@ -4701,7 +4732,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);
@@ -4741,7 +4771,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
@@ -5115,7 +5145,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",
@@ -5227,7 +5257,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,
@@ -5317,9 +5347,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
@@ -5328,15 +5355,18 @@ 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;
+ udev->bos = NULL;
+
for (i = 0; i < SET_CONFIG_TRIES; ++i) {
/* ep0 maxpacket size may change; let the HCD know about it.
@@ -5433,10 +5463,11 @@ done:
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/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f368d2053..8e641b589 100644
--- a/drivers/usb/core/message.c
+++ b/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/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 210618319..5487fe308 100644
--- a/drivers/usb/core/port.c
+++ b/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/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index f5a381945..6dc810bce 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -125,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 },
@@ -199,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/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index cfc68c11c..d9ec2de6c 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -957,6 +957,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,
@@ -966,6 +1001,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/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index c9e8ee81b..3d274778c 100644
--- a/drivers/usb/core/urb.c
+++ b/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/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 8d5b2f411..f8bbd0b6d 100644
--- a/drivers/usb/core/usb.c
+++ b/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/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 457255a33..05b5e17ab 100644
--- a/drivers/usb/core/usb.h
+++ b/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);