diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/core/common.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 345 | ||||
-rw-r--r-- | drivers/usb/core/hub.h | 7 | ||||
-rw-r--r-- | drivers/usb/core/of.c | 17 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 364 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 1 |
7 files changed, 454 insertions, 284 deletions
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 58f6c5e027..60e03caad7 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_USB_HOST) += usb.o hub.o obj-$(CONFIG_USB) += common.o obj-$(CONFIG_OFDEVICE) += of.o diff --git a/drivers/usb/core/common.c b/drivers/usb/core/common.c index bcbe3a155d..61ccc13024 100644 --- a/drivers/usb/core/common.c +++ b/drivers/usb/core/common.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only #include <common.h> -#include <usb/ch9.h> +#include <linux/usb/ch9.h> static const char *const speed_names[] = { [USB_SPEED_UNKNOWN] = "UNKNOWN", diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8874775f17..bef428f7fb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1,32 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * hub.c - USB hub support * * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <common.h> #include <init.h> #include <malloc.h> #include <errno.h> -#include <usb/phy.h> -#include <usb/usb.h> -#include <usb/usb_defs.h> +#include <linux/usb/phy.h> +#include <linux/usb/usb.h> +#include <linux/usb/usb_defs.h> #include "usb.h" -#include "hub.h" #define USB_BUFSIZ 512 @@ -44,11 +31,38 @@ struct usb_device_scan { static LIST_HEAD(usb_scan_list); +static bool usb_hub_is_superspeed(struct usb_device *hdev) +{ + return hdev->descriptor->bDeviceProtocol == 3; +} + +bool usb_hub_is_root_hub(struct usb_device *hdev) +{ + return hdev->level == 0; +} + +static int usb_set_hub_depth(struct usb_device *dev, int depth) +{ + dev_dbg(&dev->dev, "set hub depth to %d\n", dev->level); + + if (depth < 0 || depth > 4) + return -EINVAL; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HUB_SET_DEPTH, USB_DIR_OUT | USB_RT_HUB, + depth, 0, NULL, 0, USB_CNTL_TIMEOUT); +} + static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { + unsigned short dtype = USB_DT_HUB; + + if (usb_hub_is_superspeed(dev)) + dtype = USB_DT_SS_HUB; + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT); + dtype << 8, 0, data, size, USB_CNTL_TIMEOUT); } static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) @@ -72,11 +86,39 @@ static int usb_get_hub_status(struct usb_device *dev, void *data) data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); } -static int usb_get_port_status(struct usb_device *dev, int port, void *data) +static int usb_get_port_status(struct usb_device *dev, int port, + struct usb_port_status *status) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + struct usb_port_status *data; + int ret; + + data = dma_alloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); + if (ret < 0) + goto out; + + *status = *data; + + if (!usb_hub_is_root_hub(dev) && usb_hub_is_superspeed(dev)) { + u16 tmp = status->wPortStatus & USB_SS_PORT_STAT_MASK; + + if (status->wPortStatus & USB_SS_PORT_STAT_POWER) + tmp |= USB_PORT_STAT_POWER; + if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) == + USB_PORT_STAT_SPEED_5GBPS) + tmp |= USB_PORT_STAT_SUPER_SPEED; + + status->wPortStatus = tmp; + } + +out: + dma_free(data); + return ret; } @@ -88,22 +130,13 @@ static void usb_hub_power_on(struct usb_hub_device *hub) dev = hub->pusb_dev; - /* - * Enable power to the ports: - * Here we Power-cycle the ports: aka, - * turning them off and turning on again. - */ - for (i = 0; i < dev->maxchild; i++) { - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); - dev_dbg(&dev->dev, "port %d returns %lX\n", i + 1, dev->status); - } - /* Enable power to the ports */ dev_dbg(&dev->dev, "enabling power on all ports\n"); for (i = 0; i < dev->maxchild; i++) { usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); - dev_dbg(&dev->dev, "port %d returns %lX\n", i + 1, dev->status); + dev_dbg(&dev->dev, "port%d: usb_set_port_feature returns 0x%08lx\n", + i + 1, dev->status); } /* @@ -120,8 +153,7 @@ static void usb_hub_power_on(struct usb_hub_device *hub) */ hub->connect_timeout = hub->query_delay + 1000 * MSECOND; - dev_dbg(&dev->dev, "devnum=%d poweron: query_delay=%d \ - connect_timeout=%d\n", + dev_dbg(&dev->dev, "devnum=%d poweron: query_delay=%d connect_timeout=%d\n", dev->devnum, max(100, (int) pgood_delay), max(100, (int) pgood_delay) + 1000); } @@ -130,41 +162,48 @@ static void usb_hub_power_on(struct usb_hub_device *hub) static inline char *portspeed(int portstatus) { - if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) + switch (portstatus & USB_PORT_STAT_SPEED_MASK) { + case USB_PORT_STAT_SUPER_SPEED: + return "5 Gb/s"; + case USB_PORT_STAT_HIGH_SPEED: return "480 Mb/s"; - else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) + case USB_PORT_STAT_LOW_SPEED: return "1.5 Mb/s"; - else + default: return "12 Mb/s"; + } } -int hub_port_reset(struct usb_device *hub, int port, struct usb_device *usb) +static int hub_port_reset(struct usb_device *hub, int port, + struct usb_device *usb) { int tries; struct usb_port_status portsts; unsigned short portstatus, portchange; int delay = HUB_SHORT_RESET_TIME; /* start with short reset delay */ - dev_dbg(&hub->dev, "hub_port_reset: resetting port %d...\n", port); + dev_dbg(&hub->dev, "port%d: resetting...\n", port + 1); for (tries = 0; tries < MAX_TRIES; tries++) { usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); mdelay(delay); if (usb_get_port_status(hub, port + 1, &portsts) < 0) { - dev_dbg(&hub->dev, "get_port_status failed status %lX\n", - hub->status); + dev_dbg(&hub->dev, "port%d: get_port_status failed status 0x%lX\n", + port + 1, hub->status); return -1; } portstatus = le16_to_cpu(portsts.wPortStatus); portchange = le16_to_cpu(portsts.wPortChange); - dev_dbg(&hub->dev, "portstatus %x, change %x, %s\n", + dev_dbg(&hub->dev, "port%d: status 0x%04x, change 0x%04x, %s\n", + port + 1, portstatus, portchange, portspeed(portstatus)); - dev_dbg(&hub->dev, "STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \ + dev_dbg(&hub->dev, "port%d: STAT_C_CONNECTION = %d STAT_CONNECTION = %d" " USB_PORT_STAT_ENABLE %d\n", + port + 1, (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0, (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); @@ -181,48 +220,44 @@ int hub_port_reset(struct usb_device *hub, int port, struct usb_device *usb) } if (tries == MAX_TRIES) { - dev_dbg(&hub->dev, "Cannot enable port %i after %i retries, " \ - "disabling port.\n", port + 1, MAX_TRIES); + dev_dbg(&hub->dev, "port%d: Cannot enable after %i retries, disabling port.\n", + port + 1, MAX_TRIES); dev_dbg(&hub->dev, "Maybe the USB cable is bad?\n"); return -1; } usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); - if (portstatus & USB_PORT_STAT_HIGH_SPEED) + switch (portstatus & USB_PORT_STAT_SPEED_MASK) { + case USB_PORT_STAT_SUPER_SPEED: + usb->speed = USB_SPEED_SUPER; + break; + case USB_PORT_STAT_HIGH_SPEED: usb->speed = USB_SPEED_HIGH; - else if (portstatus & USB_PORT_STAT_LOW_SPEED) + break; + case USB_PORT_STAT_LOW_SPEED: usb->speed = USB_SPEED_LOW; - else + break; + default: usb->speed = USB_SPEED_FULL; + break; + } return 0; } -static void usb_hub_port_connect_change(struct usb_device *dev, int port) +static void usb_hub_port_connect_change(struct usb_device *dev, int port, + uint16_t portstatus, uint16_t portchange) { struct usb_device *usb; - struct usb_port_status portsts; - unsigned short portstatus, portchange; - - /* Check status */ - if (usb_get_port_status(dev, port + 1, &portsts) < 0) { - dev_dbg(&dev->dev, "get_port_status failed\n"); - return; - } - - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - dev_dbg(&dev->dev, "portstatus %x, change %x, %s\n", - portstatus, portchange, portspeed(portstatus)); /* Clear the connection change status */ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION); /* Disconnect any existing devices under this port */ if (dev->children[port] && !(portstatus & USB_PORT_STAT_CONNECTION)) { - dev_dbg(&dev->dev, "disconnect detected on port %d\n", port + 1); + dev_dbg(&dev->dev, "port%d: disconnect detected\n", port + 1); usb_remove_device(dev->children[port]); if (!dev->parent && dev->host->usbphy) @@ -242,7 +277,7 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Reset it */ if (hub_port_reset(dev, port, usb) < 0) { - dev_warn(&dev->dev, "cannot reset port %i!?\n", port + 1); + dev_warn(&dev->dev, "port%d: cannot reset\n", port + 1); usb_free_device(usb); return; } @@ -267,7 +302,7 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port) device_detect(&usb->dev); } -static int usb_scan_port(struct usb_device_scan *usb_scan) +static void usb_scan_port(struct usb_device_scan *usb_scan) { struct usb_port_status portsts; unsigned short portstatus, portchange; @@ -284,68 +319,65 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) * This is needed for voltages to stabilize. */ if (get_time_ns() < hub->query_delay) - return 0; + return; if (usb_get_port_status(dev, port + 1, &portsts) < 0) { - dev_dbg(&dev->dev, "get_port_status failed\n"); + dev_dbg(&dev->dev, "port%d: get_port_status failed\n", port + 1); if(get_time_ns() >= hub->connect_timeout) { - dev_dbg(&dev->dev, "port=%d: timeout\n", port + 1); + dev_dbg(&dev->dev, "port%d: timeout\n", port + 1); /* Remove this device from scanning list */ goto remove; } - return 0; + return; } portstatus = le16_to_cpu(portsts.wPortStatus); portchange = le16_to_cpu(portsts.wPortChange); - dev_dbg(&dev->dev, "Port %d Status %X Change %X\n", + dev_dbg(&dev->dev, "port%d: Status 0x%04x Change 0x%04x\n", port + 1, portstatus, portchange); - if (!(portchange & USB_PORT_STAT_C_CONNECTION)) { - if(get_time_ns() >= hub->connect_timeout) { - dev_dbg(&dev->dev, "port=%d: timeout\n", port + 1); + if (!(portchange & USB_PORT_STAT_C_CONNECTION) || + !(portstatus & USB_PORT_STAT_CONNECTION)) { + if (get_time_ns() >= hub->connect_timeout) { + dev_dbg(&dev->dev, "port%d: timeout\n", port + 1); /* Remove this device from scanning list */ goto remove; } - return 0; + return; } - /* Test if the connection came up, and if not exit */ - if(!(portstatus & USB_PORT_STAT_CONNECTION)) - return 0; + if (portchange & USB_PORT_STAT_C_RESET) { + dev_dbg(&dev->dev, "port%d: reset change\n", port + 1); + usb_clear_port_feature(dev, port + 1, + USB_PORT_FEAT_C_RESET); + } + + if ((portchange & USB_PORT_STAT_C_BH_RESET) && + usb_hub_is_superspeed(dev)) { + dev_dbg(&dev->dev, "port%d: BH reset change\n", port + 1); + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_BH_PORT_RESET); + } /* A new USB device is ready at this point */ - dev_dbg(&dev->dev, "port=%d: USB dev found\n", port + 1); + dev_dbg(&dev->dev, "port%d: USB dev found\n", port + 1); - usb_hub_port_connect_change(dev, port); + usb_hub_port_connect_change(dev, port, portstatus, portchange); if (portchange & USB_PORT_STAT_C_ENABLE) { - dev_dbg(&dev->dev, "port %d enable change, status %x\n", + dev_dbg(&dev->dev, "port%d: enable change, status 0x%04x\n", port + 1, portstatus); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_ENABLE); - - /* EM interference sometimes causes bad shielded USB - * devices to be shutdown by the hub, this hack enables - * them again. Works at least with mouse driver */ - if (!(portstatus & USB_PORT_STAT_ENABLE) && - (portstatus & USB_PORT_STAT_CONNECTION) && - ((dev->children[port]))) { - dev_dbg(&dev->dev, "already running port %i " \ - "disabled by hub (EMI?), " \ - "re-enabling...\n", port + 1); - usb_hub_port_connect_change(dev, port); - } } if (portstatus & USB_PORT_STAT_SUSPEND) { - dev_dbg(&dev->dev, "port %d suspend change\n", port + 1); + dev_dbg(&dev->dev, "port%d: suspend change\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - dev_dbg(&dev->dev, "port %d over-current change\n", port + 1); + dev_dbg(&dev->dev, "port%d: over-current change\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_OVER_CURRENT); /* Only power-on this one port */ @@ -358,19 +390,13 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) */ if (hub->overcurrent_count[port] <= PORT_OVERCURRENT_MAX_SCAN_COUNT) - return 0; + return; /* Otherwise the device will get removed */ - dev_dbg(&dev->dev,"Port %d over-current occurred %d times\n", + dev_dbg(&dev->dev,"port%d: over-current occurred %d times\n", port + 1, hub->overcurrent_count[port]); } - if (portchange & USB_PORT_STAT_C_RESET) { - dev_dbg(&dev->dev, "port %d reset change\n", port + 1); - usb_clear_port_feature(dev, port + 1, - USB_PORT_FEAT_C_RESET); - } - remove: /* * We're done with this device, so let's remove this device from @@ -378,8 +404,6 @@ remove: */ list_del(&usb_scan->list); free(usb_scan); - - return 0; } static int usb_device_list_scan(void) @@ -387,7 +411,6 @@ static int usb_device_list_scan(void) struct usb_device_scan *usb_scan; struct usb_device_scan *tmp; static int running; - int ret = 0; /* Only run this loop once for each controller */ if (running) @@ -400,12 +423,11 @@ static int usb_device_list_scan(void) if (list_empty(&usb_scan_list)) goto out; - list_for_each_entry_safe(usb_scan, tmp, &usb_scan_list, list) { - /* Scan this port */ - ret = usb_scan_port(usb_scan); - if (ret) - goto out; - } + list_for_each_entry_safe(usb_scan, tmp, &usb_scan_list, list) + usb_scan_port(usb_scan); + + /* Avoid hammering the HUB with port scans */ + mdelay(25); } out: @@ -416,17 +438,21 @@ out: */ running = 0; - return ret; + return 0; } static int usb_hub_configure(struct usb_device *dev) { - unsigned char buffer[USB_BUFSIZ], *bitmap; + unsigned char *buffer, *bitmap; struct usb_hub_descriptor *descriptor; struct usb_hub_status *hubsts; - int i; + int i, ret; struct usb_hub_device *hub; + buffer = dma_alloc(USB_BUFSIZ); + if (!buffer) + return -ENOMEM; + hub = xzalloc(sizeof (*hub)); dev->hub = hub; @@ -435,7 +461,8 @@ static int usb_hub_configure(struct usb_device *dev) if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { dev_dbg(&dev->dev, "%s: failed to get hub " \ "descriptor, giving up %lX\n", __func__, dev->status); - return -1; + ret = -1; + goto out; } descriptor = (struct usb_hub_descriptor *)buffer; @@ -445,13 +472,15 @@ static int usb_hub_configure(struct usb_device *dev) dev_dbg(&dev->dev, "%s: failed to get hub " \ "descriptor - too long: %d\n", __func__, descriptor->bLength); - return -1; + ret = -1; + goto out; } if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { dev_dbg(&dev->dev, "%s: failed to get hub " \ "descriptor 2nd giving up %lX\n", __func__, dev->status); - return -1; + ret = -1; + goto out; } memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); /* adjust 16bit values */ @@ -504,6 +533,56 @@ static int usb_hub_configure(struct usb_device *dev) break; } + switch (dev->descriptor->bDeviceProtocol) { + case USB_HUB_PR_FS: + break; + case USB_HUB_PR_HS_SINGLE_TT: + dev_dbg(&dev->dev, "Single TT\n"); + break; + case USB_HUB_PR_HS_MULTI_TT: + ret = usb_set_interface(dev, 0, 1); + if (ret == 0) { + dev_dbg(&dev->dev, "TT per port\n"); + hub->tt.multi = true; + } else { + dev_dbg(&dev->dev, "Using single TT (err %d)\n", ret); + } + break; + case USB_HUB_PR_SS: + /* USB 3.0 hubs don't have a TT */ + break; + default: + dev_dbg(&dev->dev, "Unrecognized hub protocol %d\n", + dev->descriptor->bDeviceProtocol); + break; + } + + /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ + switch (hub->desc.wHubCharacteristics & HUB_CHAR_TTTT) { + case HUB_TTTT_8_BITS: + if (dev->descriptor->bDeviceProtocol != 0) { + hub->tt.think_time = 666; + dev_dbg(&dev->dev, "TT requires at most %d FS bit times (%d ns)\n", + 8, hub->tt.think_time); + } + break; + case HUB_TTTT_16_BITS: + hub->tt.think_time = 666 * 2; + dev_dbg(&dev->dev, "TT requires at most %d FS bit times (%d ns)\n", + 16, hub->tt.think_time); + break; + case HUB_TTTT_24_BITS: + hub->tt.think_time = 666 * 3; + dev_dbg(&dev->dev, "TT requires at most %d FS bit times (%d ns)\n", + 24, hub->tt.think_time); + break; + case HUB_TTTT_32_BITS: + hub->tt.think_time = 666 * 4; + dev_dbg(&dev->dev, "TT requires at most %d FS bit times (%d ns)\n", + 32, hub->tt.think_time); + break; + } + dev_dbg(&dev->dev, "power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); dev_dbg(&dev->dev, "hub controller current requirement: %dmA\n", @@ -517,13 +596,15 @@ static int usb_hub_configure(struct usb_device *dev) if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { dev_dbg(&dev->dev, "%s: failed to get Status - " \ "too long: %d\n", __func__, descriptor->bLength); - return -1; + ret = -1; + goto out; } if (usb_get_hub_status(dev, buffer) < 0) { dev_dbg(&dev->dev, "%s: failed to get Status %lX\n", __func__, dev->status); - return -1; + ret = -1; + goto out; } hubsts = (struct usb_hub_status *)buffer; @@ -536,9 +617,33 @@ static int usb_hub_configure(struct usb_device *dev) dev_dbg(&dev->dev, "%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); + + if (dev->host->update_hub_device) { + ret = dev->host->update_hub_device(dev); + if (ret) + goto out; + } + + if (!usb_hub_is_root_hub(dev) && usb_hub_is_superspeed(dev)) { + /* + * This request sets the value that the hub uses to + * determine the index into the 'route string index' + * for this hub. + */ + ret = usb_set_hub_depth(dev, dev->level - 1); + if (ret < 0) { + dev_dbg(&dev->dev, "failed to set hub depth (0x%08lx)\n", + dev->status); + goto out; + } + } + usb_hub_power_on(hub); - return 0; + ret = 0; +out: + dma_free(buffer); + return ret; } static int usb_hub_configure_ports(struct usb_device *dev) @@ -572,7 +677,7 @@ static int usb_hub_configure_ports(struct usb_device *dev) return usb_device_list_scan(); } -static int usb_hub_detect(struct device_d *dev) +static int usb_hub_detect(struct device *dev) { struct usb_device *usbdev = container_of(dev, struct usb_device, dev); int i; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h deleted file mode 100644 index 74921b66fd..0000000000 --- a/drivers/usb/core/hub.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __CORE_HUB_H -#define __CORE_HUB_H - -int hub_port_reset(struct usb_device *hub, int port, - struct usb_device *usb); - -#endif /* __CORE_HUB_H */ diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 979088ef4e..25203c6064 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * usb devicetree helper functions - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <common.h> -#include <usb/usb.h> -#include <usb/phy.h> +#include <linux/usb/usb.h> +#include <linux/usb/phy.h> #include <of.h> static const char *usb_dr_modes[] = { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index d29cd1328b..1f6f1d7c41 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * * Most of this source has been derived from the Linux USB @@ -14,21 +15,6 @@ * * Adapted for barebox: * (C) Copyright 2001 Denis Peter, MPL AG Switzerland - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ /* @@ -40,7 +26,6 @@ * * For each transfer (except "Interrupt") we wait for completion. */ - #define pr_fmt(fmt) "usb: " fmt #include <common.h> @@ -53,11 +38,10 @@ #include <init.h> #include <dma.h> -#include <usb/usb.h> -#include <usb/ch9.h> +#include <linux/usb/usb.h> +#include <linux/usb/ch9.h> #include "usb.h" -#include "hub.h" #define USB_BUFSIZ 512 @@ -69,7 +53,7 @@ LIST_HEAD(usb_device_list); static void print_usb_device(struct usb_device *dev) { - pr_info("Bus %03d Device %03d: ID %04x:%04x %s\n", + dev_info(&dev->dev, "Bus %03d Device %03d: ID %04x:%04x %s\n", dev->host->busnum, dev->devnum, dev->descriptor->idVendor, dev->descriptor->idProduct, @@ -80,28 +64,44 @@ static int host_busnum = 1; static inline int usb_host_acquire(struct usb_host *host) { - if (host->sem) + if (slice_acquired(&host->slice)) return -EAGAIN; - host->sem++; + + slice_acquire(&host->slice); + return 0; } static inline void usb_host_release(struct usb_host *host) { - if (host->sem > 0) - host->sem--; + slice_release(&host->slice); +} + +static int usb_hw_detect(struct device *dev) +{ + struct usb_host *host; + + list_for_each_entry(host, &host_list, list) { + if (dev == host->hw_dev) + return usb_host_detect(host); + } + + return -ENODEV; } int usb_register_host(struct usb_host *host) { list_add_tail(&host->list, &host_list); host->busnum = host_busnum++; - host->sem = 0; + slice_init(&host->slice, dev_name(host->hw_dev)); + if (!host->hw_dev->detect) + host->hw_dev->detect = usb_hw_detect; return 0; } void usb_unregister_host(struct usb_host *host) { + slice_exit(&host->slice); list_del(&host->list); } @@ -112,7 +112,7 @@ static int usb_set_configuration(struct usb_device *dev, int configuration) { int res; - pr_debug("set configuration %d\n", configuration); + dev_dbg(&dev->dev, "set configuration %d\n", configuration); /* set setup command */ res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -124,7 +124,7 @@ static int usb_set_configuration(struct usb_device *dev, int configuration) dev->toggle[1] = 0; return 0; } else - return -1; + return res; } /* The routine usb_set_maxpacket_ep() is extracted from the loop of routine @@ -147,21 +147,21 @@ usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep) /* Control => bidirectional */ dev->epmaxpacketout[b] = ep->wMaxPacketSize; dev->epmaxpacketin[b] = ep->wMaxPacketSize; - pr_debug("##Control EP epmaxpacketout/in[%d] = %d\n", + dev_dbg(&dev->dev, "##Control EP epmaxpacketout/in[%d] = %d\n", b, dev->epmaxpacketin[b]); } else { if ((ep->bEndpointAddress & 0x80) == 0) { /* OUT Endpoint */ if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) { dev->epmaxpacketout[b] = ep->wMaxPacketSize; - pr_debug("##EP epmaxpacketout[%d] = %d\n", + dev_dbg(&dev->dev, "##EP epmaxpacketout[%d] = %d\n", b, dev->epmaxpacketout[b]); } } else { /* IN Endpoint */ if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) { dev->epmaxpacketin[b] = ep->wMaxPacketSize; - pr_debug("##EP epmaxpacketin[%d] = %d\n", + dev_dbg(&dev->dev, "##EP epmaxpacketin[%d] = %d\n", b, dev->epmaxpacketin[b]); } } /* if out */ @@ -193,6 +193,7 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c int index, ifno, epno, curr_if_num; int i; unsigned char *ch; + struct usb_interface *if_desc; ifno = -1; epno = -1; @@ -201,7 +202,7 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c dev->configno = cfgno; head = (struct usb_descriptor_header *) &buffer[0]; if (head->bDescriptorType != USB_DT_CONFIG) { - printf(" ERROR: NOT USB_CONFIG_DESC %x\n", + dev_err(&dev->dev, " ERROR: NOT USB_CONFIG_DESC %x\n", head->bDescriptorType); return -1; } @@ -224,7 +225,7 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c * next memcpy() will corrupt dev->config */ if (ifno > USB_MAXINTERFACES) { - printf("ifno = %d > " + dev_err(&dev->dev, "ifno = %d > " "USB_MAXINTERFACES = %d !\n", ifno, USB_MAXINTERFACES); @@ -250,13 +251,18 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c &buffer[index], buffer[index]); le16_to_cpus(&(dev->config.interface[ifno].ep_desc[epno].\ wMaxPacketSize)); - pr_debug("if %d, ep %d\n", ifno, epno); + dev_dbg(&dev->dev, "if %d, ep %d\n", ifno, epno); + break; + case USB_DT_SS_ENDPOINT_COMP: + if_desc = &dev->config.interface[ifno]; + memcpy(&if_desc->ss_ep_comp_desc[epno], + &buffer[index], buffer[index]); break; default: if (head->bLength == 0) return 1; - pr_debug("unknown Description Type : %x\n", + dev_dbg(&dev->dev, "unknown Description Type : %x\n", head->bDescriptorType); { @@ -273,23 +279,6 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c return 1; } -/** - * set address of a device to the value in dev->devnum. - * This can only be done by addressing the device via the default address (0) - */ -static int usb_set_address(struct usb_device *dev) -{ - int res; - - pr_debug("set address %d\n", dev->devnum); - - res = usb_control_msg(dev, usb_snddefctrl(dev), - USB_REQ_SET_ADDRESS, 0, - (dev->devnum), 0, - NULL, 0, USB_CNTL_TIMEOUT); - return res; -} - static int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { @@ -301,29 +290,30 @@ static int usb_get_descriptor(struct usb_device *dev, unsigned char type, return res; } -/* - * By the time we get here, the device has gotten a new device ID - * and is in the default state. We need to identify the thing and - * get the ball rolling.. - * - * Returns 0 for success, != 0 for error. - */ -int usb_new_device(struct usb_device *dev) +static int get_descriptor_len(struct usb_device *dev, int len, int expect_len) { - int addr, err; - int tmp; - void *buf; - struct usb_device_descriptor *desc; - struct usb_device *parent = dev->parent; - char str[16]; + int err; - buf = dma_alloc(USB_BUFSIZ); + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, dev->descriptor, len); + if (err < expect_len) { + if (err < 0) { + dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n", + err); + return err; + } else { + dev_err(&dev->dev, "USB device descriptor short read (expected %i, got %i)\n", + expect_len, err); + return -EIO; + } + } - /* We still haven't set the Address yet */ - addr = dev->devnum; - dev->devnum = 0; + return 0; +} - /* This is a Windows scheme of initialization sequence, with double +static int usb_setup_descriptor(struct usb_device *dev, bool do_read) +{ + /* + * This is a Windows scheme of initialization sequence, with double * reset of the device (Linux uses the same sequence) * Some equipment is said to work only with such init sequence; this * patch is based on the work by Alan Stern: @@ -331,38 +321,50 @@ int usb_new_device(struct usb_device *dev) * thread_id=5729457&forum_id=5398 */ - /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is + /* + * send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is * only 18 bytes long, this will terminate with a short packet. But if * the maxpacket size is 8 or 16 the device may be waiting to transmit - * some more, or keeps on retransmitting the 8 byte header. */ - - desc = buf; - dev->descriptor->bMaxPacketSize0 = 64; /* Start off at 64 bytes */ - /* Default to 64 byte max packet size */ - dev->maxpacketsize = PACKET_SIZE_64; - dev->epmaxpacketin[0] = 64; - dev->epmaxpacketout[0] = 64; + * some more, or keeps on retransmitting the 8 byte header. + */ - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); - if (err < 0) { - pr_debug("%s: usb_get_descriptor() failed with %d\n", __func__, err); - goto err_out; + if (dev->speed == USB_SPEED_LOW) { + dev->descriptor->bMaxPacketSize0 = 8; + dev->maxpacketsize = PACKET_SIZE_8; + } else { + dev->descriptor->bMaxPacketSize0 = 64; + dev->maxpacketsize = PACKET_SIZE_64; } + dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0; - dev->descriptor->bMaxPacketSize0 = desc->bMaxPacketSize0; - - /* find the port number we're at */ - if (parent) { - /* reset the port for the second time */ - err = hub_port_reset(dev->parent, dev->portnr - 1, dev); - if (err < 0) { - printf("\n Couldn't reset port %i\n", dev->portnr); - goto err_out; - } + if (do_read && dev->speed == USB_SPEED_FULL) { + int err; + + /* + * Validate we've received only at least 8 bytes, not that + * we've received the entire descriptor. The reasoning is: + * - The code only uses fields in the first 8 bytes, so + * that's all we need to have fetched at this stage. + * - The smallest maxpacket size is 8 bytes. Before we know + * the actual maxpacket the device uses, the USB controller + * may only accept a single packet. Consequently we are only + * guaranteed to receive 1 packet (at least 8 bytes) even in + * a non-error case. + * + * At least the DWC2 controller needs to be programmed with + * the number of packets in addition to the number of bytes. + * A request for 64 bytes of data with the maxpacket guessed + * as 64 (above) yields a request for 1 packet. + */ + err = get_descriptor_len(dev, 64, 8); + if (err) + return err; + + dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0; } - dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0; - dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0; switch (dev->descriptor->bMaxPacketSize0) { case 8: dev->maxpacketsize = PACKET_SIZE_8; @@ -377,29 +379,90 @@ int usb_new_device(struct usb_device *dev) dev->maxpacketsize = PACKET_SIZE_64; break; } - dev->devnum = addr; + + return 0; +} + +/** + * set address of a device to the value in dev->devnum. + * This can only be done by addressing the device via the default address (0) + */ +static int usb_set_address(struct usb_device *dev) +{ + int res; + + dev_dbg(&dev->dev, "set address %d\n", dev->devnum); + + res = usb_control_msg(dev, usb_snddefctrl(dev), + USB_REQ_SET_ADDRESS, 0, + (dev->devnum), 0, + NULL, 0, USB_CNTL_TIMEOUT); + return res; +} + +/* + * By the time we get here, the device is in the default state. We need to + * identify the thing and get the ball rolling.. + * + * Returns 0 for success, != 0 for error. + */ +int usb_new_device(struct usb_device *dev) +{ + int err; + void *buf; + struct usb_host *host = dev->host; + struct usb_device *parent = dev->parent; + char str[16]; + + if (parent) + dev_set_name(&dev->dev, "%s-%d", parent->dev.name, + dev->portnr - 1); + else + dev_set_name(&dev->dev, "usb%d", dev->host->busnum); + + dev->dev.id = DEVICE_ID_SINGLE; + + buf = dma_alloc(USB_BUFSIZ); + + if (parent) + dev->level = parent->level + 1; + + if (host->alloc_device) { + err = host->alloc_device(dev); + if (err) + goto err_out; + } + + usb_setup_descriptor(dev, !host->no_desc_before_addr); + + dev->devnum = ++dev_index; err = usb_set_address(dev); /* set address */ if (err < 0) { - printf("\n USB device not accepting new address " \ + dev_err(&dev->dev, "USB device not accepting new address " \ "(error=%lX)\n", dev->status); goto err_out; } mdelay(10); /* Let the SET_ADDRESS settle */ - tmp = sizeof(*dev->descriptor); + if (host->no_desc_before_addr) { + err = usb_setup_descriptor(dev, true); + if (err) + goto err_out; + } err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, dev->descriptor, sizeof(*dev->descriptor)); - if (err < tmp) { + if (err < sizeof(*dev->descriptor)) { if (err < 0) - printf("unable to get device descriptor (error=%d)\n", + dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n", err); else - printf("USB device descriptor short read " \ - "(expected %i, got %i)\n", tmp, err); + dev_err(&dev->dev, "USB device descriptor short read " \ + "(expected %zu, got %i)\n", + sizeof(*dev->descriptor), err); goto err_out; } /* correct le values */ @@ -412,12 +475,14 @@ int usb_new_device(struct usb_device *dev) usb_parse_config(dev, buf, 0); usb_set_maxpacket(dev); /* we set the default configuration here */ - if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) { - printf("failed to set default configuration " \ - "len %d, status %lX\n", dev->act_len, dev->status); + err = usb_set_configuration(dev, dev->config.desc.bConfigurationValue); + if (err) { + dev_err(&dev->dev, "Setting default configuration failed with: %pe\n" \ + "len %d, status %lX\n", ERR_PTR(err), + dev->act_len, dev->status); goto err_out; } - pr_debug("new device: Mfr=%d, Product=%d, SerialNumber=%d\n", + dev_dbg(&dev->dev, "new device: Mfr=%d, Product=%d, SerialNumber=%d\n", dev->descriptor->iManufacturer, dev->descriptor->iProduct, dev->descriptor->iSerialNumber); memset(dev->mf, 0, sizeof(dev->mf)); @@ -433,20 +498,11 @@ int usb_new_device(struct usb_device *dev) usb_string(dev, dev->descriptor->iSerialNumber, dev->serial, sizeof(dev->serial)); - if (parent) { - dev_set_name(&dev->dev, "%s-%d", parent->dev.name, - dev->portnr - 1); - } else { - dev_set_name(&dev->dev, "usb%d", dev->host->busnum); - } - - dev->dev.id = DEVICE_ID_SINGLE; - print_usb_device(dev); err = register_device(&dev->dev); if (err) { - printf("Failed to register device: %s\n", strerror(-err)); + dev_err(&dev->dev, "Failed to register device: %pe\n", ERR_PTR(err)); goto err_out; } @@ -478,6 +534,7 @@ void usb_free_device(struct usb_device *usbdev) { dma_free(usbdev->descriptor); dma_free(usbdev->setup_packet); + free_device_res(&usbdev->dev); free(usbdev); } @@ -507,7 +564,6 @@ struct usb_device *usb_alloc_new_device(void) { struct usb_device *usbdev = xzalloc(sizeof (*usbdev)); - usbdev->devnum = ++dev_index; usbdev->maxchild = 0; usbdev->dev.bus = &usb_bus_type; usbdev->setup_packet = dma_alloc(sizeof(*usbdev->setup_packet)); @@ -520,10 +576,14 @@ int usb_host_detect(struct usb_host *host) { int ret; + of_usb_host_probe_hubs(host); + if (!host->root_dev) { - ret = host->init(host); - if (ret) - return ret; + if (host->init) { + ret = host->init(host); + if (ret) + return ret; + } host->root_dev = usb_alloc_new_device(); host->root_dev->dev.parent = host->hw_dev; @@ -541,7 +601,7 @@ int usb_host_detect(struct usb_host *host) return 0; } -void usb_rescan(void) +int usb_rescan(void) { struct usb_host *host; int ret; @@ -555,6 +615,22 @@ void usb_rescan(void) } pr_info("%d USB Device(s) found\n", dev_count); + + if (IS_ENABLED(CONFIG_USB_OTGDEV)) { + unsigned int skipped_otg = 0; + struct device *dev; + + bus_for_each_device(&otg_bus_type, dev) { + if (otg_device_get_mode(dev) == USB_DR_MODE_OTG) + skipped_otg++; + } + + if (skipped_otg) + pr_notice("%u unconfigured OTG controller(s) were not scanned\n", + skipped_otg); + } + + return dev_count; } /*------------------------------------------------------------------- @@ -593,7 +669,7 @@ int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned char request, unsigned char requesttype, unsigned short value, unsigned short index, - void *data, unsigned short size, int timeout) + void *data, unsigned short size, int timeout_ms) { struct usb_host *host = dev->host; int ret; @@ -609,13 +685,13 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, setup_packet->value = cpu_to_le16(value); setup_packet->index = cpu_to_le16(index); setup_packet->length = cpu_to_le16(size); - pr_debug("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \ + dev_dbg(&dev->dev, "usb_control_msg: request: 0x%X, requesttype: 0x%X, " \ "value 0x%X index 0x%X length 0x%X\n", request, requesttype, value, index, size); dev->status = USB_ST_NOT_PROC; /*not yet processed */ ret = host->submit_control_msg(dev, pipe, data, size, setup_packet, - timeout); + timeout_ms); usb_host_release(host); @@ -631,7 +707,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, * synchronous behavior */ int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) + void *data, int len, int *actual_length, int timeout_ms) { struct usb_host *host = dev->host; int ret; @@ -644,7 +720,7 @@ int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, return ret; dev->status = USB_ST_NOT_PROC; /* not yet processed */ - ret = host->submit_bulk_msg(dev, pipe, data, len, timeout); + ret = host->submit_bulk_msg(dev, pipe, data, len, timeout_ms); usb_host_release(host); @@ -719,23 +795,23 @@ int usb_get_configuration_no(struct usb_device *dev, result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9); if (result < 9) { if (result < 0) - printf("unable to get descriptor, error %lX\n", + dev_err(&dev->dev, "unable to get descriptor, error %lX\n", dev->status); else - printf("config descriptor too short " \ + dev_err(&dev->dev, "config descriptor too short " \ "(expected %i, got %i)\n", 9, result); return -1; } tmp = le16_to_cpu(config->wTotalLength); if (tmp > USB_BUFSIZ) { - pr_debug("usb_get_configuration_no: failed to get " \ + dev_dbg(&dev->dev, "usb_get_configuration_no: failed to get " \ "descriptor - too long: %u\n", tmp); return -1; } result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp); - pr_debug("get_conf_no %d Result %d, wLength %u\n", + dev_dbg(&dev->dev, "get_conf_no %d Result %d, wLength %u\n", cfgno, result, tmp); return result; } @@ -755,7 +831,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) } } if (!if_face) { - printf("selecting invalid interface %d", interface); + dev_err(&dev->dev, "selecting invalid interface %d", interface); return -1; } /* @@ -902,31 +978,33 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, */ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) { - unsigned char mybuf[USB_BUFSIZ]; unsigned char *tbuf; - int err; + int err = 0; unsigned int u, idx; if (size <= 0 || !buf || !index) return -1; + + tbuf = dma_alloc(USB_BUFSIZ); buf[0] = 0; - tbuf = &mybuf[0]; /* get langid for strings if it's not yet known */ if (!dev->have_langid) { err = usb_string_sub(dev, 0, 0, tbuf); if (err < 0) { - pr_debug("error getting string descriptor 0 " \ + dev_dbg(&dev->dev, "error getting string descriptor 0 " \ "(error=%lx)\n", dev->status); - return -1; + err = -1; + goto fail; } else if (tbuf[0] < 4) { pr_debug("string descriptor 0 too short\n"); - return -1; + err = -1; + goto fail; } else { dev->have_langid = -1; dev->string_langid = tbuf[2] | (tbuf[3] << 8); /* always use the first langid listed */ - pr_debug("USB device number %d default " \ + dev_dbg(&dev->dev, "USB device number %d default " \ "language ID 0x%x\n", dev->devnum, dev->string_langid); } @@ -934,7 +1012,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = usb_string_sub(dev, dev->string_langid, index, tbuf); if (err < 0) - return err; + goto fail; size--; /* leave room for trailing NULL char in output buffer */ for (idx = 0, u = 2; u < err; u += 2) { @@ -947,6 +1025,8 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) } buf[idx] = 0; err = idx; +fail: + dma_free(tbuf); return err; } @@ -1042,7 +1122,7 @@ static const struct usb_device_id *usb_match_id(struct usb_device *usbdev, } EXPORT_SYMBOL(usb_match_id); -static int usb_match(struct device_d *dev, struct driver_d *drv) +static int usb_match(struct device *dev, struct driver *drv) { struct usb_device *usbdev = container_of(dev, struct usb_device, dev); struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); @@ -1059,7 +1139,7 @@ static int usb_match(struct device_d *dev, struct driver_d *drv) return 1; } -static int usb_probe(struct device_d *dev) +static int usb_probe(struct device *dev) { struct usb_device *usbdev = container_of(dev, struct usb_device, dev); struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); @@ -1070,7 +1150,7 @@ static int usb_probe(struct device_d *dev) return usbdrv->probe(usbdev, id); } -static void usb_remove(struct device_d *dev) +static void usb_remove(struct device *dev) { struct usb_device *usbdev = container_of(dev, struct usb_device, dev); struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index a5bb255121..0d4f80c21d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef __CORE_USB_H #define __CORE_USB_H |