diff options
Diffstat (limited to 'drivers/usb')
174 files changed, 1630 insertions, 1077 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 70e6c956c23c..e4b27413f528 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB device configuration # diff --git a/drivers/usb/README b/drivers/usb/README deleted file mode 100644 index 2144e7dbfa41..000000000000 --- a/drivers/usb/README +++ /dev/null @@ -1,54 +0,0 @@ -To understand all the Linux-USB framework, you'll use these resources: - - * This source code. This is necessarily an evolving work, and - includes kerneldoc that should help you get a current overview. - ("make pdfdocs", and then look at "usb.pdf" for host side and - "gadget.pdf" for peripheral side.) Also, Documentation/usb has - more information. - - * The USB 2.0 specification (from www.usb.org), with supplements - such as those for USB OTG and the various device classes. - The USB specification has a good overview chapter, and USB - peripherals conform to the widely known "Chapter 9". - - * Chip specifications for USB controllers. Examples include - host controllers (on PCs, servers, and more); peripheral - controllers (in devices with Linux firmware, like printers or - cell phones); and hard-wired peripherals like Ethernet adapters. - - * Specifications for other protocols implemented by USB peripheral - functions. Some are vendor-specific; others are vendor-neutral - but just standardized outside of the www.usb.org team. - -Here is a list of what each subdirectory here is, and what is contained in -them. - -core/ - This is for the core USB host code, including the - usbfs files and the hub class driver ("hub_wq"). - -host/ - This is for USB host controller drivers. This - includes UHCI, OHCI, EHCI, and others that might - be used with more specialized "embedded" systems. - -gadget/ - This is for USB peripheral controller drivers and - the various gadget drivers which talk to them. - - -Individual USB driver directories. A new driver should be added to the -first subdirectory in the list below that it fits into. - -image/ - This is for still image drivers, like scanners or - digital cameras. -../input/ - This is for any driver that uses the input subsystem, - like keyboard, mice, touchscreens, tablets, etc. -../media/ - This is for multimedia drivers, like video cameras, - radios, and any other drivers that talk to the v4l - subsystem. -../net/ - This is for network drivers. -serial/ - This is for USB to serial drivers. -storage/ - This is for USB mass-storage drivers. -class/ - This is for all USB device drivers that do not fit - into any of the above categories, and work for a range - of USB Class specified devices. -misc/ - This is for all USB device drivers that do not fit - into any of the above categories. diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index 0f922942a07a..989aaa3b080d 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB/ATM DSL configuration # diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index ee34e9046f7e..eb37ebfcb123 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_CHIPIDEA tristate "ChipIdea Highspeed Dual Role Controller" depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index e81de9ca8729..ceec8d5985d4 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -7,10 +7,8 @@ #include <linux/module.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/dma-mapping.h> #include <linux/usb/chipidea.h> #include <linux/usb/of.h> #include <linux/clk.h> @@ -152,8 +150,8 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) dev_warn(dev, "No over current polarity defined\n"); } - if (of_find_property(np, "external-vbus-divider", NULL)) - data->evdo = 1; + data->pwr_pol = of_property_read_bool(np, "power-active-high"); + data->evdo = of_property_read_bool(np, "external-vbus-divider"); if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) data->ulpi = 1; @@ -316,7 +314,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (IS_ERR(data->usbmisc_data)) return PTR_ERR(data->usbmisc_data); - if (of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) { + if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) + && data->usbmisc_data) { pdata.flags |= CI_HDRC_IMX_IS_HSIC; data->usbmisc_data->hsic = 1; data->pinctrl = devm_pinctrl_get(dev); diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 7cc53e2ce564..c842e03f8767 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -18,6 +18,7 @@ struct imx_usbmisc_data { /* true if dt specifies polarity */ unsigned int oc_pol_configured:1; + unsigned int pwr_pol:1; /* power polarity */ unsigned int evdo:1; /* set external vbus divider option */ unsigned int ulpi:1; /* connected to an ULPI phy */ unsigned int hsic:1; /* HSIC controlller */ diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 772851bee99b..12025358bb3c 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -130,6 +130,7 @@ static int tegra_udc_remove(struct platform_device *pdev) { struct tegra_udc *udc = platform_get_drvdata(pdev); + ci_hdrc_remove_device(udc->dev); usb_phy_set_suspend(udc->phy, 1); clk_disable_unprepare(udc->clk); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 7bfcbb23c2a4..27749ace2d93 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -954,25 +954,47 @@ static int ci_hdrc_probe(struct platform_device *pdev) } else if (ci->platdata->usb_phy) { ci->usb_phy = ci->platdata->usb_phy; } else { + /* Look for a generic PHY first */ ci->phy = devm_phy_get(dev->parent, "usb-phy"); - ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); - /* if both generic PHY and USB PHY layers aren't enabled */ - if (PTR_ERR(ci->phy) == -ENOSYS && - PTR_ERR(ci->usb_phy) == -ENXIO) { - ret = -ENXIO; + if (PTR_ERR(ci->phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; goto ulpi_exit; + } else if (IS_ERR(ci->phy)) { + ci->phy = NULL; } - if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) { - ret = -EPROBE_DEFER; - goto ulpi_exit; + /* Look for a legacy USB PHY from device-tree next */ + if (!ci->phy) { + ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent, + "phys", 0); + + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } else if (IS_ERR(ci->usb_phy)) { + ci->usb_phy = NULL; + } } - if (IS_ERR(ci->phy)) - ci->phy = NULL; - else if (IS_ERR(ci->usb_phy)) - ci->usb_phy = NULL; + /* Look for any registered legacy USB PHY as last resort */ + if (!ci->phy && !ci->usb_phy) { + ci->usb_phy = devm_usb_get_phy(dev->parent, + USB_PHY_TYPE_USB2); + + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } else if (IS_ERR(ci->usb_phy)) { + ci->usb_phy = NULL; + } + } + + /* No USB PHY was found in the end */ + if (!ci->phy && !ci->usb_phy) { + ret = -ENXIO; + goto ulpi_exit; + } } ret = ci_usb_phy_init(ci); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 097ffbca0bd9..d8b67e150b12 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -63,6 +63,7 @@ #define MX6_BM_NON_BURST_SETTING BIT(1) #define MX6_BM_OVER_CUR_DIS BIT(7) #define MX6_BM_OVER_CUR_POLARITY BIT(8) +#define MX6_BM_PWR_POLARITY BIT(9) #define MX6_BM_WAKEUP_ENABLE BIT(10) #define MX6_BM_UTMI_ON_CLOCK BIT(13) #define MX6_BM_ID_WAKEUP BIT(16) @@ -383,6 +384,9 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) else if (data->oc_pol_configured) reg &= ~MX6_BM_OVER_CUR_POLARITY; } + /* If the polarity is not set keep it as setup by the bootlader */ + if (data->pwr_pol == 1) + reg |= MX6_BM_PWR_POLARITY; writel(reg, usbmisc->base + data->index * 4); /* SoC non-burst setting */ @@ -585,6 +589,9 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data) else if (data->oc_pol_configured) reg &= ~MX6_BM_OVER_CUR_POLARITY; } + /* If the polarity is not set keep it as setup by the bootlader */ + if (data->pwr_pol == 1) + reg |= MX6_BM_PWR_POLARITY; writel(reg, usbmisc->base); reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 971385fe9abc..52f3a531a82f 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Class driver configuration # diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ed8c62b2d9d1..739f8960811a 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1865,6 +1865,13 @@ static const struct usb_device_id acm_ids[] = { .driver_info = IGNORE_DEVICE, }, + { USB_DEVICE(0x1bc7, 0x0021), /* Telit 3G ACM only composition */ + .driver_info = SEND_ZERO_PACKET, + }, + { USB_DEVICE(0x1bc7, 0x0023), /* Telit 3G ACM + ECM composition */ + .driver_info = SEND_ZERO_PACKET, + }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) }, diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bec581fb7c63..9e9caff905d5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -1099,7 +1099,7 @@ static int wdm_post_reset(struct usb_interface *intf) rv = recover_from_urb_loss(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - return 0; + return rv; } static struct usb_driver wdm_driver = { diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 4d75d9a80001..bdb6bd0b63a6 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Core configuration # @@ -90,3 +91,15 @@ config USB_LEDS_TRIGGER_USBPORT This driver allows LEDs to be controlled by USB events. Enabling this trigger allows specifying list of USB ports that should turn on LED when some USB device gets connected. + +config USB_AUTOSUSPEND_DELAY + int "Default autosuspend delay" + depends on USB + default 2 + help + The default autosuspend delay in seconds. Can be overridden + with the usbcore.autosuspend command line or module parameter. + + The default value Linux has always had is 2 seconds. Change + this value if you want a different delay and cannot modify + the command line or module parameter. diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7b5cb28ffb35..20ff036b4c22 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -552,7 +552,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, unsigned char *buffer2; int size2; struct usb_descriptor_header *header; - int len, retval; + int retval; u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; unsigned iad_num = 0; @@ -707,8 +707,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, nalts[i] = j = USB_MAXALTSETTING; } - len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; - config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); + intfc = kzalloc(struct_size(intfc, altsetting, j), GFP_KERNEL); + config->intf_cache[i] = intfc; if (!intfc) return -ENOMEM; kref_init(&intfc->ref); @@ -800,13 +800,11 @@ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = 0; + int result = -ENOMEM; unsigned int cfgno, length; unsigned char *bigbuffer; struct usb_config_descriptor *desc; - cfgno = 0; - result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -832,8 +830,7 @@ int usb_get_configuration(struct usb_device *dev) if (!desc) goto err2; - result = 0; - for (; cfgno < ncfg; cfgno++) { + for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, @@ -889,7 +886,6 @@ int usb_get_configuration(struct usb_device *dev) goto err; } } - result = 0; err: kfree(desc); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index d65566341dd1..fa783531ee88 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -604,7 +604,7 @@ static void async_completed(struct urb *urb) snoop(&urb->dev->dev, "urb complete\n"); snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, as->status, COMPLETE, NULL, 0); - if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN) + if (usb_urb_dir_in(urb)) snoop_urb_data(urb, urb->actual_length); if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && @@ -1564,12 +1564,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb } for (totlen = u = 0; u < number_of_packets; u++) { /* - * arbitrary limit need for USB 3.0 - * bMaxBurst (0~15 allowed, 1~16 packets) - * bmAttributes (bit 1:0, mult 0~2, 1~3 packets) - * sizemax: 1024 * 16 * 3 = 49152 + * arbitrary limit need for USB 3.1 Gen2 + * sizemax: 96 DPs at SSP, 96 * 1024 = 98304 */ - if (isopkt[u].length > 49152) { + if (isopkt[u].length > 98304) { ret = -EINVAL; goto error; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 53564386ed57..8987cec9549d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1896,14 +1896,11 @@ int usb_runtime_idle(struct device *dev) return -EBUSY; } -int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; - if (enable && !udev->usb2_hw_lpm_allowed) - return 0; - if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) @@ -1913,6 +1910,24 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } +int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_capable || + !udev->usb2_hw_lpm_allowed || + udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 1); +} + +int usb_disable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 0); +} + #endif /* CONFIG_PM */ struct bus_type usb_bus_type = { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 356b05c82dbc..1ac9c1e5f773 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -118,6 +118,31 @@ int usb_choose_configuration(struct usb_device *udev) continue; } + /* + * Select first configuration as default for audio so that + * devices that don't comply with UAC3 protocol are supported. + * But, still iterate through other configurations and + * select UAC3 compliant config if present. + */ + if (desc && is_audio(desc)) { + /* Always prefer the first found UAC3 config */ + if (is_uac3_config(desc)) { + best = c; + break; + } + + /* If there is no UAC3 config, prefer the first config */ + else if (i == 0) + best = c; + + /* Unconditional continue, because the rest of the code + * in the loop is irrelevant for audio devices, and + * because it can reassign best, which for audio devices + * we don't want. + */ + continue; + } + /* When the first config's first interface is one of Microsoft's * pet nonstandard Ethernet-over-USB protocols, ignore it unless * this kernel has enabled the necessary host side driver. @@ -132,22 +157,6 @@ int usb_choose_configuration(struct usb_device *udev) #endif } - /* - * Select first configuration as default for audio so that - * devices that don't comply with UAC3 protocol are supported. - * But, still iterate through other configurations and - * select UAC3 compliant config if present. - */ - if (i == 0 && num_configs > 1 && desc && is_audio(desc)) { - best = c; - continue; - } - - if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) { - best = c; - break; - } - /* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 015b126ce455..3189181bb628 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -373,13 +373,19 @@ static const u8 ss_rh_config_descriptor[] = { * -1 is authorized for all devices except wireless (old behaviour) * 0 is unauthorized for all devices * 1 is authorized for all devices + * 2 is authorized for internal devices */ -static int authorized_default = -1; +#define USB_AUTHORIZE_WIRED -1 +#define USB_AUTHORIZE_NONE 0 +#define USB_AUTHORIZE_ALL 1 +#define USB_AUTHORIZE_INTERNAL 2 + +static int authorized_default = USB_AUTHORIZE_WIRED; module_param(authorized_default, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(authorized_default, "Default USB device authorization: 0 is not authorized, 1 is " - "authorized, -1 is authorized except for wireless USB (default, " - "old behaviour"); + "authorized, 2 is authorized for internal devices, -1 is " + "authorized except for wireless USB (default, old behaviour)"); /*-------------------------------------------------------------------------*/ /** @@ -884,7 +890,7 @@ static ssize_t authorized_default_show(struct device *dev, struct usb_hcd *hcd; hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd)); + return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy); } static ssize_t authorized_default_store(struct device *dev, @@ -900,11 +906,8 @@ static ssize_t authorized_default_store(struct device *dev, hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - if (val) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - + hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ? + val : USB_DEVICE_AUTHORIZE_ALL; result = size; } else { result = -EINVAL; @@ -2736,6 +2739,11 @@ int usb_add_hcd(struct usb_hcd *hcd, if (retval) return retval; + retval = usb_phy_roothub_set_mode(hcd->phy_roothub, + PHY_MODE_USB_HOST_SS); + if (retval) + goto err_usb_phy_roothub_power_on; + retval = usb_phy_roothub_power_on(hcd->phy_roothub); if (retval) goto err_usb_phy_roothub_power_on; @@ -2743,18 +2751,26 @@ 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) { - 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); + switch (authorized_default) { + case USB_AUTHORIZE_NONE: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_NONE; + break; + + case USB_AUTHORIZE_ALL: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_ALL; + break; + + case USB_AUTHORIZE_INTERNAL: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_INTERNAL; + break; + + case USB_AUTHORIZE_WIRED: + default: + hcd->dev_policy = hcd->wireless ? + USB_DEVICE_AUTHORIZE_NONE : USB_DEVICE_AUTHORIZE_ALL; + break; } + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* per default all interfaces are authorized */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1d1e61e980f3..8d4631c81b9f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -108,6 +108,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); static void hub_release(struct kref *kref); static int usb_reset_and_verify_device(struct usb_device *udev); static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, + u16 portstatus); static inline char *portspeed(struct usb_hub *hub, int portstatus) { @@ -607,6 +609,36 @@ static int hub_port_status(struct usb_hub *hub, int port1, status, change, NULL); } +static void hub_resubmit_irq_urb(struct usb_hub *hub) +{ + unsigned long flags; + int status; + + spin_lock_irqsave(&hub->irq_urb_lock, flags); + + if (hub->quiescing) { + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); + return; + } + + status = usb_submit_urb(hub->urb, GFP_ATOMIC); + if (status && status != -ENODEV && status != -EPERM && + status != -ESHUTDOWN) { + dev_err(hub->intfdev, "resubmit --> %d\n", status); + mod_timer(&hub->irq_urb_retry, jiffies + HZ); + } + + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); +} + +static void hub_retry_irq_urb(struct timer_list *t) +{ + struct usb_hub *hub = from_timer(hub, t, irq_urb_retry); + + hub_resubmit_irq_urb(hub); +} + + static void kick_hub_wq(struct usb_hub *hub) { struct usb_interface *intf; @@ -709,12 +741,7 @@ static void hub_irq(struct urb *urb) kick_hub_wq(hub); resubmit: - if (hub->quiescing) - return; - - status = usb_submit_urb(hub->urb, GFP_ATOMIC); - if (status != 0 && status != -ENODEV && status != -EPERM) - dev_err(hub->intfdev, "resubmit --> %d\n", status); + hub_resubmit_irq_urb(hub); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -1112,6 +1139,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_PORT_FEAT_ENABLE); } + /* Make sure a warm-reset request is handled by port_event */ + if (type == HUB_RESUME && + hub_port_warm_reset_required(hub, port1, portstatus)) + set_bit(port1, hub->event_bits); + /* * Add debounce if USB3 link is in polling/link training state. * Link will automatically transition to Enabled state after @@ -1264,10 +1296,13 @@ enum hub_quiescing_type { static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) { struct usb_device *hdev = hub->hdev; + unsigned long flags; int i; /* hub_wq and related activity won't re-trigger */ + spin_lock_irqsave(&hub->irq_urb_lock, flags); hub->quiescing = 1; + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); if (type != HUB_SUSPEND) { /* Disconnect all the children */ @@ -1278,6 +1313,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) } /* Stop hub_wq and related activity */ + del_timer_sync(&hub->irq_urb_retry); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); @@ -1810,6 +1846,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); + spin_lock_init(&hub->irq_urb_lock); + timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); usb_get_intf(intf); usb_get_dev(hdev); @@ -3220,8 +3258,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } /* disable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); if (usb_disable_ltm(udev)) { dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); @@ -3259,8 +3296,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_enable_ltm(udev); err_ltm: /* Try to enable USB2 hardware LPM again */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); if (udev->do_remote_wakeup) (void) usb_disable_remote_wakeup(udev); @@ -3543,8 +3579,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) hub_port_logical_disconnect(hub, port1); } else { /* Try to enable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); /* Try to enable USB3 LTM */ usb_enable_ltm(udev); @@ -4435,7 +4470,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { udev->usb2_hw_lpm_allowed = 1; - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); } } @@ -5649,8 +5684,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) /* Disable USB2 hardware LPM. * It will be re-enabled by the enumeration process. */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); /* Disable LPM while we reset the device and reinstall the alt settings. * Device-initiated LPM, and system exit latency settings are cleared @@ -5753,7 +5787,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4accfb63f7dc..a9e24e4b8df1 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,8 @@ struct usb_hub { struct delayed_work leds; struct delayed_work init_work; struct work_struct events; + spinlock_t irq_urb_lock; + struct timer_list irq_urb_retry; struct usb_port **ports; }; diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index dc7f7fd71684..c12ac56606c3 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -119,11 +119,6 @@ static const struct attribute_group ports_group = { .attrs = ports_attrs, }; -static const struct attribute_group *ports_groups[] = { - &ports_group, - NULL -}; - /*************************************** * Adding & removing ports ***************************************/ @@ -307,6 +302,7 @@ static int usbport_trig_notify(struct notifier_block *nb, unsigned long action, static int usbport_trig_activate(struct led_classdev *led_cdev) { struct usbport_trig_data *usbport_data; + int err; usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL); if (!usbport_data) @@ -315,6 +311,9 @@ static int usbport_trig_activate(struct led_classdev *led_cdev) /* List of ports */ INIT_LIST_HEAD(&usbport_data->ports); + err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group); + if (err) + goto err_free; usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports); usbport_trig_update_count(usbport_data); @@ -322,8 +321,11 @@ static int usbport_trig_activate(struct led_classdev *led_cdev) usbport_data->nb.notifier_call = usbport_trig_notify; led_set_trigger_data(led_cdev, usbport_data); usb_register_notify(&usbport_data->nb); - return 0; + +err_free: + kfree(usbport_data); + return err; } static void usbport_trig_deactivate(struct led_classdev *led_cdev) @@ -335,6 +337,8 @@ static void usbport_trig_deactivate(struct led_classdev *led_cdev) usbport_trig_remove_port(usbport_data, port); } + sysfs_remove_group(&led_cdev->dev->kobj, &ports_group); + usb_unregister_notify(&usbport_data->nb); kfree(usbport_data); @@ -344,7 +348,6 @@ static struct led_trigger usbport_led_trigger = { .name = "usbport", .activate = usbport_trig_activate, .deactivate = usbport_trig_deactivate, - .groups = ports_groups, }; static int __init usbport_trig_init(void) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index bfa5eda0cc26..82239f27c4cc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1243,8 +1243,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev->actconfig->interface[i] = NULL; } - if (dev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(dev, 0); + usb_disable_usb2_hardware_lpm(dev); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); @@ -2007,6 +2006,13 @@ free_interfaces: for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; + if (intf->dev.of_node && + !of_device_is_available(intf->dev.of_node)) { + dev_info(&dev->dev, "skipping disabled interface %d\n", + intf->cur_altsetting->desc.bInterfaceNumber); + continue; + } + dev_dbg(&dev->dev, "adding %s (config #%d, interface %d)\n", dev_name(&intf->dev), configuration, diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 38b2c776c4b4..7580493b867a 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -123,6 +123,34 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) } EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); +int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, + enum phy_mode mode) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_set_mode(roothub_entry->phy, mode); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode); + int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) { struct usb_phy_roothub *roothub_entry; diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index 88a3c037e9df..dad564e2d2d4 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -16,6 +16,8 @@ struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev); int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub); int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); +int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, + enum phy_mode mode); int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 514c5214ddb2..8bc35d53408b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -394,7 +394,8 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET }, /* Corsair K70 RGB */ - { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, /* Corsair Strafe */ { USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT | diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ea18284dfa9a..7e88fdfe3cf5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -528,7 +528,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, if (!ret) { udev->usb2_hw_lpm_allowed = value; - ret = usb_set_usb2_hardware_lpm(udev, value); + if (value) + ret = usb_enable_usb2_hardware_lpm(udev); + else + ret = usb_disable_usb2_hardware_lpm(udev); } usb_unlock_device(udev); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index f51750bcd152..0eab79f82ce4 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -70,9 +70,8 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; - urb = kmalloc(sizeof(struct urb) + - iso_packets * sizeof(struct usb_iso_packet_descriptor), - mem_flags); + urb = kmalloc(struct_size(urb, iso_frame_desc, iso_packets), + mem_flags); if (!urb) return NULL; usb_init_urb(urb); diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index e221861b3187..9043d7242d67 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -139,86 +139,123 @@ static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent, return acpi_find_child_device(parent, raw, false); } -static struct acpi_device *usb_acpi_find_companion(struct device *dev) +static struct acpi_device * +usb_acpi_get_companion_for_port(struct usb_port *port_dev) { struct usb_device *udev; struct acpi_device *adev; acpi_handle *parent_handle; + int port1; + + /* Get the struct usb_device point of port's hub */ + udev = to_usb_device(port_dev->dev.parent->parent); /* - * In the ACPI DSDT table, only usb root hub and usb ports are - * acpi device nodes. The hierarchy like following. - * Device (EHC1) - * Device (HUBN) - * Device (PR01) - * Device (PR11) - * Device (PR12) - * Device (PR13) - * ... - * So all binding process is divided into two parts. binding - * root hub and usb ports. + * The root hub ports' parent is the root hub. The non-root-hub + * ports' parent is the parent hub port which the hub is + * connected to. */ - if (is_usb_device(dev)) { - udev = to_usb_device(dev); - if (udev->parent) + if (!udev->parent) { + adev = ACPI_COMPANION(&udev->dev); + port1 = usb_hcd_find_raw_port_number(bus_to_hcd(udev->bus), + port_dev->portnum); + } else { + parent_handle = usb_get_hub_port_acpi_handle(udev->parent, + udev->portnum); + if (!parent_handle) return NULL; - /* root hub is only child (_ADR=0) under its parent, the HC */ - adev = ACPI_COMPANION(dev->parent); - return acpi_find_child_device(adev, 0, false); - } else if (is_usb_port(dev)) { - struct usb_port *port_dev = to_usb_port(dev); - int port1 = port_dev->portnum; - struct acpi_pld_info *pld; - acpi_handle *handle; - acpi_status status; - - /* Get the struct usb_device point of port's hub */ - udev = to_usb_device(dev->parent->parent); - - /* - * The root hub ports' parent is the root hub. The non-root-hub - * ports' parent is the parent hub port which the hub is - * connected to. - */ - if (!udev->parent) { - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - int raw; - - raw = usb_hcd_find_raw_port_number(hcd, port1); - - adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev), - raw); - - if (!adev) - return NULL; - } else { - parent_handle = - usb_get_hub_port_acpi_handle(udev->parent, - udev->portnum); - if (!parent_handle) - return NULL; - - acpi_bus_get_device(parent_handle, &adev); - - adev = usb_acpi_find_port(adev, port1); - - if (!adev) - return NULL; - } - handle = adev->handle; - status = acpi_get_physical_device_location(handle, &pld); - if (ACPI_FAILURE(status) || !pld) - return adev; + acpi_bus_get_device(parent_handle, &adev); + port1 = port_dev->portnum; + } + return usb_acpi_find_port(adev, port1); +} + +static struct acpi_device * +usb_acpi_find_companion_for_port(struct usb_port *port_dev) +{ + struct acpi_device *adev; + struct acpi_pld_info *pld; + acpi_handle *handle; + acpi_status status; + + adev = usb_acpi_get_companion_for_port(port_dev); + if (!adev) + return NULL; + + handle = adev->handle; + status = acpi_get_physical_device_location(handle, &pld); + if (!ACPI_FAILURE(status) && pld) { port_dev->location = USB_ACPI_LOCATION_VALID | pld->group_token << 8 | pld->group_position; port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); ACPI_FREE(pld); + } - return adev; + return adev; +} + +static struct acpi_device * +usb_acpi_find_companion_for_device(struct usb_device *udev) +{ + struct acpi_device *adev; + struct usb_port *port_dev; + struct usb_hub *hub; + + if (!udev->parent) { + /* root hub is only child (_ADR=0) under its parent, the HC */ + adev = ACPI_COMPANION(udev->dev.parent); + return acpi_find_child_device(adev, 0, false); } + hub = usb_hub_to_struct_hub(udev->parent); + if (!hub) + return NULL; + + /* + * This is an embedded USB device connected to a port and such + * devices share port's ACPI companion. + */ + port_dev = hub->ports[udev->portnum - 1]; + return usb_acpi_get_companion_for_port(port_dev); +} + +static struct acpi_device *usb_acpi_find_companion(struct device *dev) +{ + /* + * The USB hierarchy like following: + * + * Device (EHC1) + * Device (HUBN) + * Device (PR01) + * Device (PR11) + * Device (PR12) + * Device (FN12) + * Device (FN13) + * Device (PR13) + * ... + * where HUBN is root hub, and PRNN are USB ports and devices + * connected to them, and FNNN are individualk functions for + * connected composite USB devices. PRNN and FNNN may contain + * _CRS and other methods describing sideband resources for + * the connected device. + * + * On the kernel side both root hub and embedded USB devices are + * represented as instances of usb_device structure, and ports + * are represented as usb_port structures, so the whole process + * is split into 2 parts: finding companions for devices and + * finding companions for ports. + * + * Note that we do not handle individual functions of composite + * devices yet, for that we would need to assign companions to + * devices corresponding to USB interfaces. + */ + if (is_usb_device(dev)) + return usb_acpi_find_companion_for_device(to_usb_device(dev)); + else if (is_usb_port(dev)) + return usb_acpi_find_companion_for_port(to_usb_port(dev)); + return NULL; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4ebfbd737905..7fcb9f782931 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -46,8 +46,7 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> -#include "usb.h" - +#include "hub.h" const char *usbcore_name = "usbcore"; @@ -65,8 +64,8 @@ int usb_disabled(void) EXPORT_SYMBOL_GPL(usb_disabled); #ifdef CONFIG_PM -static int usb_autosuspend_delay = 2; /* Default delay value, - * in seconds */ +/* Default delay value, in seconds */ +static int usb_autosuspend_delay = CONFIG_USB_AUTOSUSPEND_DELAY; module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); @@ -536,6 +535,27 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) return hcd->wireless; } +static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd) +{ + struct usb_hub *hub; + + if (!dev->parent) + return true; /* Root hub always ok [and always wired] */ + + switch (hcd->dev_policy) { + case USB_DEVICE_AUTHORIZE_NONE: + default: + return false; + + case USB_DEVICE_AUTHORIZE_ALL: + return true; + + case USB_DEVICE_AUTHORIZE_INTERNAL: + hub = usb_hub_to_struct_hub(dev->parent); + return hub->ports[dev->portnum - 1]->connect_type == + USB_PORT_CONNECT_TYPE_HARD_WIRED; + } +} /** * usb_alloc_dev - usb device constructor (usbcore-internal) @@ -663,12 +683,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->connect_time = jiffies; dev->active_duration = -jiffies; #endif - if (root_hub) /* Root hub always ok [and always wired] */ - dev->authorized = 1; - else { - dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); + + dev->authorized = usb_dev_authorized(dev, usb_hcd); + if (!root_hub) dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; - } + return dev; } EXPORT_SYMBOL_GPL(usb_alloc_dev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 546a2219454b..d95a5358f73d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -92,7 +92,8 @@ extern int usb_remote_wakeup(struct usb_device *dev); extern int usb_runtime_suspend(struct device *dev); extern int usb_runtime_resume(struct device *dev); extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); +extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev); +extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev); #else @@ -112,7 +113,12 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + return 0; +} + +static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { return 0; } diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index b6a495e98fd8..68d095ae2865 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_DWC2 tristate "DesignWare USB2 DRD Core Support" depends on HAS_DMA diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 68ad75a7460d..6812a8a3a98b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -261,7 +261,7 @@ static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); - dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); + dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); } } @@ -768,22 +768,13 @@ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) return desc_size; } -/* - * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. - * @hs_ep: The endpoint - * @dma_buff: DMA address to use - * @len: Length of the transfer - * - * This function will iterate over descriptor chain and fill its entries - * with corresponding information based on transfer data. - */ -static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, +static void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, + struct dwc2_dma_desc **desc, dma_addr_t dma_buff, - unsigned int len) + unsigned int len, + bool true_last) { - struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; - struct dwc2_dma_desc *desc = hs_ep->desc_list; u32 mps = hs_ep->ep.maxpacket; u32 maxsize = 0; u32 offset = 0; @@ -798,39 +789,77 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, hs_ep->desc_count = 1; for (i = 0; i < hs_ep->desc_count; ++i) { - desc->status = 0; - desc->status |= (DEV_DMA_BUFF_STS_HBUSY + (*desc)->status = 0; + (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); if (len > maxsize) { if (!hs_ep->index && !dir_in) - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); - desc->status |= (maxsize << - DEV_DMA_NBYTES_SHIFT & mask); - desc->buf = dma_buff + offset; + (*desc)->status |= + maxsize << DEV_DMA_NBYTES_SHIFT & mask; + (*desc)->buf = dma_buff + offset; len -= maxsize; offset += maxsize; } else { - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + if (true_last) + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); if (dir_in) - desc->status |= (len % mps) ? DEV_DMA_SHORT : - ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0); - if (len > maxsize) - dev_err(hsotg->dev, "wrong len %d\n", len); + (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : + ((hs_ep->send_zlp && true_last) ? + DEV_DMA_SHORT : 0); - desc->status |= + (*desc)->status |= len << DEV_DMA_NBYTES_SHIFT & mask; - desc->buf = dma_buff + offset; + (*desc)->buf = dma_buff + offset; } - desc->status &= ~DEV_DMA_BUFF_STS_MASK; - desc->status |= (DEV_DMA_BUFF_STS_HREADY + (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; + (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); - desc++; + (*desc)++; + } +} + +/* + * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. + * @hs_ep: The endpoint + * @ureq: Request to transfer + * @offset: offset in bytes + * @len: Length of the transfer + * + * This function will iterate over descriptor chain and fill its entries + * with corresponding information based on transfer data. + */ +static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, + struct usb_request *ureq, + unsigned int offset, + unsigned int len) +{ + struct dwc2_dma_desc *desc = hs_ep->desc_list; + struct scatterlist *sg; + int i; + u8 desc_count = 0; + + /* non-DMA sg buffer */ + if (!ureq->num_sgs) { + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, + ureq->dma + offset, len, true); + return; } + + /* DMA sg buffer */ + for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, + sg_dma_address(sg) + sg->offset, sg_dma_len(sg), + sg_is_last(sg)); + desc_count += hs_ep->desc_count; + } + + hs_ep->desc_count = desc_count; } /* @@ -944,7 +973,13 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) hs_ep->next_desc = 0; list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { - ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); if (ret) break; @@ -1100,7 +1135,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, offset = ureq->actual; /* Fill DDMA chain entries */ - dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, + dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq, offset, length); /* write descriptor chain address to control register */ @@ -1399,7 +1434,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, */ if (using_desc_dma(hs) && hs_ep->isochronous) { if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { - dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); } return 0; @@ -1987,13 +2028,12 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", index); if (using_desc_dma(hsotg)) { - /* Not specific buffer needed for ep0 ZLP */ - dma_addr_t dma = hs_ep->desc_list_dma; - if (!index) dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); - dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); + /* Not specific buffer needed for ep0 ZLP */ + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &hs_ep->desc_list, + hs_ep->desc_list_dma, 0, true); } else { dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | DXEPTSIZ_XFERSIZE(0), @@ -4005,6 +4045,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, ret = -ENOMEM; goto error1; } + epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT); hsotg->fifo_map |= 1 << fifo_index; epctrl |= DXEPCTL_TXFNUM(fifo_index); hs_ep->fifo_index = fifo_index; @@ -4385,6 +4426,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); + gadget->sg_supported = using_desc_dma(hsotg); dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index dd82fa516f3f..3f087962f498 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3981,10 +3981,8 @@ static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags) { struct dwc2_hcd_urb *urb; - u32 size = sizeof(*urb) + iso_desc_count * - sizeof(struct dwc2_hcd_iso_packet_desc); - urb = kzalloc(size, mem_flags); + urb = kzalloc(struct_size(urb, iso_descs, iso_desc_count), mem_flags); if (urb) urb->packet_count = iso_desc_count; return urb; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 1a0404fda596..2b1494460d0c 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && HAS_DMA @@ -86,11 +88,11 @@ config USB_DWC3_HAPS platform, please say 'Y' or 'M' here. config USB_DWC3_KEYSTONE - tristate "Texas Instruments Keystone2 Platforms" - depends on ARCH_KEYSTONE || COMPILE_TEST + tristate "Texas Instruments Keystone2/AM654 Platforms" + depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST default USB_DWC3 help - Support of USB2/3 functionality in TI Keystone2 platforms. + Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. Say 'Y' or 'M' here if you have one such device config USB_DWC3_OF_SIMPLE diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index df876418cb78..1528d395b156 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -692,7 +692,6 @@ struct dwc3_ep { #define DWC3_EP_WEDGE BIT(2) #define DWC3_EP_TRANSFER_STARTED BIT(3) #define DWC3_EP_PENDING_REQUEST BIT(5) -#define DWC3_EP_END_TRANSFER_PENDING BIT(7) /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN BIT(31) @@ -863,6 +862,7 @@ struct dwc3_hwparams { * @num_pending_sgs: counter to pending sgs * @num_queued_sgs: counter to the number of sgs which already got queued * @remaining: amount of data remaining + * @status: internal dwc3 request status tracking * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb * @trb_dma: DMA address of @trb @@ -871,7 +871,6 @@ struct dwc3_hwparams { * or unaligned OUT) * @direction: IN or OUT direction flag * @mapped: true when request has been dma-mapped - * @started: request is started */ struct dwc3_request { struct usb_request request; @@ -883,6 +882,14 @@ struct dwc3_request { unsigned num_pending_sgs; unsigned int num_queued_sgs; unsigned remaining; + + unsigned int status; +#define DWC3_REQUEST_STATUS_QUEUED 0 +#define DWC3_REQUEST_STATUS_STARTED 1 +#define DWC3_REQUEST_STATUS_CANCELLED 2 +#define DWC3_REQUEST_STATUS_COMPLETED 3 +#define DWC3_REQUEST_STATUS_UNKNOWN -1 + u8 epnum; struct dwc3_trb *trb; dma_addr_t trb_dma; @@ -892,7 +899,6 @@ struct dwc3_request { unsigned needs_extra_trb:1; unsigned direction:1; unsigned mapped:1; - unsigned started:1; }; /* diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 4f75ab3505b7..6759a7efd8d5 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -193,65 +193,69 @@ static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) * dwc3_gadget_event_string - returns event name * @event: the event code */ -static inline const char * -dwc3_gadget_event_string(char *str, const struct dwc3_event_devt *event) +static inline const char *dwc3_gadget_event_string(char *str, size_t size, + const struct dwc3_event_devt *event) { enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK; switch (event->type) { case DWC3_DEVICE_EVENT_DISCONNECT: - sprintf(str, "Disconnect: [%s]", + snprintf(str, size, "Disconnect: [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_RESET: - sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Reset [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CONNECT_DONE: - sprintf(str, "Connection Done [%s]", + snprintf(str, size, "Connection Done [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - sprintf(str, "Link Change [%s]", + snprintf(str, size, "Link Change [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_WAKEUP: - sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "WakeUp [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_EOPF: - sprintf(str, "End-Of-Frame [%s]", + snprintf(str, size, "End-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_SOF: - sprintf(str, "Start-Of-Frame [%s]", + snprintf(str, size, "Start-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - sprintf(str, "Erratic Error [%s]", + snprintf(str, size, "Erratic Error [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CMD_CMPL: - sprintf(str, "Command Complete [%s]", + snprintf(str, size, "Command Complete [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_OVERFLOW: - sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Overflow [%s]", + dwc3_gadget_link_string(state)); break; default: - sprintf(str, "UNKNOWN"); + snprintf(str, size, "UNKNOWN"); } return str; } -static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) +static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str, + size_t size) { switch (t & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: - sprintf(str, "Get Interface Status(Intf = %d, Length = %d)", - i, l); + snprintf(str, size, "Get Interface Status(Intf = %d, Length = %d)", + i, l); break; case USB_RECIP_ENDPOINT: - sprintf(str, "Get Endpoint Status(ep%d%s)", + snprintf(str, size, "Get Endpoint Status(ep%d%s)", i & ~USB_DIR_IN, i & USB_DIR_IN ? "in" : "out"); break; @@ -259,11 +263,11 @@ static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) } static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, - __u16 i, char *str) + __u16 i, char *str, size_t size) { switch (t & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - sprintf(str, "%s Device Feature(%s%s)", + snprintf(str, size, "%s Device Feature(%s%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", ({char *s; switch (v) { @@ -311,13 +315,13 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, } s; }) : ""); break; case USB_RECIP_INTERFACE: - sprintf(str, "%s Interface Feature(%s)", + snprintf(str, size, "%s Interface Feature(%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", v == USB_INTRF_FUNC_SUSPEND ? "Function Suspend" : "UNKNOWN"); break; case USB_RECIP_ENDPOINT: - sprintf(str, "%s Endpoint Feature(%s ep%d%s)", + snprintf(str, size, "%s Endpoint Feature(%s ep%d%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", v == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", i & ~USB_DIR_IN, @@ -326,15 +330,15 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, } } -static inline void dwc3_decode_set_address(__u16 v, char *str) +static inline void dwc3_decode_set_address(__u16 v, char *str, size_t size) { - sprintf(str, "Set Address(Addr = %02x)", v); + snprintf(str, size, "Set Address(Addr = %02x)", v); } static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, - __u16 i, __u16 l, char *str) + __u16 i, __u16 l, char *str, size_t size) { - sprintf(str, "%s %s Descriptor(Index = %d, Length = %d)", + snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)", b == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set", ({ char *s; switch (v >> 8) { @@ -393,87 +397,92 @@ static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, } -static inline void dwc3_decode_get_configuration(__u16 l, char *str) +static inline void dwc3_decode_get_configuration(__u16 l, char *str, + size_t size) { - sprintf(str, "Get Configuration(Length = %d)", l); + snprintf(str, size, "Get Configuration(Length = %d)", l); } -static inline void dwc3_decode_set_configuration(__u8 v, char *str) +static inline void dwc3_decode_set_configuration(__u8 v, char *str, size_t size) { - sprintf(str, "Set Configuration(Config = %d)", v); + snprintf(str, size, "Set Configuration(Config = %d)", v); } -static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str) +static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str, + size_t size) { - sprintf(str, "Get Interface(Intf = %d, Length = %d)", i, l); + snprintf(str, size, "Get Interface(Intf = %d, Length = %d)", i, l); } -static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str) +static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str, size_t size) { - sprintf(str, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); + snprintf(str, size, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); } -static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str) +static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str, + size_t size) { - sprintf(str, "Synch Frame(Endpoint = %d, Length = %d)", i, l); + snprintf(str, size, "Synch Frame(Endpoint = %d, Length = %d)", i, l); } -static inline void dwc3_decode_set_sel(__u16 l, char *str) +static inline void dwc3_decode_set_sel(__u16 l, char *str, size_t size) { - sprintf(str, "Set SEL(Length = %d)", l); + snprintf(str, size, "Set SEL(Length = %d)", l); } -static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str) +static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str, size_t size) { - sprintf(str, "Set Isochronous Delay(Delay = %d ns)", v); + snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", v); } /** * dwc3_decode_ctrl - returns a string represetion of ctrl request */ -static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, - __u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength) +static inline const char *dwc3_decode_ctrl(char *str, size_t size, + __u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength) { switch (bRequest) { case USB_REQ_GET_STATUS: - dwc3_decode_get_status(bRequestType, wIndex, wLength, str); + dwc3_decode_get_status(bRequestType, wIndex, wLength, str, + size); break; case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: dwc3_decode_set_clear_feature(bRequestType, bRequest, wValue, - wIndex, str); + wIndex, str, size); break; case USB_REQ_SET_ADDRESS: - dwc3_decode_set_address(wValue, str); + dwc3_decode_set_address(wValue, str, size); break; case USB_REQ_GET_DESCRIPTOR: case USB_REQ_SET_DESCRIPTOR: dwc3_decode_get_set_descriptor(bRequestType, bRequest, wValue, - wIndex, wLength, str); + wIndex, wLength, str, size); break; case USB_REQ_GET_CONFIGURATION: - dwc3_decode_get_configuration(wLength, str); + dwc3_decode_get_configuration(wLength, str, size); break; case USB_REQ_SET_CONFIGURATION: - dwc3_decode_set_configuration(wValue, str); + dwc3_decode_set_configuration(wValue, str, size); break; case USB_REQ_GET_INTERFACE: - dwc3_decode_get_intf(wIndex, wLength, str); + dwc3_decode_get_intf(wIndex, wLength, str, size); break; case USB_REQ_SET_INTERFACE: - dwc3_decode_set_intf(wValue, wIndex, str); + dwc3_decode_set_intf(wValue, wIndex, str, size); break; case USB_REQ_SYNCH_FRAME: - dwc3_decode_synch_frame(wIndex, wLength, str); + dwc3_decode_synch_frame(wIndex, wLength, str, size); break; case USB_REQ_SET_SEL: - dwc3_decode_set_sel(wLength, str); + dwc3_decode_set_sel(wLength, str, size); break; case USB_REQ_SET_ISOCH_DELAY: - dwc3_decode_set_isoch_delay(wValue, str); + dwc3_decode_set_isoch_delay(wValue, str, size); break; default: - sprintf(str, "%02x %02x %02x %02x %02x %02x %02x %02x", + snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x", bRequestType, bRequest, cpu_to_le16(wValue) & 0xff, cpu_to_le16(wValue) >> 8, @@ -490,16 +499,15 @@ static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, * dwc3_ep_event_string - returns event name * @event: then event code */ -static inline const char * -dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, - u32 ep0state) +static inline const char *dwc3_ep_event_string(char *str, size_t size, + const struct dwc3_event_depevt *event, u32 ep0state) { u8 epnum = event->endpoint_number; size_t len; int status; int ret; - ret = sprintf(str, "ep%d%s: ", epnum >> 1, + ret = snprintf(str, size, "ep%d%s: ", epnum >> 1, (epnum & 1) ? "in" : "out"); if (ret < 0) return "UNKNOWN"; @@ -509,7 +517,7 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: len = strlen(str); - sprintf(str + len, "Transfer Complete (%c%c%c)", + snprintf(str + len, size - len, "Transfer Complete (%c%c%c)", status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_LST ? 'L' : 'l'); @@ -517,12 +525,13 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, len = strlen(str); if (epnum <= 1) - sprintf(str + len, " [%s]", dwc3_ep0_state_string(ep0state)); + snprintf(str + len, size - len, " [%s]", + dwc3_ep0_state_string(ep0state)); break; case DWC3_DEPEVT_XFERINPROGRESS: len = strlen(str); - sprintf(str + len, "Transfer In Progress [%d] (%c%c%c)", + snprintf(str + len, size - len, "Transfer In Progress [%d] (%c%c%c)", event->parameters, status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', @@ -531,47 +540,51 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, case DWC3_DEPEVT_XFERNOTREADY: len = strlen(str); - sprintf(str + len, "Transfer Not Ready [%d]%s", + snprintf(str + len, size - len, "Transfer Not Ready [%d]%s", event->parameters, status & DEPEVT_STATUS_TRANSFER_ACTIVE ? " (Active)" : " (Not Active)"); + len = strlen(str); + /* Control Endpoints */ if (epnum <= 1) { int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status); switch (phase) { case DEPEVT_STATUS_CONTROL_DATA: - strcat(str, " [Data Phase]"); + snprintf(str + ret, size - ret, + " [Data Phase]"); break; case DEPEVT_STATUS_CONTROL_STATUS: - strcat(str, " [Status Phase]"); + snprintf(str + ret, size - ret, + " [Status Phase]"); } } break; case DWC3_DEPEVT_RXTXFIFOEVT: - strcat(str, "FIFO"); + snprintf(str + ret, size - ret, "FIFO"); break; case DWC3_DEPEVT_STREAMEVT: status = event->status; switch (status) { case DEPEVT_STREAMEVT_FOUND: - sprintf(str + ret, " Stream %d Found", + snprintf(str + ret, size - ret, " Stream %d Found", event->parameters); break; case DEPEVT_STREAMEVT_NOTFOUND: default: - strcat(str, " Stream Not Found"); + snprintf(str + ret, size - ret, " Stream Not Found"); break; } break; case DWC3_DEPEVT_EPCMDCMPLT: - strcat(str, "Endpoint Command Complete"); + snprintf(str + ret, size - ret, "Endpoint Command Complete"); break; default: - sprintf(str, "UNKNOWN"); + snprintf(str, size, "UNKNOWN"); } return str; @@ -611,14 +624,15 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) } } -static inline const char *dwc3_decode_event(char *str, u32 event, u32 ep0state) +static inline const char *dwc3_decode_event(char *str, size_t size, u32 event, + u32 ep0state) { const union dwc3_event evt = (union dwc3_event) event; if (evt.type.is_devspec) - return dwc3_gadget_event_string(str, &evt.devt); + return dwc3_gadget_event_string(str, size, &evt.devt); else - return dwc3_ep_event_string(str, &evt.depevt, ep0state); + return dwc3_ep_event_string(str, size, &evt.depevt, ep0state); } static inline const char *dwc3_ep_cmd_status_string(int status) diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 869725d15c74..726100d1ac0d 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -457,8 +457,13 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) * This device property is for kernel internal use only and * is expected to be set by the glue code. */ - if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) - return extcon_get_extcon_dev(name); + if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { + edev = extcon_get_extcon_dev(name); + if (!edev) + return ERR_PTR(-EPROBE_DEFER); + + return edev; + } np_phy = of_parse_phandle(dev->of_node, "phys", 0); np_conn = of_graph_get_remote_node(np_phy, -1, -1); diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index cb7fcd7c0ad8..c1e9ea621f41 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -78,7 +78,7 @@ static int dwc3_exynos_probe(struct platform_device *pdev) for (i = 0; i < exynos->num_clks; i++) { ret = clk_prepare_enable(exynos->clks[i]); if (ret) { - while (--i > 0) + while (i-- > 0) clk_disable_unprepare(exynos->clks[i]); return ret; } @@ -223,7 +223,7 @@ static int dwc3_exynos_resume(struct device *dev) for (i = 0; i < exynos->num_clks; i++) { ret = clk_prepare_enable(exynos->clks[i]); if (ret) { - while (--i > 0) + while (i-- > 0) clk_disable_unprepare(exynos->clks[i]); return ret; } diff --git a/drivers/usb/dwc3/dwc3-haps.c b/drivers/usb/dwc3/dwc3-haps.c index 02d57d98ef9b..3cecbf169452 100644 --- a/drivers/usb/dwc3/dwc3-haps.c +++ b/drivers/usb/dwc3/dwc3-haps.c @@ -106,6 +106,15 @@ static const struct pci_device_id dwc3_haps_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), + /* + * i.MX6QP and i.MX7D platform use a PCIe controller with the + * same VID and PID as this USB controller. The system may + * incorrectly match this driver to that PCIe controller. To + * workaround this, specifically use class type USB to prevent + * incorrect driver matching. + */ + .class = (PCI_CLASS_SERIAL_USB << 8), + .class_mask = 0xffff00, }, { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 193a9a88222a..cbee5fb9b9fb 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -106,6 +106,10 @@ static int kdwc3_probe(struct platform_device *pdev) goto err_irq; } + /* IRQ processing not required currently for AM65 */ + if (of_device_is_compatible(node, "ti,am654-dwc3")) + goto skip_irq; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "missing irq\n"); @@ -123,6 +127,7 @@ static int kdwc3_probe(struct platform_device *pdev) kdwc3_enable_irqs(kdwc); +skip_irq: error = of_platform_populate(node, NULL, NULL, dev); if (error) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); @@ -152,8 +157,11 @@ static int kdwc3_remove_core(struct device *dev, void *c) static int kdwc3_remove(struct platform_device *pdev) { struct dwc3_keystone *kdwc = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + if (!of_device_is_compatible(node, "ti,am654-dwc3")) + kdwc3_disable_irqs(kdwc); - kdwc3_disable_irqs(kdwc); device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); pm_runtime_put_sync(kdwc->dev); pm_runtime_disable(kdwc->dev); @@ -165,6 +173,7 @@ static int kdwc3_remove(struct platform_device *pdev) static const struct of_device_id kdwc3_of_match[] = { { .compatible = "ti,keystone-dwc3", }, + { .compatible = "ti,am654-dwc3" }, {}, }; MODULE_DEVICE_TABLE(of, kdwc3_of_match); diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index a6d0203e40b6..184df4daa590 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -595,6 +595,7 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { static const struct of_device_id dwc3_qcom_of_match[] = { { .compatible = "qcom,dwc3" }, { .compatible = "qcom,msm8996-dwc3" }, + { .compatible = "qcom,msm8998-dwc3" }, { .compatible = "qcom,sdm845-dwc3" }, { } }; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 07bd31bb2f8a..e293400cc6e9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -174,9 +174,9 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, { struct dwc3 *dwc = dep->dwc; - req->started = false; list_del(&req->list); req->remaining = 0; + req->needs_extra_trb = false; if (req->request.status == -EINPROGRESS) req->request.status = status; @@ -208,6 +208,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3 *dwc = dep->dwc; dwc3_gadget_del_and_unmap_request(dep, req, status); + req->status = DWC3_REQUEST_STATUS_COMPLETED; spin_unlock(&dwc->lock); usb_gadget_giveback_request(&dep->endpoint, &req->request); @@ -383,19 +384,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status); - if (ret == 0) { - switch (DWC3_DEPCMD_CMD(cmd)) { - case DWC3_DEPCMD_STARTTRANSFER: - dep->flags |= DWC3_EP_TRANSFER_STARTED; - dwc3_gadget_ep_get_transfer_index(dep); - break; - case DWC3_DEPCMD_ENDTRANSFER: - dep->flags &= ~DWC3_EP_TRANSFER_STARTED; - break; - default: - /* nothing */ - break; - } + if (ret == 0 && DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { + dep->flags |= DWC3_EP_TRANSFER_STARTED; + dwc3_gadget_ep_get_transfer_index(dep); } if (saved_config) { @@ -641,7 +632,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; - dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg |= DWC3_DALEPENA_EP(dep->number); @@ -697,12 +687,13 @@ out: return 0; } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force); +static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt); static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, false); /* - giveback all requests to gadget driver */ while (!list_empty(&dep->started_list)) { @@ -747,7 +738,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->stream_capable = false; dep->type = 0; - dep->flags &= DWC3_EP_END_TRANSFER_PENDING; + dep->flags = 0; /* Clear out the ep descriptors for non-ep0 */ if (dep->number > 1) { @@ -846,6 +837,7 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep, req->direction = dep->direction; req->epnum = dep->number; req->dep = dep; + req->status = DWC3_REQUEST_STATUS_UNKNOWN; trace_dwc3_alloc_request(req); @@ -1118,7 +1110,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); unsigned int rem = length % maxp; - if (rem && usb_endpoint_dir_out(dep->endpoint.desc)) { + if ((!length || rem) && usb_endpoint_dir_out(dep->endpoint.desc)) { struct dwc3 *dwc = dep->dwc; struct dwc3_trb *trb; @@ -1359,7 +1351,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) * to wait for the next XferNotReady to test the command again */ if (cmd_status == 0) { - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); return 0; } } @@ -1434,6 +1426,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) &req->request, req->dep->name)) return -EINVAL; + if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED, + "%s: request %pK already in flight\n", + dep->name, &req->request)) + return -EINVAL; + pm_runtime_get(dwc->dev); req->request.actual = 0; @@ -1442,6 +1439,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); list_add_tail(&req->list, &dep->pending_list); + req->status = DWC3_REQUEST_STATUS_QUEUED; /* * NOTICE: Isochronous endpoints should NEVER be prestarted. We must @@ -1505,6 +1503,8 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } + + req->num_trbs = 0; } static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep) @@ -1546,13 +1546,16 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, } if (r == req) { /* wait until it is processed */ - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); if (!r->trb) goto out0; dwc3_gadget_move_cancelled_request(req); - goto out0; + if (dep->flags & DWC3_EP_TRANSFER_STARTED) + goto out0; + else + goto out1; } dev_err(dwc->dev, "request %pK was not queued to %s\n", request, ep->name); @@ -1560,6 +1563,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, goto out0; } +out1: dwc3_gadget_giveback(dep, req, -ECONNRESET); out0: @@ -1984,6 +1988,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; + dwc->link_state = DWC3_LINK_STATE_SS_DIS; dwc3_ep0_out_start(dwc); dwc3_gadget_enable_irq(dwc); @@ -2498,7 +2503,7 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); if (stop) { - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); dep->flags = DWC3_EP_ENABLED; } @@ -2545,7 +2550,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep = dwc->eps[epnum]; if (!(dep->flags & DWC3_EP_ENABLED)) { - if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* Handle only EPCMDCMPLT when EP disabled */ @@ -2569,7 +2574,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, cmd = DEPEVT_PARAMETER_CMD(event->parameters); if (cmd == DWC3_DEPCMD_ENDTRANSFER) { - dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; dwc3_gadget_ep_cleanup_cancelled_requests(dep); } break; @@ -2619,15 +2624,15 @@ static void dwc3_reset_gadget(struct dwc3 *dwc) } } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force) +static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt) { struct dwc3 *dwc = dep->dwc; struct dwc3_gadget_ep_cmd_params params; u32 cmd; int ret; - if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || - !dep->resource_index) + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* @@ -2663,17 +2668,15 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force) cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; - cmd |= DWC3_DEPCMD_CMDIOC; + cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) { - dep->flags |= DWC3_EP_END_TRANSFER_PENDING; + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) udelay(100); - } } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) @@ -3337,6 +3340,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed); + return 0; err4: @@ -3379,6 +3384,8 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) dwc3_disconnect_gadget(dwc); __dwc3_gadget_stop(dwc); + synchronize_irq(dwc->irq_gadget); + return 0; } diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 023a473648eb..3ed738e86ea7 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -75,7 +75,7 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->started = true; + req->status = DWC3_REQUEST_STATUS_STARTED; list_move_tail(&req->list, &dep->started_list); } @@ -90,7 +90,7 @@ static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->started = false; + req->status = DWC3_REQUEST_STATUS_CANCELLED; list_move_tail(&req->list, &dep->cancelled_list); } diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index e97a00593dda..818a63da1a44 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -59,8 +59,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event, __entry->ep0state = dwc->ep0state; ), TP_printk("event (%08x): %s", __entry->event, - dwc3_decode_event(__get_str(str), __entry->event, - __entry->ep0state)) + dwc3_decode_event(__get_str(str), DWC3_MSG_MAX, + __entry->event, __entry->ep0state)) ); DEFINE_EVENT(dwc3_log_event, dwc3_event, @@ -86,7 +86,8 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", dwc3_decode_ctrl(__get_str(str), __entry->bRequestType, + TP_printk("%s", dwc3_decode_ctrl(__get_str(str), DWC3_MSG_MAX, + __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) ) @@ -305,7 +306,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ep, __entry->trb_enqueue = dep->trb_enqueue; __entry->trb_dequeue = dep->trb_dequeue; ), - TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c:%c", + TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c", __get_str(name), __entry->maxpacket, __entry->maxpacket_limit, __entry->max_streams, __entry->maxburst, __entry->trb_enqueue, @@ -315,7 +316,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ep, __entry->flags & DWC3_EP_WEDGE ? 'W' : 'w', __entry->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b', __entry->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p', - __entry->flags & DWC3_EP_END_TRANSFER_PENDING ? 'E' : 'e', __entry->direction ? '<' : '>' ) ); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 31cce7805eb2..ec189d7855a0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 71b15c65b90f..1eb4fa2e623f 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -67,9 +67,6 @@ struct usb_ep *usb_ep_autoconfig_ss( ) { struct usb_ep *ep; - u8 type; - - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (gadget->ops->match_ep) { ep = gadget->ops->match_ep(gadget, desc, ep_comp); @@ -109,16 +106,6 @@ found_ep: desc->bEndpointAddress |= gadget->out_epnum; } - /* report (variable) full speed bulk maxpacket */ - if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) { - int size = ep->maxpacket_limit; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - desc->wMaxPacketSize = cpu_to_le16(size); - } - ep->address = desc->bEndpointAddress; ep->desc = NULL; ep->comp_desc = NULL; @@ -152,9 +139,10 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); * * On success, this returns an claimed usb_ep, and modifies the endpoint * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed. To prevent - * the endpoint from being returned by a later autoconfig call, claims it - * by assigning ep->claimed to true. + * is initialized as if the endpoint were used at full speed. Because of + * that the users must consider adjusting the autoconfigured descriptor. + * To prevent the endpoint from being returned by a later autoconfig call, + * claims it by assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -163,7 +151,26 @@ struct usb_ep *usb_ep_autoconfig( struct usb_endpoint_descriptor *desc ) { - return usb_ep_autoconfig_ss(gadget, desc, NULL); + struct usb_ep *ep; + u8 type; + + ep = usb_ep_autoconfig_ss(gadget, desc, NULL); + if (!ep) + return NULL; + + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* report (variable) full speed bulk maxpacket */ + if (type == USB_ENDPOINT_XFER_BULK) { + int size = ep->maxpacket_limit; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + + return ep; } EXPORT_SYMBOL_GPL(usb_ep_autoconfig); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 1e5430438703..20413c276c61 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1082,6 +1082,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * condition with req->complete callback. */ usb_ep_dequeue(ep->ep, req); + wait_for_completion(&done); interrupted = ep->status < 0; } @@ -2843,12 +2844,18 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, struct usb_request *req; struct usb_ep *ep; u8 bEndpointAddress; + u16 wMaxPacketSize; /* * We back up bEndpointAddress because autoconfig overwrites * it with physical endpoint address. */ bEndpointAddress = ds->bEndpointAddress; + /* + * We back up wMaxPacketSize because autoconfig treats + * endpoint descriptors as if they were full speed. + */ + wMaxPacketSize = ds->wMaxPacketSize; pr_vdebug("autoconfig\n"); ep = usb_ep_autoconfig(func->gadget, ds); if (unlikely(!ep)) @@ -2869,6 +2876,11 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, */ if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) ds->bEndpointAddress = bEndpointAddress; + /* + * Restore wMaxPacketSize which was potentially + * overwritten by autoconfig. + */ + ds->wMaxPacketSize = wMaxPacketSize; } ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 9cdef108fb1b..ed68a4860b7d 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -838,7 +838,7 @@ static struct usb_function *source_sink_alloc_func( ss = kzalloc(sizeof(*ss), GFP_KERNEL); if (!ss) - return NULL; + return ERR_PTR(-ENOMEM); ss_opts = container_of(fi, struct f_ss_opts, func_inst); diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 2746a926a8d9..00d346965f7a 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -459,10 +459,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } else if (intf == uac1->as_in_intf) { uac1->as_in_alt = alt; - if (alt) - ret = u_audio_start_playback(&uac1->g_audio); - else - u_audio_stop_playback(&uac1->g_audio); + if (alt) + ret = u_audio_start_playback(&uac1->g_audio); + else + u_audio_stop_playback(&uac1->g_audio); } else { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return -EINVAL; @@ -568,6 +568,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; as_out_interface_alt_0_desc.bInterfaceNumber = status; as_out_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[0] = status; uac1->as_out_intf = status; uac1->as_out_alt = 0; @@ -576,6 +577,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; as_in_interface_alt_0_desc.bInterfaceNumber = status; as_in_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[1] = status; uac1->as_in_intf = status; uac1->as_in_alt = 0; diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h index 050aa672ee7f..098ece573a5e 100644 --- a/drivers/usb/gadget/function/u_ecm.h +++ b/drivers/usb/gadget/function/u_ecm.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_ECM_H diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/function/u_eem.h index de3828d3e8f0..921386a375cf 100644 --- a/drivers/usb/gadget/function/u_eem.h +++ b/drivers/usb/gadget/function/u_eem.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_EEM_H diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index cd33cee4d78b..d8b92485b727 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_ETHER_CONFIGFS_H diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index c3aba4dfa958..f9b0cf67360d 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_FFS_H diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/function/u_gether.h index 5b7e2eb90336..ce4f07626f96 100644 --- a/drivers/usb/gadget/function/u_gether.h +++ b/drivers/usb/gadget/function/u_gether.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_GETHER_H diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 2f5ca4bfa7ff..1594bfa312eb 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_HID_H diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index 5599aa5fc977..29bf006c0a13 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_MIDI_H diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 67324f983343..d483e45c0f77 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_NCM_H diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index 6088ff744194..78797764f478 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -7,7 +7,7 @@ * Copyright (c) 2015 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_PRINTER_H diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index d65fb4ebac3c..1e148b76f339 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_RNDIS_H diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 29436f75bbe0..65f634ec7fc2 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/interrupt.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/tty.h> @@ -26,6 +25,7 @@ #include <linux/module.h> #include <linux/console.h> #include <linux/kthread.h> +#include <linux/workqueue.h> #include <linux/kfifo.h> #include "u_serial.h" @@ -110,7 +110,7 @@ struct gs_port { int read_allocated; struct list_head read_queue; unsigned n_read; - struct tasklet_struct push; + struct delayed_work push; struct list_head write_pool; int write_started; @@ -352,9 +352,10 @@ __acquires(&port->port_lock) * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ -static void gs_rx_push(unsigned long _port) +static void gs_rx_push(struct work_struct *work) { - struct gs_port *port = (void *)_port; + struct delayed_work *w = to_delayed_work(work); + struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; @@ -429,21 +430,13 @@ static void gs_rx_push(unsigned long _port) /* We want our data queue to become empty ASAP, keeping data * in the tty and ldisc (not here). If we couldn't push any - * this time around, there may be trouble unless there's an - * implicit tty_unthrottle() call on its way... + * this time around, RX may be starved, so wait until next jiffy. * - * REVISIT we should probably add a timer to keep the tasklet - * from starving ... but it's not clear that case ever happens. + * We may leave non-empty queue only when there is a tty, and + * either it is throttled or there is no more room in flip buffer. */ - if (!list_empty(queue) && tty) { - if (!tty_throttled(tty)) { - if (do_push) - tasklet_schedule(&port->push); - else - pr_warn("ttyGS%d: RX not scheduled?\n", - port->port_num); - } - } + if (!list_empty(queue) && !tty_throttled(tty)) + schedule_delayed_work(&port->push, 1); /* If we're still connected, refill the USB RX queue. */ if (!disconnect && port->port_usb) @@ -459,7 +452,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) /* Queue all received data until the tty layer is ready for it. */ spin_lock(&port->port_lock); list_add_tail(&req->list, &port->read_queue); - tasklet_schedule(&port->push); + schedule_delayed_work(&port->push, 0); spin_unlock(&port->port_lock); } @@ -854,8 +847,8 @@ static void gs_unthrottle(struct tty_struct *tty) * rts/cts, or other handshaking with the host, but if the * read queue backs up enough we'll be NAKing OUT packets. */ - tasklet_schedule(&port->push); pr_vdebug("ttyGS%d: unthrottle\n", port->port_num); + schedule_delayed_work(&port->push, 0); } spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1159,7 +1152,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) init_waitqueue_head(&port->drain_wait); init_waitqueue_head(&port->close_wait); - tasklet_init(&port->push, gs_rx_push, (unsigned long) port); + INIT_DELAYED_WORK(&port->push, gs_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); @@ -1186,7 +1179,7 @@ static int gs_closed(struct gs_port *port) static void gserial_free_port(struct gs_port *port) { - tasklet_kill(&port->push); + cancel_delayed_work_sync(&port->push); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 8362ee572e1e..82048791eb6e 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_UAC2_H diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 5242d489e20a..16da49a2fcf2 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -7,7 +7,7 @@ * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_UVC_H diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 099d650082e5..1473d25ff17a 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -56,6 +56,8 @@ extern unsigned int uvc_gadget_trace_param; dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) #define uvcg_info(f, fmt, args...) \ dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) +#define uvcg_warn(f, fmt, args...) \ + dev_warn(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) #define uvcg_err(f, fmt, args...) \ dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index bc1e2af566c3..00fb58e50a15 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #include <linux/sort.h> @@ -1570,10 +1570,6 @@ uvcg_uncompressed_##cname##_store(struct config_item *item, \ if (ret) \ goto end; \ \ - if (num > 255) { \ - ret = -EINVAL; \ - goto end; \ - } \ u->desc.aname = num; \ ret = len; \ end: \ @@ -1767,10 +1763,6 @@ uvcg_mjpeg_##cname##_store(struct config_item *item, \ if (ret) \ goto end; \ \ - if (num > 255) { \ - ret = -EINVAL; \ - goto end; \ - } \ u->desc.aname = num; \ ret = len; \ end: \ diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h index 8549c0b27b9d..341391dbc81f 100644 --- a/drivers/usb/gadget/function/uvc_configfs.h +++ b/drivers/usb/gadget/function/uvc_configfs.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef UVC_CONFIGFS_H #define UVC_CONFIGFS_H diff --git a/drivers/usb/gadget/function/uvc_v4l2.h b/drivers/usb/gadget/function/uvc_v4l2.h index a75e9c397446..452d71059b3f 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.h +++ b/drivers/usb/gadget/function/uvc_v4l2.h @@ -7,7 +7,7 @@ * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __UVC_V4L2_H__ diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 278dc52c7604..dff12103f696 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -7,7 +7,7 @@ * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __UVC_VIDEO_H__ #define __UVC_VIDEO_H__ diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 784bf86dad4f..d7c9e4fca895 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 37ca0e669bd8..249277d0e53f 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -1218,27 +1218,27 @@ ep0_poll (struct file *fd, poll_table *wait) if (dev->state <= STATE_DEV_OPENED) return DEFAULT_POLLMASK; - poll_wait(fd, &dev->wait, wait); - - spin_lock_irq (&dev->lock); - - /* report fd mode change before acting on it */ - if (dev->setup_abort) { - dev->setup_abort = 0; - mask = EPOLLHUP; - goto out; - } - - if (dev->state == STATE_DEV_SETUP) { - if (dev->setup_in || dev->setup_can_stall) - mask = EPOLLOUT; - } else { - if (dev->ev_next != 0) - mask = EPOLLIN; - } + poll_wait(fd, &dev->wait, wait); + + spin_lock_irq(&dev->lock); + + /* report fd mode change before acting on it */ + if (dev->setup_abort) { + dev->setup_abort = 0; + mask = EPOLLHUP; + goto out; + } + + if (dev->state == STATE_DEV_SETUP) { + if (dev->setup_in || dev->setup_can_stall) + mask = EPOLLOUT; + } else { + if (dev->ev_next != 0) + mask = EPOLLIN; + } out: - spin_unlock_irq(&dev->lock); - return mask; + spin_unlock_irq(&dev->lock); + return mask; } static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index dbaa46eee853..6aea1ecb3999 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -5,7 +5,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #include "u_f.h" diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 09f90447fed5..eaa13fd3dc7f 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_F_H__ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h index 8acd21779ac8..5d7d35c8cc31 100644 --- a/drivers/usb/gadget/u_os_desc.h +++ b/drivers/usb/gadget/u_os_desc.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_OS_DESC_H__ diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 0a16cbd4e528..ef0259a950ba 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 4a28e3fbeb0b..83340f4fdc6e 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -120,7 +120,7 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep) /* No current DMA ongoing */ req->active = false; - /* Grab lenght out of HW */ + /* Grab length out of HW */ len = VHUB_EP_DMA_TX_SIZE(stat); /* If not using DMA, copy data out if needed */ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 35ba0e55a2e9..7c040f56100e 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -295,7 +295,7 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, dsize = AST_VHUB_HUB_DESC_SIZE; memcpy(ep->buf, &ast_vhub_hub_desc, dsize); BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc)); - BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); + BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; default: return std_req_stall; diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig index c74ac25dddcd..3e88c7670b2e 100644 --- a/drivers/usb/gadget/udc/bdc/Kconfig +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_BDC_UDC tristate "Broadcom USB3.0 device controller IP driver(BDC)" depends on USB_GADGET && HAS_DMA diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c index 6305bf2c8b59..44c2a5eef785 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.c +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -311,8 +311,8 @@ int bdc_ep_clear_stall(struct bdc *bdc, int epnum) /* if the endpoint it not stallled */ if (!(ep->flags & BDC_EP_STALL)) { ret = bdc_ep_set_stall(bdc, epnum); - if (ret) - return ret; + if (ret) + return ret; } } /* Preserve the seq number for ep0 only */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 01b44e159623..ccbd1d34eb2a 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -172,8 +172,9 @@ static int scratchpad_setup(struct bdc *bdc) /* Refer to BDC spec, Table 4 for description of SPB */ sp_buff_size = 1 << (sp_buff_size + 5); dev_dbg(bdc->dev, "Allocating %d bytes for scratchpad\n", sp_buff_size); - bdc->scratchpad.buff = dma_zalloc_coherent(bdc->dev, sp_buff_size, - &bdc->scratchpad.sp_dma, GFP_KERNEL); + bdc->scratchpad.buff = dma_alloc_coherent(bdc->dev, sp_buff_size, + &bdc->scratchpad.sp_dma, + GFP_KERNEL); if (!bdc->scratchpad.buff) goto fail; @@ -202,11 +203,9 @@ static int setup_srr(struct bdc *bdc, int interrupter) bdc_writel(bdc->regs, BDC_SRRINT(0), BDC_SRR_RWS | BDC_SRR_RST); bdc->srr.dqp_index = 0; /* allocate the status report descriptors */ - bdc->srr.sr_bds = dma_zalloc_coherent( - bdc->dev, - NUM_SR_ENTRIES * sizeof(struct bdc_bd), - &bdc->srr.dma_addr, - GFP_KERNEL); + bdc->srr.sr_bds = dma_alloc_coherent(bdc->dev, + NUM_SR_ENTRIES * sizeof(struct bdc_bd), + &bdc->srr.dma_addr, GFP_KERNEL); if (!bdc->srr.sr_bds) return -ENOMEM; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 87d6b12779f2..7cf34beb50df 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -281,10 +281,10 @@ EXPORT_SYMBOL_GPL(usb_ep_queue); * @ep:the endpoint associated with the request * @req:the request being canceled * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. + * If the request is still active on the endpoint, it is dequeued and + * eventually its completion routine is called (with status -ECONNRESET); + * else a negative error code is returned. This routine is asynchronous, + * that is, it may return before the completion routine runs. * * Note that some hardware can't clear out write fifos (to unlink the request * at the head of the queue) except as part of disconnecting from usb. Such diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index bc6abaea907d..cec49294bac6 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -326,6 +326,7 @@ dma_reset: static void fotg210_start_dma(struct fotg210_ep *ep, struct fotg210_request *req) { + struct device *dev = &ep->fotg210->gadget.dev; dma_addr_t d; u8 *buffer; u32 length; @@ -348,18 +349,14 @@ static void fotg210_start_dma(struct fotg210_ep *ep, length = req->req.length; } - d = dma_map_single(NULL, buffer, length, + d = dma_map_single(dev, buffer, length, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(NULL, d)) { + if (dma_mapping_error(dev, d)) { pr_err("dma_mapping_error\n"); return; } - dma_sync_single_for_device(NULL, d, length, - ep->dir_in ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - fotg210_enable_dma(ep, d, length); /* check if dma is done */ @@ -370,7 +367,7 @@ static void fotg210_start_dma(struct fotg210_ep *ep, /* update actual transfer length */ req->req.actual += length; - dma_unmap_single(NULL, d, length, DMA_TO_DEVICE); + dma_unmap_single(dev, d, length, DMA_TO_DEVICE); } static void fotg210_ep0_queue(struct fotg210_ep *ep, diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 660878a19505..b77f3126580e 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -2083,7 +2083,7 @@ static irqreturn_t net2272_irq(int irq, void *_dev) #if defined(PLX_PCI_RDK2) /* see if PCI int for us by checking irqstat */ intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT); - if (!intcsr & (1 << NET2272_PCI_IRQ)) { + if (!(intcsr & (1 << NET2272_PCI_IRQ))) { spin_unlock(&dev->lock); return IRQ_NONE; } diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index e7dae5379e04..f63f82450bf4 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -516,8 +516,8 @@ static int net2280_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) { - pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); + if (!_ep || _ep->name == ep0name) { + pr_err("%s: Invalid ep=%p\n", __func__, _ep); return -EINVAL; } spin_lock_irqsave(&ep->dev->lock, flags); @@ -2279,7 +2279,7 @@ static void usb_reinit_338x(struct net2280 *dev) * - It is safe to set for all connection speeds; all chip revisions. * - R-M-W to leave other bits undisturbed. * - Reference PLX TT-7372 - */ + */ val = readl(&dev->ll_chicken_reg->ll_tsn_chicken_bit); val |= BIT(RECOVERY_IDLE_TO_RECOVER_FMW); writel(val, &dev->ll_chicken_reg->ll_tsn_chicken_bit); diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 6e34f9594159..7dc248546fd4 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2630,6 +2630,10 @@ MODULE_DEVICE_TABLE(of, usb3_of_match); static const struct soc_device_attribute renesas_usb3_quirks_match[] = { { + .soc_id = "r8a774c0", + .data = &renesas_usb3_priv_r8a77990, + }, + { .soc_id = "r8a7795", .revision = "ES1.*", .data = &renesas_usb3_priv_r8a7795_es1, }, diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index d4da47f4f6f4..3fcded31405a 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -947,15 +947,14 @@ static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) UDC_DMA_STP_STS_BS_HOST_READY, UDC_DMA_STP_STS_BS); - - /* clear NAK by writing CNAK */ - if (ep->naking) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 16758b12a5e9..d809671c5fea 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Host Controller Drivers # @@ -69,13 +70,13 @@ config USB_XHCI_MTK If unsure, say N. config USB_XHCI_MVEBU - tristate "xHCI support for Marvell Armada 375/38x" + tristate "xHCI support for Marvell Armada 375/38x/37xx" select USB_XHCI_PLATFORM depends on HAS_IOMEM depends on ARCH_MVEBU || COMPILE_TEST ---help--- Say 'Y' to enable the support for the xHCI host controller - found in Marvell Armada 375/38x ARM SOCs. + found in Marvell Armada 375/38x/37xx ARM SOCs. config USB_XHCI_RCAR tristate "xHCI support for Renesas R-Car SoCs" @@ -179,8 +180,7 @@ config XPS_USB_HCD_XILINX devices only. config USB_EHCI_FSL - tristate "Support for Freescale PPC on-chip EHCI USB controller" - depends on FSL_SOC + tristate "Support for Freescale on-chip EHCI USB controller" select USB_EHCI_ROOT_HUB_TT ---help--- Variation of ARC USB block used in some Freescale chips. diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 0a9fd2022acf..e3d0c1c25160 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -23,6 +23,7 @@ #include <linux/platform_device.h> #include <linux/fsl_devices.h> #include <linux/of_platform.h> +#include <linux/io.h> #include "ehci.h" #include "ehci-fsl.h" @@ -50,6 +51,7 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) struct resource *res; int irq; int retval; + u32 tmp; pr_debug("initializing FSL-SOC USB Controller\n"); @@ -114,17 +116,22 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) } /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, 0x4); - + if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) { + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= 0x4; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + } /* * Enable UTMI phy and program PTS field in UTMI mode before asserting * controller reset for USB Controller version 2.5 */ if (pdata->has_fsl_erratum_a007792) { - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); } @@ -174,7 +181,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; + u32 portsc, tmp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; @@ -192,11 +199,16 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + /* turn off UTMI PHY first */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~(CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + + /* then turn on ULPI and enable USB controller */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); } portsc |= PORT_PTS_ULPI; break; @@ -210,16 +222,21 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ - if (pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - CTRL_UTMI_PHY_EN); + if (pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: @@ -241,9 +258,12 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); - if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); + if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } return 0; } @@ -284,14 +304,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) return -EINVAL; if (pdata->operating_mode == FSL_USB2_MPH_HOST) { - unsigned int chip, rev, svr; - - svr = mfspr(SPRN_SVR); - chip = svr >> 16; - rev = (svr >> 4) & 0xf; /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ - if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) + if (pdata->has_fsl_erratum_14 == 1) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f26109eafdbf..66ec1fdf9fe7 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -302,3 +302,4 @@ MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>"); MODULE_ALIAS("mv-ehci"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, ehci_mv_dt_ids); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 1ad72647a069..790acf3633e8 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -182,6 +182,23 @@ static int ehci_orion_drv_reset(struct usb_hcd *hcd) return ret; } +static int __maybe_unused ehci_orion_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return ehci_suspend(hcd, device_may_wakeup(dev)); +} + +static int __maybe_unused ehci_orion_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return ehci_resume(hcd, false); +} + +static SIMPLE_DEV_PM_OPS(ehci_orion_pm_ops, ehci_orion_drv_suspend, + ehci_orion_drv_resume); + static const struct ehci_driver_overrides orion_overrides __initconst = { .extra_priv_size = sizeof(struct orion_ehci_hcd), .reset = ehci_orion_drv_reset, @@ -257,15 +274,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) if (IS_ERR(priv->phy)) { err = PTR_ERR(priv->phy); if (err != -ENOSYS) - goto err_phy_get; - } else { - err = phy_init(priv->phy); - if (err) - goto err_phy_init; - - err = phy_power_on(priv->phy); - if (err) - goto err_phy_power_on; + goto err_dis_clk; } /* @@ -297,19 +306,12 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_add_hcd; + goto err_dis_clk; device_wakeup_enable(hcd->self.controller); return 0; -err_add_hcd: - if (!IS_ERR(priv->phy)) - phy_power_off(priv->phy); -err_phy_power_on: - if (!IS_ERR(priv->phy)) - phy_exit(priv->phy); -err_phy_init: -err_phy_get: +err_dis_clk: if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); usb_put_hcd(hcd); @@ -327,11 +329,6 @@ static int ehci_orion_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); - if (!IS_ERR(priv->phy)) { - phy_power_off(priv->phy); - phy_exit(priv->phy); - } - if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); @@ -354,6 +351,7 @@ static struct platform_driver ehci_orion_driver = { .driver = { .name = "orion-ehci", .of_match_table = ehci_orion_dt_ids, + .pm = &ehci_orion_pm_ops, }, }; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 677f9d592109..4f8b8a08c914 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -225,6 +225,12 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->has_fsl_erratum_a005697 = of_property_read_bool(np, "fsl,usb_erratum-a005697"); + if (of_get_property(np, "fsl,usb_erratum_14", NULL)) + pdata->has_fsl_erratum_14 = 1; + else + pdata->has_fsl_erratum_14 = 0; + + /* * Determine whether phy_clk_valid needs to be checked * by reading property in device tree diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index ec6739ef3129..fc35a7993b7b 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -141,8 +141,11 @@ static struct regmap *at91_dt_syscon_sfr(void) struct regmap *regmap; regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap)) - regmap = NULL; + if (IS_ERR(regmap)) { + regmap = syscon_regmap_lookup_by_compatible("microchip,sam9x60-sfr"); + if (IS_ERR(regmap)) + regmap = NULL; + } return regmap; } diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index a55cbba40a5a..ca8a94f15ac0 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -9,6 +9,7 @@ */ #include <linux/clk.h> +#include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/jiffies.h> @@ -40,6 +41,8 @@ struct da8xx_ohci_hcd { struct regulator *vbus_reg; struct notifier_block nb; unsigned int reg_enabled; + struct gpio_desc *vbus_gpio; + struct gpio_desc *oc_gpio; }; #define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv) @@ -86,12 +89,13 @@ static void ohci_da8xx_disable(struct usb_hcd *hcd) static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); + struct device *dev = hcd->self.controller; int ret; - if (hub && hub->set_power) - return hub->set_power(1, on); + if (da8xx_ohci->vbus_gpio) { + gpiod_set_value_cansleep(da8xx_ohci->vbus_gpio, on); + return 0; + } if (!da8xx_ohci->vbus_reg) return 0; @@ -119,11 +123,9 @@ static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) static int ohci_da8xx_get_power(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - if (hub && hub->get_power) - return hub->get_power(1); + if (da8xx_ohci->vbus_gpio) + return gpiod_get_value_cansleep(da8xx_ohci->vbus_gpio); if (da8xx_ohci->vbus_reg) return regulator_is_enabled(da8xx_ohci->vbus_reg); @@ -134,13 +136,11 @@ static int ohci_da8xx_get_power(struct usb_hcd *hcd) static int ohci_da8xx_get_oci(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); unsigned int flags; int ret; - if (hub && hub->get_oci) - return hub->get_oci(1); + if (da8xx_ohci->oc_gpio) + return gpiod_get_value_cansleep(da8xx_ohci->oc_gpio); if (!da8xx_ohci->vbus_reg) return 0; @@ -158,10 +158,8 @@ static int ohci_da8xx_get_oci(struct usb_hcd *hcd) static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - if (hub && hub->set_power) + if (da8xx_ohci->vbus_gpio) return 1; if (da8xx_ohci->vbus_reg) @@ -173,10 +171,8 @@ static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) static int ohci_da8xx_has_oci(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - if (hub && hub->get_oci) + if (da8xx_ohci->oc_gpio) return 1; if (da8xx_ohci->vbus_reg) @@ -196,19 +192,6 @@ static int ohci_da8xx_has_potpgt(struct usb_hcd *hcd) return 0; } -/* - * Handle the port over-current indicator change. - */ -static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub, - unsigned port) -{ - ocic_mask |= 1 << port; - - /* Once over-current is detected, the port needs to be powered down */ - if (hub->get_oci(port) > 0) - hub->set_power(port, 0); -} - static int ohci_da8xx_regulator_event(struct notifier_block *nb, unsigned long event, void *data) { @@ -223,16 +206,23 @@ static int ohci_da8xx_regulator_event(struct notifier_block *nb, return 0; } +static irqreturn_t ohci_da8xx_oc_handler(int irq, void *data) +{ + struct da8xx_ohci_hcd *da8xx_ohci = data; + + if (gpiod_get_value(da8xx_ohci->oc_gpio)) + gpiod_set_value(da8xx_ohci->vbus_gpio, 0); + + return IRQ_HANDLED; +} + static int ohci_da8xx_register_notify(struct usb_hcd *hcd) { struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); int ret = 0; - if (hub && hub->ocic_notify) { - ret = hub->ocic_notify(ohci_da8xx_ocic_handler); - } else if (da8xx_ohci->vbus_reg) { + if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) { da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event; ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg, &da8xx_ohci->nb); @@ -244,15 +234,6 @@ static int ohci_da8xx_register_notify(struct usb_hcd *hcd) return ret; } -static void ohci_da8xx_unregister_notify(struct usb_hcd *hcd) -{ - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); - - if (hub && hub->ocic_notify) - hub->ocic_notify(NULL); -} - static int ohci_da8xx_reset(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; @@ -402,34 +383,35 @@ MODULE_DEVICE_TABLE(of, da8xx_ohci_ids); static int ohci_da8xx_probe(struct platform_device *pdev) { struct da8xx_ohci_hcd *da8xx_ohci; + struct device *dev = &pdev->dev; + int error, hcd_irq, oc_irq; struct usb_hcd *hcd; struct resource *mem; - int error, irq; - hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); + + hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev)); if (!hcd) return -ENOMEM; da8xx_ohci = to_da8xx_ohci(hcd); da8xx_ohci->hcd = hcd; - da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, NULL); + da8xx_ohci->usb11_clk = devm_clk_get(dev, NULL); if (IS_ERR(da8xx_ohci->usb11_clk)) { error = PTR_ERR(da8xx_ohci->usb11_clk); if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get clock.\n"); + dev_err(dev, "Failed to get clock.\n"); goto err; } - da8xx_ohci->usb11_phy = devm_phy_get(&pdev->dev, "usb-phy"); + da8xx_ohci->usb11_phy = devm_phy_get(dev, "usb-phy"); if (IS_ERR(da8xx_ohci->usb11_phy)) { error = PTR_ERR(da8xx_ohci->usb11_phy); if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get phy.\n"); + dev_err(dev, "Failed to get phy.\n"); goto err; } - da8xx_ohci->vbus_reg = devm_regulator_get_optional(&pdev->dev, "vbus"); + da8xx_ohci->vbus_reg = devm_regulator_get_optional(dev, "vbus"); if (IS_ERR(da8xx_ohci->vbus_reg)) { error = PTR_ERR(da8xx_ohci->vbus_reg); if (error == -ENODEV) { @@ -437,13 +419,34 @@ static int ohci_da8xx_probe(struct platform_device *pdev) } else if (error == -EPROBE_DEFER) { goto err; } else { - dev_err(&pdev->dev, "Failed to get regulator\n"); + dev_err(dev, "Failed to get regulator\n"); goto err; } } + da8xx_ohci->vbus_gpio = devm_gpiod_get_optional(dev, "vbus", + GPIOD_OUT_HIGH); + if (IS_ERR(da8xx_ohci->vbus_gpio)) + goto err; + + da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN); + if (IS_ERR(da8xx_ohci->oc_gpio)) + goto err; + + if (da8xx_ohci->oc_gpio) { + oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio); + if (oc_irq < 0) + goto err; + + error = devm_request_irq(dev, oc_irq, ohci_da8xx_oc_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "OHCI over-current indicator", da8xx_ohci); + if (error) + goto err; + } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, mem); + hcd->regs = devm_ioremap_resource(dev, mem); if (IS_ERR(hcd->regs)) { error = PTR_ERR(hcd->regs); goto err; @@ -451,13 +454,13 @@ static int ohci_da8xx_probe(struct platform_device *pdev) hcd->rsrc_start = mem->start; hcd->rsrc_len = resource_size(mem); - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + hcd_irq = platform_get_irq(pdev, 0); + if (hcd_irq < 0) { error = -ENODEV; goto err; } - error = usb_add_hcd(hcd, irq, 0); + error = usb_add_hcd(hcd, hcd_irq, 0); if (error) goto err; @@ -480,7 +483,6 @@ static int ohci_da8xx_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - ohci_da8xx_unregister_notify(hcd); usb_remove_hcd(hcd); usb_put_hcd(hcd); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index c5e6e8d0b5ef..47c5515a9ce4 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -1323,7 +1323,7 @@ static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu, } /* by default, enable interrupt on urb completion */ - qtd->hw_token |= cpu_to_le32(QTD_IOC); + qtd->hw_token |= cpu_to_le32(QTD_IOC); return head; cleanup: @@ -2253,16 +2253,12 @@ static void scan_periodic(struct oxu_hcd *oxu) for (;;) { union ehci_shadow q, *q_p; __le32 type, *hw_p; - unsigned uframes; /* don't scan past the live uframe */ frame = now_uframe >> 3; - if (frame == (clock >> 3)) - uframes = now_uframe & 0x07; - else { + if (frame != (clock >> 3)) { /* safe to scan the whole frame at once */ now_uframe |= 0x07; - uframes = 8; } restart: @@ -2832,7 +2828,6 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, { struct oxu_hcd *oxu = hcd_to_oxu(hcd); int num, rem; - int transfer_buffer_length; void *transfer_buffer; struct urb *murb; int i, ret; @@ -2843,7 +2838,6 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* Otherwise we should verify the USB transfer buffer size! */ transfer_buffer = urb->transfer_buffer; - transfer_buffer_length = urb->transfer_buffer_length; num = urb->transfer_buffer_length / 4096; rem = urb->transfer_buffer_length % 4096; diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5b8a3d9530c4..934584f0a20a 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2477,7 +2477,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } urb->error_count = 0; + } + urb->error_count = 0; usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { @@ -2982,7 +2983,8 @@ static int u132_remove(struct platform_device *pdev) while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; u132_ring_cancel_work(u132, ring); - } while (endps-- > 0) { + } + while (endps-- > 0) { struct u132_endp *endp = u132->endp[endps]; if (endp) u132_endp_cancel_work(u132, endp); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6218bfe54f52..98deb5f64268 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -596,9 +596,9 @@ static int uhci_start(struct usb_hcd *hcd) &uhci_debug_operations); #endif - uhci->frame = dma_zalloc_coherent(uhci_dev(uhci), - UHCI_NUMFRAMES * sizeof(*uhci->frame), - &uhci->frame_dma_handle, GFP_KERNEL); + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + &uhci->frame_dma_handle, GFP_KERNEL); if (!uhci->frame) { dev_err(uhci_dev(uhci), "unable to allocate consistent memory for frame list\n"); diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Makefile index 26df0138079e..859d20079df6 100644 --- a/drivers/usb/host/whci/Kbuild +++ b/drivers/usb/host/whci/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o whci-hcd-y := \ diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 86cff5c28eff..c78be578abb0 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -181,7 +181,7 @@ static void xhci_dbc_flush_endpoint_requests(struct dbc_ep *dep) xhci_dbc_flush_single_request(req); } -static void xhci_dbc_flush_reqests(struct xhci_dbc *dbc) +static void xhci_dbc_flush_requests(struct xhci_dbc *dbc) { xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_OUT]); xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_IN]); @@ -687,7 +687,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) !(portsc & DBC_PORTSC_CONN_STATUS)) { xhci_info(xhci, "DbC cable unplugged\n"); dbc->state = DS_ENABLED; - xhci_dbc_flush_reqests(dbc); + xhci_dbc_flush_requests(dbc); return EVT_DISC; } @@ -697,7 +697,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) xhci_info(xhci, "DbC port reset\n"); writel(portsc, &dbc->regs->portsc); dbc->state = DS_ENABLED; - xhci_dbc_flush_reqests(dbc); + xhci_dbc_flush_requests(dbc); return EVT_DISC; } diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h index ac5bc40f5c3a..f7a4e2492b00 100644 --- a/drivers/usb/host/xhci-debugfs.h +++ b/drivers/usb/host/xhci-debugfs.h @@ -80,7 +80,6 @@ struct xhci_regset { char name[DEBUGFS_NAMELEN]; struct debugfs_regset32 regset; size_t nregs; - struct dentry *parent; struct list_head list; }; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 36a3eb8849f1..cf5e17962179 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -933,7 +933,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) * that tt_info, then free the child first. Recursive. * We can't rely on udev at this point to find child-parent relationships. */ -void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) +static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) { struct xhci_virt_device *vdev; struct list_head *tt_list_head; @@ -1672,8 +1672,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma); for (i = 0; i < num_sp; i++) { dma_addr_t dma; - void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma, - flags); + void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma, + flags); if (!buf) goto fail_sp4; @@ -1799,8 +1799,8 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_erst_entry *entry; size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; - erst->entries = dma_zalloc_coherent(xhci_to_hcd(xhci)->self.sysdev, - size, &erst->erst_dma_addr, flags); + erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, + size, &erst->erst_dma_addr, flags); if (!erst->entries) return -ENOMEM; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 32e158568788..60651a50770f 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -13,6 +13,7 @@ #include <linux/usb/hcd.h> #include "xhci-mvebu.h" +#include "xhci.h" #define USB3_MAX_WINDOWS 4 #define USB3_WIN_CTRL(w) (0x0 + ((w) * 8)) @@ -72,3 +73,13 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) return 0; } + +int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + /* Without reset on resume, the HC won't work at all */ + xhci->quirks |= XHCI_RESET_ON_RESUME; + + return 0; +} diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h index 09791df2cec0..ca0a3a5721dd 100644 --- a/drivers/usb/host/xhci-mvebu.h +++ b/drivers/usb/host/xhci-mvebu.h @@ -12,10 +12,16 @@ struct usb_hcd; #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); +int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); #else static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) { return 0; } + +static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +{ + return 0; +} #endif #endif /* __LINUX_XHCI_MVEBU_H */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a9ec7051f286..c2fe218e051f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -194,6 +194,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SSIC_PORT_UNUSED; if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; if (pdev->vendor == PCI_VENDOR_ID_INTEL && diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ef09cb06212f..0ac4ec975547 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -98,6 +98,10 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = { .init_quirk = xhci_mvebu_mbus_init_quirk, }; +static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { + .init_quirk = xhci_mvebu_a3700_init_quirk, +}; + static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1, .init_quirk = xhci_rcar_init_quirk, @@ -124,6 +128,9 @@ static const struct of_device_id usb_xhci_of_match[] = { .compatible = "marvell,armada-380-xhci", .data = &xhci_plat_marvell_armada, }, { + .compatible = "marvell,armada3700-xhci", + .data = &xhci_plat_marvell_armada3700, + }, { .compatible = "renesas,xhci-r8a7790", .data = &xhci_plat_renesas_rcar_gen2, }, { diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 938ff06c0349..efb0cad8710e 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -941,9 +941,9 @@ static void tegra_xusb_powerdomain_remove(struct device *dev, device_link_del(tegra->genpd_dl_ss); if (tegra->genpd_dl_host) device_link_del(tegra->genpd_dl_host); - if (tegra->genpd_dev_ss) + if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss)) dev_pm_domain_detach(tegra->genpd_dev_ss, true); - if (tegra->genpd_dev_host) + if (!IS_ERR_OR_NULL(tegra->genpd_dev_host)) dev_pm_domain_detach(tegra->genpd_dev_host, true); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 005e65922608..7fa58c99f126 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1455,8 +1455,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag else num_tds = 1; - urb_priv = kzalloc(sizeof(struct urb_priv) + - num_tds * sizeof(struct xhci_td), mem_flags); + urb_priv = kzalloc(struct_size(urb_priv, td, num_tds), mem_flags); if (!urb_priv) return -ENOMEM; diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig index 320d368c8dac..26c75f309da9 100644 --- a/drivers/usb/image/Kconfig +++ b/drivers/usb/image/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Imaging devices configuration # diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig index c94b7d953399..b1022cc490a2 100644 --- a/drivers/usb/isp1760/Kconfig +++ b/drivers/usb/isp1760/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_ISP1760 tristate "NXP ISP 1760/1761 support" depends on USB || USB_GADGET diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 68d2f2cd17dd..be04c117fe80 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Miscellaneous driver configuration # diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 76c718ac8c78..257efacf3551 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -915,7 +915,6 @@ static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) int bytes_read = 0; int retry_on_empty = 1; int retry_on_timeout = 3; - int empty_packets = 0; read:{ int packet_bytes = 0; int retval = usb_bulk_msg(ftdi->udev, @@ -960,31 +959,6 @@ read:{ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", retval, packet_bytes, bytes_read, diag); return retval; - } else if (packet_bytes == 2) { - unsigned char s0 = ftdi->bulk_in_buffer[0]; - unsigned char s1 = ftdi->bulk_in_buffer[1]; - empty_packets += 1; - if (s0 == 0x31 && s1 == 0x60) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else if (s0 == 0x31 && s1 == 0x00) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } else if (packet_bytes == 1) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; } else { if (retry_on_empty-- > 0) { goto more; diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 36bc28c884ad..9b632ab24f03 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config USB_SISUSBVGA tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile index 6ed3a638261a..6551bce68ac5 100644 --- a/drivers/usb/misc/sisusbvga/Makefile +++ b/drivers/usb/misc/sisusbvga/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o -sisusbvga-y := sisusb.o sisusb_init.o sisusb_con.o +sisusbvga-y := sisusb.o +sisusbvga-$(CONFIG_USB_SISUSBVGA_CON) += sisusb_con.o sisusb_init.o diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 3198d0477cf8..9560fde621ee 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -53,7 +53,7 @@ #include "sisusb.h" #include "sisusb_init.h" -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON #include <linux/font.h> #endif @@ -61,7 +61,7 @@ /* Forward declarations / clean-up routines */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON static int sisusb_first_vc; static int sisusb_last_vc; module_param_named(first, sisusb_first_vc, int, 0); @@ -1198,7 +1198,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, /* High level: Gfx (indexed) register access */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); @@ -1272,7 +1272,7 @@ int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, /* Write/read video ram */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data); @@ -2255,7 +2255,7 @@ static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen) } -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Set up default text mode: * - Set text mode (0x03) @@ -2448,7 +2448,7 @@ void sisusb_delete(struct kref *kref) sisusb->sisusb_dev = NULL; sisusb_free_buffers(sisusb); sisusb_free_urbs(sisusb); -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON kfree(sisusb->SiS_Pr); #endif kfree(sisusb); @@ -2844,7 +2844,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, case SUCMD_HANDLETEXTMODE: retval = 0; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Gfx core must be initialized, SiS_Pr must exist */ if (!sisusb->gfxinit || !sisusb->SiS_Pr) return -ENODEV; @@ -2860,7 +2860,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, #endif break; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON case SUCMD_SETMODE: /* Gfx core must be initialized, SiS_Pr must exist */ if (!sisusb->gfxinit || !sisusb->SiS_Pr) @@ -2944,7 +2944,7 @@ static long sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) x.sisusb_vramsize = sisusb->vramsize; x.sisusb_minor = sisusb->minor; x.sisusb_fbdevactive = 0; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON x.sisusb_conactive = sisusb->haveconsole ? 1 : 0; #else x.sisusb_conactive = 0; @@ -2975,7 +2975,7 @@ err_out: return retval; } -#ifdef SISUSB_NEW_CONFIG_COMPAT +#ifdef CONFIG_COMPAT static long sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { @@ -2998,7 +2998,7 @@ static const struct file_operations usb_sisusb_fops = { .read = sisusb_read, .write = sisusb_write, .llseek = sisusb_lseek, -#ifdef SISUSB_NEW_CONFIG_COMPAT +#ifdef CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif .unlocked_ioctl = sisusb_ioctl @@ -3091,7 +3091,7 @@ static int sisusb_probe(struct usb_interface *intf, dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Allocate our SiS_Pr */ sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL); if (!sisusb->SiS_Pr) { @@ -3112,7 +3112,7 @@ static int sisusb_probe(struct usb_interface *intf, if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) { int initscreen = 1; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON if (sisusb_first_vc > 0 && sisusb_last_vc > 0 && sisusb_first_vc <= sisusb_last_vc && sisusb_last_vc <= MAX_NR_CONSOLES) @@ -3134,7 +3134,7 @@ static int sisusb_probe(struct usb_interface *intf, dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc); #endif @@ -3160,7 +3160,7 @@ static void sisusb_disconnect(struct usb_interface *intf) if (!sisusb) return; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_console_exit(sisusb); #endif @@ -3210,7 +3210,7 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_init_concode(); #endif diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 20f03ad0ea16..8a5e6bb07d05 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -38,17 +38,8 @@ #ifndef _SISUSB_H_ #define _SISUSB_H_ -#ifdef CONFIG_COMPAT -#define SISUSB_NEW_CONFIG_COMPAT -#endif - #include <linux/mutex.h> -/* For older kernels, support for text consoles is by default - * off. To enable text console support, change the following: - */ -/* #define CONFIG_USB_SISUSBVGA_CON */ - /* Version Information */ #define SISUSB_VERSION 0 @@ -57,10 +48,6 @@ /* Include console and mode switching code? */ -#ifdef CONFIG_USB_SISUSBVGA_CON -#define INCL_SISUSB_CON 1 -#endif - #include <linux/console.h> #include <linux/vt_kern.h> #include "sisusb_struct.h" @@ -139,7 +126,7 @@ struct sisusb_usb_data { unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON struct SiS_Private *SiS_Pr; unsigned long scrbuf; unsigned int scrbuf_size; diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index c4f017e1d17a..cd0155310fea 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -70,13 +70,6 @@ #include "sisusb.h" #include "sisusb_init.h" -#ifdef INCL_SISUSB_CON - -#define sisusbcon_writew(val, addr) (*(addr) = (val)) -#define sisusbcon_readw(addr) (*(addr)) -#define sisusbcon_memmovew(d, s, c) memmove(d, s, c) -#define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c) - /* vc_data -> sisusb conversion table */ static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES]; @@ -86,9 +79,7 @@ static const struct consw sisusb_con; static inline void sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) { - count /= 2; - while (count--) - sisusbcon_writew(c, s++); + memset16(s, c, count / 2); } static inline void @@ -346,25 +337,30 @@ sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count) */ while (count--) { - u16 a = sisusbcon_readw(p); - - a = ((a) & 0x88ff) | - (((a) & 0x7000) >> 4) | - (((a) & 0x0700) << 4); + u16 a = *p; - sisusbcon_writew(a, p++); + *p++ = ((a) & 0x88ff) | + (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); } } -#define SISUSB_VADDR(x,y) \ - ((u16 *)c->vc_origin + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) +static inline void *sisusb_vaddr(const struct sisusb_usb_data *sisusb, + const struct vc_data *c, unsigned int x, unsigned int y) +{ + return (u16 *)c->vc_origin + y * sisusb->sisusb_num_columns + x; +} + +static inline unsigned long sisusb_haddr(const struct sisusb_usb_data *sisusb, + const struct vc_data *c, unsigned int x, unsigned int y) +{ + unsigned long offset = c->vc_origin - sisusb->scrbuf; -#define SISUSB_HADDR(x,y) \ - ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) + /* 2 bytes per each character */ + offset += 2 * (y * sisusb->sisusb_num_columns + x); + + return sisusb->vrambase + offset; +} /* Interface routine */ static void @@ -382,9 +378,8 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; } - - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), 2); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), 2); mutex_unlock(&sisusb->lock); } @@ -395,8 +390,6 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x) { struct sisusb_usb_data *sisusb; - u16 *dest; - int i; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) @@ -408,18 +401,15 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, * because the vt does this AFTER calling us. */ - dest = SISUSB_VADDR(x, y); - - for (i = count; i > 0; i--) - sisusbcon_writew(sisusbcon_readw(s++), dest++); + memcpy(sisusb_vaddr(sisusb, c, x, y), s, count * 2); if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; } - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), count * 2); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), count * 2); mutex_unlock(&sisusb->lock); } @@ -446,7 +436,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) * this AFTER calling us. */ - dest = SISUSB_VADDR(x, y); + dest = sisusb_vaddr(sisusb, c, x, y); cols = sisusb->sisusb_num_columns; @@ -472,8 +462,8 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) length = ((height * cols) - x - (cols - width - x)) * 2; - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), length); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), length); mutex_unlock(&sisusb->lock); } @@ -517,12 +507,10 @@ sisusbcon_switch(struct vc_data *c) (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); /* Restore the screen contents */ - sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, - length); + memcpy((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, length); - sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, - (long)SISUSB_HADDR(0, 0), - length); + sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_haddr(sisusb, c, 0, 0), length); mutex_unlock(&sisusb->lock); @@ -556,8 +544,7 @@ sisusbcon_save_screen(struct vc_data *c) (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); /* Save the screen contents to vc's private buffer */ - sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, - length); + memcpy((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, length); mutex_unlock(&sisusb->lock); } @@ -628,10 +615,8 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) sisusbcon_memsetw((u16 *)c->vc_origin, c->vc_video_erase_char, c->vc_screenbuf_size); - sisusb_copy_memory(sisusb, - (unsigned char *)c->vc_origin, - (u32)(sisusb->vrambase + - (c->vc_origin - sisusb->scrbuf)), + sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); sisusb->con_blanked = 1; ret = 1; @@ -796,24 +781,24 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, switch (dir) { case SM_UP: - sisusbcon_memmovew(SISUSB_VADDR(0, t), - SISUSB_VADDR(0, t + lines), + memmove(sisusb_vaddr(sisusb, c, 0, t), + sisusb_vaddr(sisusb, c, 0, t + lines), (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr, - lines * cols * 2); + sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, b - lines), + eattr, lines * cols * 2); break; case SM_DOWN: - sisusbcon_memmovew(SISUSB_VADDR(0, t + lines), - SISUSB_VADDR(0, t), + memmove(sisusb_vaddr(sisusb, c, 0, t + lines), + sisusb_vaddr(sisusb, c, 0, t), (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr, + sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, t), eattr, lines * cols * 2); break; } - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (long)SISUSB_HADDR(0, t), length); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, 0, t), + sisusb_haddr(sisusb, c, 0, t), length); mutex_unlock(&sisusb->lock); @@ -830,7 +815,6 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, int copyall = 0; unsigned long oldorigin; unsigned int delta = lines * c->vc_size_row; - u32 originoffset; /* Returning != 0 means we have done the scrolling successfully. * Returning 0 makes vt do the scrolling on its own. @@ -874,7 +858,7 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, if (c->vc_scr_end + delta >= sisusb->scrbuf + sisusb->scrbuf_size) { - sisusbcon_memcpyw((u16 *)sisusb->scrbuf, + memcpy((u16 *)sisusb->scrbuf, (u16 *)(oldorigin + delta), c->vc_screenbuf_size - delta); c->vc_origin = sisusb->scrbuf; @@ -892,12 +876,10 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, case SM_DOWN: if (oldorigin - delta < sisusb->scrbuf) { - sisusbcon_memmovew((u16 *)(sisusb->scrbuf + - sisusb->scrbuf_size - - c->vc_screenbuf_size + - delta), - (u16 *)oldorigin, - c->vc_screenbuf_size - delta); + memmove((void *)sisusb->scrbuf + sisusb->scrbuf_size - + c->vc_screenbuf_size + delta, + (u16 *)oldorigin, + c->vc_screenbuf_size - delta); c->vc_origin = sisusb->scrbuf + sisusb->scrbuf_size - c->vc_screenbuf_size; @@ -913,23 +895,21 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, break; } - originoffset = (u32)(c->vc_origin - sisusb->scrbuf); - if (copyall) sisusb_copy_memory(sisusb, (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), + sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); else if (dir == SM_UP) sisusb_copy_memory(sisusb, (char *)c->vc_origin + c->vc_screenbuf_size - delta, - (u32)sisusb->vrambase + originoffset + + sisusb_haddr(sisusb, c, 0, 0) + c->vc_screenbuf_size - delta, delta); else sisusb_copy_memory(sisusb, (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), + sisusb_haddr(sisusb, c, 0, 0), delta); c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; @@ -1534,8 +1514,3 @@ void __init sisusb_init_concode(void) for (i = 0; i < MAX_NR_CONSOLES; i++) mysisusbs[i] = NULL; } - -#endif /* INCL_CON */ - - - diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 6a30e8bd9221..66f6ab5acd97 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -44,9 +44,6 @@ #include <linux/spinlock.h> #include "sisusb.h" - -#ifdef INCL_SISUSB_CON - #include "sisusb_init.h" /*********************************************/ @@ -955,5 +952,3 @@ int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) return SiSUSBSetMode(SiS_Pr, ModeNo); } - -#endif /* INCL_SISUSB_CON */ diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index a6efb9a72939..4d72b7d1d383 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -337,10 +337,12 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, struct device *dev = hub->dev; struct device_node *np = dev->of_node; int len, err, i; - u32 property_u32 = 0; + u32 port, property_u32 = 0; const u32 *cproperty_u32; const char *cproperty_char; char str[USB251XB_STRING_BUFSIZE / 2]; + struct property *prop; + const __be32 *p; if (!np) { dev_err(dev, "failed to get ofdata\n"); @@ -539,6 +541,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, (wchar_t *)hub->serial, USB251XB_STRING_BUFSIZE); + /* + * The datasheet documents the register as 'Port Swap' but in real the + * register controls the USB DP/DM signal swapping for each port. + */ + hub->port_swap = USB251XB_DEF_PORT_SWAP; + of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) { + if ((port >= 0) && (port <= data->port_cnt)) + hub->port_swap |= BIT(port); + } + /* The following parameters are currently not exposed to devicetree, but * may be as soon as needed. */ @@ -546,7 +558,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->boost_up = USB251XB_DEF_BOOST_UP; hub->boost_57 = USB251XB_DEF_BOOST_57; hub->boost_14 = USB251XB_DEF_BOOST_14; - hub->port_swap = USB251XB_DEF_PORT_SWAP; hub->port_map12 = USB251XB_DEF_PORT_MAP_12; hub->port_map34 = USB251XB_DEF_PORT_MAP_34; hub->port_map56 = USB251XB_DEF_PORT_MAP_56; diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index f723f7b8c9ac..d5141aa79dd4 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -355,11 +355,8 @@ static int usb3503_platform_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int usb3503_i2c_suspend(struct device *dev) +static int usb3503_suspend(struct usb3503 *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb3503 *hub = i2c_get_clientdata(client); - usb3503_switch_mode(hub, USB3503_MODE_STANDBY); if (hub->clk) @@ -368,11 +365,8 @@ static int usb3503_i2c_suspend(struct device *dev) return 0; } -static int usb3503_i2c_resume(struct device *dev) +static int usb3503_resume(struct usb3503 *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb3503 *hub = i2c_get_clientdata(client); - if (hub->clk) clk_prepare_enable(hub->clk); @@ -380,11 +374,38 @@ static int usb3503_i2c_resume(struct device *dev) return 0; } + +static int usb3503_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + return usb3503_suspend(i2c_get_clientdata(client)); +} + +static int usb3503_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + return usb3503_resume(i2c_get_clientdata(client)); +} + +static int usb3503_platform_suspend(struct device *dev) +{ + return usb3503_suspend(dev_get_drvdata(dev)); +} + +static int usb3503_platform_resume(struct device *dev) +{ + return usb3503_resume(dev_get_drvdata(dev)); +} #endif static SIMPLE_DEV_PM_OPS(usb3503_i2c_pm_ops, usb3503_i2c_suspend, usb3503_i2c_resume); +static SIMPLE_DEV_PM_OPS(usb3503_platform_pm_ops, usb3503_platform_suspend, + usb3503_platform_resume); + static const struct i2c_device_id usb3503_id[] = { { USB3503_I2C_NAME, 0 }, { } @@ -415,6 +436,7 @@ static struct platform_driver usb3503_platform_driver = { .driver = { .name = USB3503_I2C_NAME, .of_match_table = of_match_ptr(usb3503_of_match), + .pm = &usb3503_platform_pm_ops, }, .probe = usb3503_platform_probe, .remove = usb3503_platform_remove, diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index c7f82310e73e..98ada1a3425c 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -347,6 +347,14 @@ static unsigned get_maxpacket(struct usb_device *udev, int pipe) return le16_to_cpup(&ep->desc.wMaxPacketSize); } +static int ss_isoc_get_packet_num(struct usb_device *udev, int pipe) +{ + struct usb_host_endpoint *ep = usb_pipe_endpoint(udev, pipe); + + return USB_SS_MULT(ep->ss_ep_comp.bmAttributes) + * (1 + ep->ss_ep_comp.bMaxBurst); +} + static void simple_fill_buf(struct urb *urb) { unsigned i; @@ -1976,8 +1984,13 @@ static struct urb *iso_alloc_urb( if (bytes < 0 || !desc) return NULL; + maxp = usb_endpoint_maxp(desc); - maxp *= usb_endpoint_maxp_mult(desc); + if (udev->speed >= USB_SPEED_SUPER) + maxp *= ss_isoc_get_packet_num(udev, pipe); + else + maxp *= usb_endpoint_maxp_mult(desc); + packets = DIV_ROUND_UP(bytes, maxp); urb = usb_alloc_urb(packets, GFP_KERNEL); @@ -2065,17 +2078,24 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, packets *= param->iterations; if (context.is_iso) { + int transaction_num; + + if (udev->speed >= USB_SPEED_SUPER) + transaction_num = ss_isoc_get_packet_num(udev, pipe); + else + transaction_num = usb_endpoint_maxp_mult(desc); + dev_info(&dev->intf->dev, "iso period %d %sframes, wMaxPacket %d, transactions: %d\n", 1 << (desc->bInterval - 1), - (udev->speed == USB_SPEED_HIGH) ? "micro" : "", + (udev->speed >= USB_SPEED_HIGH) ? "micro" : "", usb_endpoint_maxp(desc), - usb_endpoint_maxp_mult(desc)); + transaction_num); dev_info(&dev->intf->dev, "total %lu msec (%lu packets)\n", (packets * (1 << (desc->bInterval - 1))) - / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1), + / ((udev->speed >= USB_SPEED_HIGH) ? 8 : 1), packets); } diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 5c6ffa2a612e..48f1b2dadb24 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Monitor configuration # diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig index 40bbf1f53337..bcc23486c4ed 100644 --- a/drivers/usb/mtu3/Kconfig +++ b/drivers/usb/mtu3/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# # For MTK USB3.0 IP config USB_MTU3 diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index ad08895e78f9..f742fddc5e2c 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Dual Role (OTG-ready) Controller Drivers # for silicon based on Mentor Graphics INVENTRA designs @@ -111,9 +112,9 @@ config USB_MUSB_UX500 config USB_MUSB_JZ4740 tristate "JZ4740" depends on NOP_USB_XCEIV - depends on MACH_JZ4740 || COMPILE_TEST + depends on MIPS || COMPILE_TEST depends on USB_MUSB_GADGET - depends on USB_OTG_BLACKLIST_HUB + depends on USB=n || USB_OTG_BLACKLIST_HUB config USB_MUSB_AM335X_CHILD tristate diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index 04d8b2bc205a..a60627bf7be3 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/usb/usb_phy_generic.h> @@ -188,11 +189,20 @@ static int jz4740_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id jz4740_musb_of_match[] = { + { .compatible = "ingenic,jz4740-musb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); +#endif + static struct platform_driver jz4740_driver = { .probe = jz4740_probe, .remove = jz4740_remove, .driver = { .name = "musb-jz4740", + .of_match_table = of_match_ptr(jz4740_musb_of_match), }, }; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index eae8b1b1b45b..ffe462a657b1 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -452,13 +452,10 @@ void musb_g_tx(struct musb *musb, u8 epnum) } if (request) { - u8 is_dma = 0; - bool short_packet = false; trace_musb_req_tx(req); if (dma && (csr & MUSB_TXCSR_DMAENAB)) { - is_dma = 1; csr |= MUSB_TXCSR_P_WZC_BITS; csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); @@ -476,16 +473,8 @@ void musb_g_tx(struct musb *musb, u8 epnum) */ if ((request->zero && request->length) && (request->length % musb_ep->packet_sz == 0) - && (request->actual == request->length)) - short_packet = true; + && (request->actual == request->length)) { - if ((musb_dma_inventra(musb) || musb_dma_ux500(musb)) && - (is_dma && (!dma->desired_mode || - (request->actual & - (musb_ep->packet_sz - 1))))) - short_packet = true; - - if (short_packet) { /* * On DMA completion, FIFO may not be * available yet... diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index b59ce9ad14ce..eb308ec35c66 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -378,7 +378,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, qh = first_qh(head); break; } - /* else: fall through */ + /* fall through */ case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: @@ -1283,7 +1283,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); } - return; + return; } done: diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index a688f7f87829..5fc6825745f2 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -346,12 +346,10 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) channel->status = MUSB_DMA_STATUS_FREE; /* completed */ - if ((devctl & MUSB_DEVCTL_HM) - && (musb_channel->transmit) - && ((channel->desired_mode == 0) - || (channel->actual_len & - (musb_channel->max_packet_sz - 1))) - ) { + if (musb_channel->transmit && + (!channel->desired_mode || + (channel->actual_len % + musb_channel->max_packet_sz))) { u8 epnum = musb_channel->epnum; int offset = musb->io.ep_offset(epnum, MUSB_TXCSR); @@ -363,11 +361,14 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) */ musb_ep_select(mbase, epnum); txcsr = musb_readw(mbase, offset); - txcsr &= ~(MUSB_TXCSR_DMAENAB + if (channel->desired_mode == 1) { + txcsr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_AUTOSET); - musb_writew(mbase, offset, txcsr); - /* Send out the packet */ - txcsr &= ~MUSB_TXCSR_DMAMODE; + musb_writew(mbase, offset, txcsr); + /* Send out the packet */ + txcsr &= ~MUSB_TXCSR_DMAMODE; + txcsr |= MUSB_TXCSR_DMAENAB; + } txcsr |= MUSB_TXCSR_TXPKTRDY; musb_writew(mbase, offset, txcsr); } diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index d7312eed6088..8c509b060c09 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Physical Layer USB driver configuration # @@ -21,7 +22,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM + depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM=y && PM depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 27bdb7222527..f5f0568d8533 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -61,9 +61,6 @@ static int am335x_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy); - if (ret) - return ret; am_phy->usb_phy_gen.phy.init = am335x_init; am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown; @@ -82,7 +79,7 @@ static int am335x_phy_probe(struct platform_device *pdev) device_set_wakeup_enable(dev, false); phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false); - return 0; + return usb_add_phy_dev(&am_phy->usb_phy_gen.phy); } static int am335x_phy_remove(struct platform_device *pdev) diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 183550b63faa..dade34d70419 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -400,7 +400,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); - cancel_delayed_work(&twl->get_status_work); + cancel_delayed_work_sync(&twl->get_status_work); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 4e59c649db81..ddd3be48f948 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -340,7 +340,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, pipe = usbhsh_uep_to_pipe(uep); if (unlikely(!pipe)) { - dev_err(dev, "uep doens't have pipe\n"); + dev_err(dev, "uep doesn't have pipe\n"); } else if (1 == uep->counter--) { /* last user */ struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index aa3820448286..5e730e9b40ef 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -59,7 +59,7 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, if (enable) { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); /* The controller on R-Car Gen3 needs to wait up to 45 usec */ - udelay(45); + usleep_range(45, 90); } else { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); } diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c index 5b287257ec11..8c739bd24acd 100644 --- a/drivers/usb/renesas_usbhs/rza.c +++ b/drivers/usb/renesas_usbhs/rza.c @@ -35,7 +35,7 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev) /* Enable USB PLL (NOTE: ch0 controls both ch0 and ch1) */ usbhs_bset(priv, SYSCFG, UPLLE, UPLLE); - udelay(1000); + usleep_range(1000, 2000); usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM); return 0; diff --git a/drivers/usb/roles/Kconfig b/drivers/usb/roles/Kconfig index e4194ac94510..f8b31aa67526 100644 --- a/drivers/usb/roles/Kconfig +++ b/drivers/usb/roles/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_ROLE_SWITCH tristate "USB Role Switch Support" help diff --git a/drivers/usb/roles/Makefile b/drivers/usb/roles/Makefile index c02873206fc1..757a7d2797eb 100644 --- a/drivers/usb/roles/Makefile +++ b/drivers/usb/roles/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_USB_ROLE_SWITCH) += roles.o roles-y := class.o obj-$(CONFIG_USB_ROLES_INTEL_XHCI) += intel-xhci-usb-role-switch.o diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 99116af07f1d..f45d8df5cfb8 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -8,6 +8,7 @@ */ #include <linux/usb/role.h> +#include <linux/property.h> #include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> @@ -84,7 +85,12 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw) } EXPORT_SYMBOL_GPL(usb_role_switch_get_role); -static int __switch_match(struct device *dev, const void *name) +static int switch_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static int switch_name_match(struct device *dev, const void *name) { return !strcmp((const char *)name, dev_name(dev)); } @@ -94,8 +100,16 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, { struct device *dev; - dev = class_find_device(role_class, NULL, con->endpoint[ep], - __switch_match); + if (con->fwnode) { + if (!fwnode_property_present(con->fwnode, con->id)) + return NULL; + + dev = class_find_device(role_class, NULL, con->fwnode, + switch_fwnode_match); + } else { + dev = class_find_device(role_class, NULL, con->endpoint[ep], + switch_name_match); + } return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); } @@ -266,6 +280,7 @@ usb_role_switch_register(struct device *parent, sw->get = desc->get; sw->dev.parent = parent; + sw->dev.fwnode = desc->fwnode; sw->dev.class = role_class; sw->dev.type = &usb_role_dev_type; dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent)); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 533f127c30ad..7d031911d04e 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Serial device configuration # diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index c0777a374a88..fffe23ab0189 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -61,6 +61,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ + { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */ { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ @@ -245,6 +246,7 @@ struct cp210x_serial_private { u8 gpio_input; #endif u8 partnum; + speed_t min_speed; speed_t max_speed; bool use_actual_rate; }; @@ -443,10 +445,10 @@ struct cp210x_pin_mode { #define CP210X_PIN_MODE_GPIO BIT(0) /* - * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes. - * Structure needs padding due to unused/unspecified bytes. + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes + * on a CP2105 chip. Structure needs padding due to unused/unspecified bytes. */ -struct cp210x_config { +struct cp210x_dual_port_config { __le16 gpio_mode; u8 __pad0[2]; __le16 reset_state; @@ -457,6 +459,19 @@ struct cp210x_config { u8 device_cfg; } __packed; +/* + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xd bytes + * on a CP2104 chip. Structure needs padding due to unused/unspecified bytes. + */ +struct cp210x_single_port_config { + __le16 gpio_mode; + u8 __pad0[2]; + __le16 reset_state; + u8 __pad1[4]; + __le16 suspend_state; + u8 device_cfg; +} __packed; + /* GPIO modes */ #define CP210X_SCI_GPIO_MODE_OFFSET 9 #define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9) @@ -464,11 +479,19 @@ struct cp210x_config { #define CP210X_ECI_GPIO_MODE_OFFSET 2 #define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2) +#define CP210X_GPIO_MODE_OFFSET 8 +#define CP210X_GPIO_MODE_MASK GENMASK(11, 8) + /* CP2105 port configuration values */ #define CP2105_GPIO0_TXLED_MODE BIT(0) #define CP2105_GPIO1_RXLED_MODE BIT(1) #define CP2105_GPIO1_RS485_MODE BIT(2) +/* CP2104 port configuration values */ +#define CP2104_GPIO0_TXLED_MODE BIT(0) +#define CP2104_GPIO1_RXLED_MODE BIT(1) +#define CP2104_GPIO2_RS485_MODE BIT(2) + /* CP2102N configuration array indices */ #define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2 #define CP210X_2NCONFIG_GPIO_MODE_IDX 581 @@ -1051,14 +1074,11 @@ static speed_t cp210x_get_an205_rate(speed_t baud) return cp210x_an205_table1[i].rate; } -static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud) +static speed_t cp210x_get_actual_rate(speed_t baud) { - struct cp210x_serial_private *priv = usb_get_serial_data(serial); unsigned int prescale = 1; unsigned int div; - baud = clamp(baud, 300u, priv->max_speed); - if (baud <= 365) prescale = 4; @@ -1101,20 +1121,18 @@ static void cp210x_change_speed(struct tty_struct *tty, struct cp210x_serial_private *priv = usb_get_serial_data(serial); u32 baud; - baud = tty->termios.c_ospeed; - /* * This maps the requested rate to the actual rate, a valid rate on * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed]. * * NOTE: B0 is not implemented. */ + baud = clamp(tty->termios.c_ospeed, priv->min_speed, priv->max_speed); + if (priv->use_actual_rate) - baud = cp210x_get_actual_rate(serial, baud); + baud = cp210x_get_actual_rate(baud); else if (baud < 1000000) baud = cp210x_get_an205_rate(baud); - else if (baud > priv->max_speed) - baud = priv->max_speed; dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) { @@ -1353,8 +1371,13 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) if (priv->partnum == CP210X_PARTNUM_CP2105) req_type = REQTYPE_INTERFACE_TO_HOST; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH, &buf, sizeof(buf)); + usb_autopm_put_interface(serial->interface); if (result < 0) return result; @@ -1375,6 +1398,10 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) buf.mask = BIT(gpio); + result = usb_autopm_get_interface(serial->interface); + if (result) + goto out; + if (priv->partnum == CP210X_PARTNUM_CP2105) { result = cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE, @@ -1392,6 +1419,8 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) NULL, 0, USB_CTRL_SET_TIMEOUT); } + usb_autopm_put_interface(serial->interface); +out: if (result < 0) { dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n", result); @@ -1470,7 +1499,7 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); struct cp210x_pin_mode mode; - struct cp210x_config config; + struct cp210x_dual_port_config config; u8 intf_num = cp210x_interface_num(serial); u8 iface_config; int result; @@ -1529,6 +1558,56 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) return 0; } +static int cp2104_gpioconf_init(struct usb_serial *serial) +{ + struct cp210x_serial_private *priv = usb_get_serial_data(serial); + struct cp210x_single_port_config config; + u8 iface_config; + u8 gpio_latch; + int result; + u8 i; + + result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST, + CP210X_GET_PORTCONFIG, &config, + sizeof(config)); + if (result < 0) + return result; + + priv->gc.ngpio = 4; + + iface_config = config.device_cfg; + priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + gpio_latch = (u8)((le16_to_cpu(config.reset_state) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + + /* mark all pins which are not in GPIO mode */ + if (iface_config & CP2104_GPIO0_TXLED_MODE) /* GPIO 0 */ + priv->gpio_altfunc |= BIT(0); + if (iface_config & CP2104_GPIO1_RXLED_MODE) /* GPIO 1 */ + priv->gpio_altfunc |= BIT(1); + if (iface_config & CP2104_GPIO2_RS485_MODE) /* GPIO 2 */ + priv->gpio_altfunc |= BIT(2); + + /* + * Like CP2102N, CP2104 has also no strict input and output pin + * modes. + * Do the same input mode emulation as CP2102N. + */ + for (i = 0; i < priv->gc.ngpio; ++i) { + /* + * Set direction to "input" iff pin is open-drain and reset + * value is 1. + */ + if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i))) + priv->gpio_input |= BIT(i); + } + + return 0; +} + static int cp2102n_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); @@ -1574,12 +1653,6 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) if (config_version != 0x01) return -ENOTSUPP; - /* - * We only support 4 GPIOs even on the QFN28 package, because - * config locations of GPIOs 4-6 determined using reverse - * engineering revealed conflicting offsets with other - * documented functions. So we'll just play it safe for now. - */ priv->gc.ngpio = 4; /* @@ -1594,6 +1667,19 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) /* 0 indicates GPIO mode, 1 is alternate function */ priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f; + if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) { + /* + * For the QFN28 package, GPIO4-6 are controlled by + * the low three bits of the mode/latch fields. + * Contrary to the document linked above, the bits for + * the SUSPEND pins are elsewhere. No alternate + * function is available for these pins. + */ + priv->gc.ngpio = 7; + gpio_latch |= (gpio_rst_latch & 7) << 4; + priv->gpio_pushpull |= (gpio_pushpull & 7) << 4; + } + /* * The CP2102N does not strictly has input and output pin modes, * it only knows open-drain and push-pull modes which is set at @@ -1620,6 +1706,9 @@ static int cp210x_gpio_init(struct usb_serial *serial) int result; switch (priv->partnum) { + case CP210X_PARTNUM_CP2104: + result = cp2104_gpioconf_init(serial); + break; case CP210X_PARTNUM_CP2105: result = cp2105_gpioconf_init(serial); break; @@ -1716,6 +1805,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); bool use_actual_rate = false; + speed_t min = 300; speed_t max; switch (priv->partnum) { @@ -1738,6 +1828,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) use_actual_rate = true; max = 2000000; /* ECI */ } else { + min = 2400; max = 921600; /* SCI */ } break; @@ -1752,6 +1843,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) break; } + priv->min_speed = min; priv->max_speed = max; priv->use_actual_rate = use_actual_rate; } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1ab2a6191013..8f5b17471759 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1025,6 +1025,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) }, { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) }, + /* EZPrototypes devices */ + { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) }, { } /* Terminating entry */ }; @@ -1783,6 +1785,10 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) int result; u16 val; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1795,6 +1801,8 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) val, result); } + usb_autopm_put_interface(serial->interface); + return result; } @@ -1846,9 +1854,15 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) unsigned char *buf; int result; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + buf = kmalloc(1, GFP_KERNEL); - if (!buf) + if (!buf) { + usb_autopm_put_interface(serial->interface); return -ENOMEM; + } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -1863,6 +1877,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) } kfree(buf); + usb_autopm_put_interface(serial->interface); return result; } diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 975d02666c5a..b863bedb55a1 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1309,6 +1309,12 @@ #define IONICS_PLUGCOMPUTER_PID 0x0102 /* + * EZPrototypes (PID reseller) + */ +#define EZPROTOTYPES_VID 0x1c40 +#define HJELMSLUND_USB485_ISO_PID 0x0477 + +/* * Dresden Elektronik Sensor Terminal Board */ #define DE_VID 0x1cf1 /* Vendor ID */ diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index 09e21e84fc4e..a68f1fb25b8a 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa26msg.h diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h index dee454c4609a..a19f3fe5d98d 100644 --- a/drivers/usb/serial/keyspan_usa28msg.h +++ b/drivers/usb/serial/keyspan_usa28msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa28msg.h diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h index 163b2dea2ec5..8c3970fdd868 100644 --- a/drivers/usb/serial/keyspan_usa49msg.h +++ b/drivers/usb/serial/keyspan_usa49msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa49msg.h diff --git a/drivers/usb/serial/keyspan_usa67msg.h b/drivers/usb/serial/keyspan_usa67msg.h index 20fa3e2f7187..dcf502fdbb44 100644 --- a/drivers/usb/serial/keyspan_usa67msg.h +++ b/drivers/usb/serial/keyspan_usa67msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa67msg.h diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h index 86708ecd8735..c4ca0f631d20 100644 --- a/drivers/usb/serial/keyspan_usa90msg.h +++ b/drivers/usb/serial/keyspan_usa90msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa90msg.h diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index aef15497ff31..11b21d9410f3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1148,6 +1148,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), .driver_info = NCTRL(0) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ + .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 98e7a5df0f6d..bb3f9aa4a909 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -46,6 +46,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 4e2554d55362..559941ca884d 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -8,6 +8,7 @@ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_TB 0x2304 #define PL2303_PRODUCT_ID_RSAQ2 0x04bb #define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 @@ -20,6 +21,7 @@ #define PL2303_PRODUCT_ID_MOTOROLA 0x0307 #define PL2303_PRODUCT_ID_ZTEK 0xe1f1 + #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 4d0273508043..edbbb13d6de6 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -85,7 +85,8 @@ DEVICE(moto_modem, MOTO_IDS); /* Motorola Tetra driver */ #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ - { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */ + { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); /* Novatel Wireless GPS driver */ diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 6fd427284b12..59aad38b490a 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Storage driver configuration # diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index edcf2be0e0eb..395cf8fb5870 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -167,6 +167,7 @@ static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us) static void rio_karma_destructor(void *extra) { struct karma_data *data = (struct karma_data *) extra; + kfree(data->recv); } @@ -174,6 +175,7 @@ static int rio_karma_init(struct us_data *us) { int ret = 0; struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO); + if (!data) goto out; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index fde2e71a6ade..a73ea495d5a7 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -235,8 +235,12 @@ static int slave_configure(struct scsi_device *sdev) if (!(us->fflags & US_FL_NEEDS_CAP16)) sdev->try_rc_10_first = 1; - /* assume SPC3 or latter devices support sense size > 18 */ - if (sdev->scsi_level > SCSI_SPC_2) + /* + * assume SPC3 or latter devices support sense size > 18 + * unless US_FL_BAD_SENSE quirk is specified. + */ + if (sdev->scsi_level > SCSI_SPC_2 && + !(us->fflags & US_FL_BAD_SENSE)) us->fflags |= US_FL_SANE_SENSE; /* diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f7f83b21dc74..ea0d27a94afe 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1266,6 +1266,18 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, US_FL_FIX_CAPACITY ), /* + * Reported by Icenowy Zheng <icenowy@aosc.io> + * The SMI SM3350 USB-UFS bridge controller will enter a wrong state + * that do not process read/write command if a long sense is requested, + * so force to use 18-byte sense. + */ +UNUSUAL_DEV( 0x090c, 0x3350, 0x0000, 0xffff, + "SMI", + "SM3350 UFS-to-USB-Mass-Storage bridge", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BAD_SENSE ), + +/* * Reported by Paul Hartman <paul.hartman+linux@gmail.com> * This card reader returns "Illegal Request, Logical Block Address * Out of Range" for the first READ(10) after a new card is inserted. diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 30a847c2089d..89d9193bd1cf 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 menuconfig TYPEC tristate "USB Type-C Support" diff --git a/drivers/usb/typec/altmodes/Kconfig b/drivers/usb/typec/altmodes/Kconfig index efef2a64bc51..ef2226eb7a33 100644 --- a/drivers/usb/typec/altmodes/Kconfig +++ b/drivers/usb/typec/altmodes/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 menu "USB Type-C Alternate Mode drivers" diff --git a/drivers/usb/typec/altmodes/Makefile b/drivers/usb/typec/altmodes/Makefile index 5caf094ef71a..eda8456f1c92 100644 --- a/drivers/usb/typec/altmodes/Makefile +++ b/drivers/usb/typec/altmodes/Makefile @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_TYPEC_DP_ALTMODE) += typec_displayport.o typec_displayport-y := displayport.o diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 3f06e94771a7..610d790bc9be 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -24,10 +24,6 @@ enum { DP_CONF_DUAL_D, }; -/* Helper for setting/getting the pin assignement value to the configuration */ -#define DP_CONF_SET_PIN_ASSIGN(_a_) ((_a_) << 8) -#define DP_CONF_GET_PIN_ASSIGN(_conf_) (((_conf_) & GENMASK(15, 8)) >> 8) - /* Pin assignments that use USB3.1 Gen2 signaling to carry DP protocol */ #define DP_PIN_ASSIGN_GEN2_BR_MASK (BIT(DP_PIN_ASSIGN_A) | \ BIT(DP_PIN_ASSIGN_B)) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 5db0593ca0bd..2eb623841847 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -9,6 +9,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> #include <linux/slab.h> #include "bus.h" @@ -204,15 +205,32 @@ static void typec_altmode_put_partner(struct altmode *altmode) put_device(&adev->dev); } -static int __typec_port_match(struct device *dev, const void *name) +static int typec_port_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static int typec_port_name_match(struct device *dev, const void *name) { return !strcmp((const char *)name, dev_name(dev)); } static void *typec_port_match(struct device_connection *con, int ep, void *data) { - return class_find_device(typec_class, NULL, con->endpoint[ep], - __typec_port_match); + struct device *dev; + + /* + * FIXME: Check does the fwnode supports the requested SVID. If it does + * we need to return ERR_PTR(-PROBE_DEFER) when there is no device. + */ + if (con->fwnode) + return class_find_device(typec_class, NULL, con->fwnode, + typec_port_fwnode_match); + + dev = class_find_device(typec_class, NULL, con->endpoint[ep], + typec_port_name_match); + + return dev ? dev : ERR_PTR(-EPROBE_DEFER); } struct typec_altmode * @@ -277,7 +295,7 @@ void typec_altmode_update_active(struct typec_altmode *adev, bool active) if (adev->active == active) return; - if (!is_typec_port(adev->dev.parent)) { + if (!is_typec_port(adev->dev.parent) && adev->dev.driver) { if (!active) module_put(adev->dev.driver->owner); else @@ -1496,11 +1514,8 @@ typec_port_register_altmode(struct typec_port *port, { struct typec_altmode *adev; struct typec_mux *mux; - char id[10]; - - sprintf(id, "id%04xm%02x", desc->svid, desc->mode); - mux = typec_mux_get(&port->dev, id); + mux = typec_mux_get(&port->dev, desc); if (IS_ERR(mux)) return ERR_CAST(mux); @@ -1593,7 +1608,7 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_CAST(port->sw); } - port->mux = typec_mux_get(&port->dev, "typec-mux"); + port->mux = typec_mux_get(&port->dev, NULL); if (IS_ERR(port->mux)) { put_device(&port->dev); return ERR_CAST(port->mux); diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index d990aa510fab..2ce54f3fc79c 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -11,6 +11,8 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> +#include <linux/slab.h> #include <linux/usb/typec_mux.h> static DEFINE_MUTEX(switch_lock); @@ -23,15 +25,25 @@ static void *typec_switch_match(struct device_connection *con, int ep, { struct typec_switch *sw; - list_for_each_entry(sw, &switch_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) - return sw; + if (!con->fwnode) { + list_for_each_entry(sw, &switch_list, entry) + if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) + return sw; + return ERR_PTR(-EPROBE_DEFER); + } /* - * We only get called if a connection was found, tell the caller to - * wait for the switch to show up. + * With OF graph the mux node must have a boolean device property named + * "orientation-switch". */ - return ERR_PTR(-EPROBE_DEFER); + if (con->id && !fwnode_property_present(con->fwnode, con->id)) + return NULL; + + list_for_each_entry(sw, &switch_list, entry) + if (dev_fwnode(sw->dev) == con->fwnode) + return sw; + + return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL; } /** @@ -48,7 +60,7 @@ struct typec_switch *typec_switch_get(struct device *dev) struct typec_switch *sw; mutex_lock(&switch_lock); - sw = device_connection_find_match(dev, "typec-switch", NULL, + sw = device_connection_find_match(dev, "orientation-switch", NULL, typec_switch_match); if (!IS_ERR_OR_NULL(sw)) { WARN_ON(!try_module_get(sw->dev->driver->owner)); @@ -112,35 +124,87 @@ EXPORT_SYMBOL_GPL(typec_switch_unregister); static void *typec_mux_match(struct device_connection *con, int ep, void *data) { + const struct typec_altmode_desc *desc = data; struct typec_mux *mux; + int nval; + bool match; + u16 *val; + int i; - list_for_each_entry(mux, &mux_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) - return mux; + if (!con->fwnode) { + list_for_each_entry(mux, &mux_list, entry) + if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) + return mux; + return ERR_PTR(-EPROBE_DEFER); + } /* - * We only get called if a connection was found, tell the caller to - * wait for the switch to show up. + * Check has the identifier already been "consumed". If it + * has, no need to do any extra connection identification. */ + match = !con->id; + if (match) + goto find_mux; + + /* Accessory Mode muxes */ + if (!desc) { + match = fwnode_property_present(con->fwnode, "accessory"); + if (match) + goto find_mux; + return NULL; + } + + /* Alternate Mode muxes */ + nval = fwnode_property_read_u16_array(con->fwnode, "svid", NULL, 0); + if (nval <= 0) + return NULL; + + val = kcalloc(nval, sizeof(*val), GFP_KERNEL); + if (!val) + return ERR_PTR(-ENOMEM); + + nval = fwnode_property_read_u16_array(con->fwnode, "svid", val, nval); + if (nval < 0) { + kfree(val); + return ERR_PTR(nval); + } + + for (i = 0; i < nval; i++) { + match = val[i] == desc->svid; + if (match) { + kfree(val); + goto find_mux; + } + } + kfree(val); + return NULL; + +find_mux: + list_for_each_entry(mux, &mux_list, entry) + if (dev_fwnode(mux->dev) == con->fwnode) + return mux; + return ERR_PTR(-EPROBE_DEFER); } /** * typec_mux_get - Find USB Type-C Multiplexer * @dev: The caller device - * @name: Mux identifier + * @desc: Alt Mode description * * Finds a mux linked to the caller. This function is primarily meant for the * Type-C drivers. Returns a reference to the mux on success, NULL if no * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection * was found but the mux has not been enumerated yet. */ -struct typec_mux *typec_mux_get(struct device *dev, const char *name) +struct typec_mux *typec_mux_get(struct device *dev, + const struct typec_altmode_desc *desc) { struct typec_mux *mux; mutex_lock(&mux_lock); - mux = device_connection_find_match(dev, name, NULL, typec_mux_match); + mux = device_connection_find_match(dev, "mode-switch", (void *)desc, + typec_mux_match); if (!IS_ERR_OR_NULL(mux)) { WARN_ON(!try_module_get(mux->dev->driver->owner)); get_device(mux->dev); diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 9a954d2b8d8f..01ed0d5e10e8 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + menu "USB Type-C Multiplexer/DeMultiplexer Switch support" config TYPEC_MUX_PI3USB30532 diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index f03ea8a61768..72481bbb2af3 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config TYPEC_TCPM tristate "USB Type-C Port Controller Manager" depends on USB diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4bc29b586698..0f62db091d8d 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -2297,7 +2297,8 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) pdo_pps_apdo_max_voltage(snk)); port->pps_data.max_curr = min_pps_apdo_current(src, snk); port->pps_data.out_volt = min(port->pps_data.max_volt, - port->pps_data.out_volt); + max(port->pps_data.min_volt, + port->pps_data.out_volt)); port->pps_data.op_curr = min(port->pps_data.max_curr, port->pps_data.op_curr); } @@ -4434,66 +4435,6 @@ sink: return 0; } -int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo) -{ - if (tcpm_validate_caps(port, pdo, nr_pdo)) - return -EINVAL; - - mutex_lock(&port->lock); - port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, pdo, nr_pdo); - switch (port->state) { - case SRC_UNATTACHED: - case SRC_ATTACH_WAIT: - case SRC_TRYWAIT: - tcpm_set_cc(port, tcpm_rp_cc(port)); - break; - case SRC_SEND_CAPABILITIES: - case SRC_NEGOTIATE_CAPABILITIES: - case SRC_READY: - case SRC_WAIT_NEW_CAPABILITIES: - tcpm_set_cc(port, tcpm_rp_cc(port)); - tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); - break; - default: - break; - } - mutex_unlock(&port->lock); - return 0; -} -EXPORT_SYMBOL_GPL(tcpm_update_source_capabilities); - -int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo, - unsigned int operating_snk_mw) -{ - if (tcpm_validate_caps(port, pdo, nr_pdo)) - return -EINVAL; - - mutex_lock(&port->lock); - port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, pdo, nr_pdo); - port->operating_snk_mw = operating_snk_mw; - port->update_sink_caps = true; - - switch (port->state) { - case SNK_NEGOTIATE_CAPABILITIES: - case SNK_NEGOTIATE_PPS_CAPABILITIES: - case SNK_READY: - case SNK_TRANSITION_SINK: - case SNK_TRANSITION_SINK_VBUS: - if (port->pps_data.active) - tcpm_set_state(port, SNK_NEGOTIATE_PPS_CAPABILITIES, 0); - else - tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0); - break; - default: - break; - } - mutex_unlock(&port->lock); - return 0; -} -EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities); - /* Power Supply access to expose source power information */ enum tcpm_psy_online_states { TCPM_PSY_OFFLINE = 0, @@ -4810,12 +4751,12 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) err = devm_tcpm_psy_register(port); if (err) - goto out_destroy_wq; + goto out_role_sw_put; port->typec_port = typec_register_port(port->dev, &port->typec_caps); if (IS_ERR(port->typec_port)) { err = PTR_ERR(port->typec_port); - goto out_destroy_wq; + goto out_role_sw_put; } if (tcpc->config && tcpc->config->alt_modes) { @@ -4848,8 +4789,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_log(port, "%s: registered", dev_name(dev)); return port; -out_destroy_wq: +out_role_sw_put: usb_role_switch_put(port->role_sw); +out_destroy_wq: + tcpm_debugfs_exit(port); destroy_workqueue(port->wq); return ERR_PTR(err); } diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index 1c0033ad8738..c674abe3cf99 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -14,6 +14,8 @@ #include <linux/usb/typec.h> /* Register offsets */ +#define TPS_REG_VID 0x00 +#define TPS_REG_MODE 0x03 #define TPS_REG_CMD1 0x08 #define TPS_REG_DATA1 0x09 #define TPS_REG_INT_EVENT1 0x14 @@ -66,6 +68,20 @@ struct tps6598x_rx_identity_reg { #define TPS_TASK_TIMEOUT 1 #define TPS_TASK_REJECTED 3 +enum { + TPS_MODE_APP, + TPS_MODE_BOOT, + TPS_MODE_BIST, + TPS_MODE_DISC, +}; + +static const char *const modes[] = { + [TPS_MODE_APP] = "APP ", + [TPS_MODE_BOOT] = "BOOT", + [TPS_MODE_BIST] = "BIST", + [TPS_MODE_DISC] = "DISC", +}; + /* Unrecognized commands will be replaced with "!CMD" */ #define INVALID_CMD(_cmd_) (_cmd_ == 0x444d4321) @@ -110,6 +126,20 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len) return 0; } +static int tps6598x_block_write(struct tps6598x *tps, u8 reg, + void *val, size_t len) +{ + u8 data[TPS_MAX_LEN + 1]; + + if (!tps->i2c_protocol) + return regmap_raw_write(tps->regmap, reg, val, len); + + data[0] = len; + memcpy(&data[1], val, len); + + return regmap_raw_write(tps->regmap, reg, data, sizeof(data)); +} + static inline int tps6598x_read16(struct tps6598x *tps, u8 reg, u16 *val) { return tps6598x_block_read(tps, reg, val, sizeof(u16)); @@ -127,23 +157,23 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val) static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u16)); + return tps6598x_block_write(tps, reg, &val, sizeof(u16)); } static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u32)); + return tps6598x_block_write(tps, reg, &val, sizeof(u32)); } static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u64)); + return tps6598x_block_write(tps, reg, &val, sizeof(u64)); } static inline int tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u32)); + return tps6598x_block_write(tps, reg, &val, sizeof(u32)); } static int tps6598x_read_partner_identity(struct tps6598x *tps) @@ -229,8 +259,8 @@ static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, return -EBUSY; if (in_len) { - ret = regmap_raw_write(tps->regmap, TPS_REG_DATA1, - in_data, in_len); + ret = tps6598x_block_write(tps, TPS_REG_DATA1, + in_data, in_len); if (ret) return ret; } @@ -384,6 +414,32 @@ err_unlock: return IRQ_HANDLED; } +static int tps6598x_check_mode(struct tps6598x *tps) +{ + char mode[5] = { }; + int ret; + + ret = tps6598x_read32(tps, TPS_REG_MODE, (void *)mode); + if (ret) + return ret; + + switch (match_string(modes, ARRAY_SIZE(modes), mode)) { + case TPS_MODE_APP: + return 0; + case TPS_MODE_BOOT: + dev_warn(tps->dev, "dead-battery condition\n"); + return 0; + case TPS_MODE_BIST: + case TPS_MODE_DISC: + default: + dev_err(tps->dev, "controller in unsupported mode \"%s\"\n", + mode); + break; + } + + return -ENODEV; +} + static const struct regmap_config tps6598x_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -409,10 +465,8 @@ static int tps6598x_probe(struct i2c_client *client) if (IS_ERR(tps->regmap)) return PTR_ERR(tps->regmap); - ret = tps6598x_read32(tps, 0, &vid); - if (ret < 0) - return ret; - if (!vid) + ret = tps6598x_read32(tps, TPS_REG_VID, &vid); + if (ret < 0 || !vid) return -ENODEV; /* @@ -425,6 +479,11 @@ static int tps6598x_probe(struct i2c_client *client) if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) tps->i2c_protocol = true; + /* Make sure the controller has application firmware running */ + ret = tps6598x_check_mode(tps); + if (ret) + return ret; + ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); if (ret < 0) return ret; diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 78118883f96c..15c2ac7db02d 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config TYPEC_UCSI tristate "USB Type-C Connector System Software Interface driver" depends on !CPU_BIG_ENDIAN diff --git a/drivers/usb/typec/ucsi/debug.h b/drivers/usb/typec/ucsi/debug.h deleted file mode 100644 index fdeff39df120..000000000000 --- a/drivers/usb/typec/ucsi/debug.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __UCSI_DEBUG_H -#define __UCSI_DEBUG_H - -#include "ucsi.h" - -static const char * const ucsi_cmd_strs[] = { - [0] = "Unknown command", - [UCSI_PPM_RESET] = "PPM_RESET", - [UCSI_CANCEL] = "CANCEL", - [UCSI_CONNECTOR_RESET] = "CONNECTOR_RESET", - [UCSI_ACK_CC_CI] = "ACK_CC_CI", - [UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE", - [UCSI_GET_CAPABILITY] = "GET_CAPABILITY", - [UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY", - [UCSI_SET_UOM] = "SET_UOM", - [UCSI_SET_UOR] = "SET_UOR", - [UCSI_SET_PDM] = "SET_PDM", - [UCSI_SET_PDR] = "SET_PDR", - [UCSI_GET_ALTERNATE_MODES] = "GET_ALTERNATE_MODES", - [UCSI_GET_CAM_SUPPORTED] = "GET_CAM_SUPPORTED", - [UCSI_GET_CURRENT_CAM] = "GET_CURRENT_CAM", - [UCSI_SET_NEW_CAM] = "SET_NEW_CAM", - [UCSI_GET_PDOS] = "GET_PDOS", - [UCSI_GET_CABLE_PROPERTY] = "GET_CABLE_PROPERTY", - [UCSI_GET_CONNECTOR_STATUS] = "GET_CONNECTOR_STATUS", - [UCSI_GET_ERROR_STATUS] = "GET_ERROR_STATUS", -}; - -static inline const char *ucsi_cmd_str(u64 raw_cmd) -{ - u8 cmd = raw_cmd & GENMASK(7, 0); - - return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; -} - -static const char * const ucsi_ack_strs[] = { - [0] = "", - [UCSI_ACK_EVENT] = "event", - [UCSI_ACK_CMD] = "command", -}; - -static inline const char *ucsi_ack_str(u8 ack) -{ - return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; -} - -static inline const char *ucsi_cci_str(u32 cci) -{ - if (cci & GENMASK(7, 0)) { - if (cci & BIT(29)) - return "Event pending (ACK completed)"; - if (cci & BIT(31)) - return "Event pending (command completed)"; - return "Connector Change"; - } - if (cci & BIT(29)) - return "ACK completed"; - if (cci & BIT(31)) - return "Command completed"; - - return ""; -} - -#endif /* __UCSI_DEBUG_H */ diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index d9a6ff6e673c..ffa3b4c3f338 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c @@ -1,3 +1,62 @@ // SPDX-License-Identifier: GPL-2.0 #define CREATE_TRACE_POINTS +#include "ucsi.h" #include "trace.h" + +static const char * const ucsi_cmd_strs[] = { + [0] = "Unknown command", + [UCSI_PPM_RESET] = "PPM_RESET", + [UCSI_CANCEL] = "CANCEL", + [UCSI_CONNECTOR_RESET] = "CONNECTOR_RESET", + [UCSI_ACK_CC_CI] = "ACK_CC_CI", + [UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE", + [UCSI_GET_CAPABILITY] = "GET_CAPABILITY", + [UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY", + [UCSI_SET_UOM] = "SET_UOM", + [UCSI_SET_UOR] = "SET_UOR", + [UCSI_SET_PDM] = "SET_PDM", + [UCSI_SET_PDR] = "SET_PDR", + [UCSI_GET_ALTERNATE_MODES] = "GET_ALTERNATE_MODES", + [UCSI_GET_CAM_SUPPORTED] = "GET_CAM_SUPPORTED", + [UCSI_GET_CURRENT_CAM] = "GET_CURRENT_CAM", + [UCSI_SET_NEW_CAM] = "SET_NEW_CAM", + [UCSI_GET_PDOS] = "GET_PDOS", + [UCSI_GET_CABLE_PROPERTY] = "GET_CABLE_PROPERTY", + [UCSI_GET_CONNECTOR_STATUS] = "GET_CONNECTOR_STATUS", + [UCSI_GET_ERROR_STATUS] = "GET_ERROR_STATUS", +}; + +const char *ucsi_cmd_str(u64 raw_cmd) +{ + u8 cmd = raw_cmd & GENMASK(7, 0); + + return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; +} + +static const char * const ucsi_ack_strs[] = { + [0] = "", + [UCSI_ACK_EVENT] = "event", + [UCSI_ACK_CMD] = "command", +}; + +const char *ucsi_ack_str(u8 ack) +{ + return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; +} + +const char *ucsi_cci_str(u32 cci) +{ + if (cci & GENMASK(7, 0)) { + if (cci & BIT(29)) + return "Event pending (ACK completed)"; + if (cci & BIT(31)) + return "Event pending (command completed)"; + return "Connector Change"; + } + if (cci & BIT(29)) + return "ACK completed"; + if (cci & BIT(31)) + return "Command completed"; + + return ""; +} diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index d5092446ecc6..5e2906df2db7 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h @@ -7,8 +7,11 @@ #define __UCSI_TRACE_H #include <linux/tracepoint.h> -#include "ucsi.h" -#include "debug.h" + +const char *ucsi_cmd_str(u64 raw_cmd); +const char *ucsi_ack_str(u8 ack); +const char *ucsi_cci_str(u32 cci); +const char *ucsi_recipient_str(u8 recipient); DECLARE_EVENT_CLASS(ucsi_log_ack, TP_PROTO(u8 ack), diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index a20b65cb6678..2f86b28fa3da 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USBIP_CORE tristate "USB/IP support" depends on NET diff --git a/drivers/usb/usbip/README b/drivers/usb/usbip/README deleted file mode 100644 index 41a2cf2e77a6..000000000000 --- a/drivers/usb/usbip/README +++ /dev/null @@ -1,7 +0,0 @@ -TODO: - - more discussion about the protocol - - testing - - review of the userspace interface - - document the protocol - -Please send patches for this code to Greg Kroah-Hartman <greg@kroah.com> diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 1e592ec94ba4..f46ee1fefe02 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -702,8 +702,10 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag } vdev = &vhci_hcd->vdev[portnum-1]; - /* patch to usb_sg_init() is in 2.5.60 */ - BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); + if (!urb->transfer_buffer && urb->transfer_buffer_length) { + dev_dbg(dev, "Null URB transfer buffer\n"); + return -EINVAL; + } spin_lock_irqsave(&vhci->lock, flags); diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c index 1634d8698e15..a72c17ff1c6a 100644 --- a/drivers/usb/usbip/vudc_dev.c +++ b/drivers/usb/usbip/vudc_dev.c @@ -297,7 +297,8 @@ static void vep_free_request(struct usb_ep *_ep, struct usb_request *_req) { struct vrequest *req; - if (WARN_ON(!_ep || !_req)) + /* ep is always valid here - see usb_ep_free_request() */ + if (!_req) return; req = to_vrequest(_req); diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig index 348de1d6726e..12e89189ca7d 100644 --- a/drivers/usb/wusbcore/Kconfig +++ b/drivers/usb/wusbcore/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Wireless USB Core configuration # diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index 222228c5c1e1..af77064c7456 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -302,10 +302,8 @@ static ssize_t cbaf_wusb_chid_show(struct device *dev, { struct usb_interface *iface = to_usb_interface(dev); struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_chid[WUSB_CKHDID_STRSIZE]; - ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid); + return sprintf(buf, "%16ph\n", cbaf->chid.data); } static ssize_t cbaf_wusb_chid_store(struct device *dev, @@ -415,10 +413,8 @@ static ssize_t cbaf_wusb_cdid_show(struct device *dev, { struct usb_interface *iface = to_usb_interface(dev); struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_cdid[WUSB_CKHDID_STRSIZE]; - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid); + return sprintf(buf, "%16ph\n", cbaf->cdid.data); } static ssize_t cbaf_wusb_cdid_store(struct device *dev, @@ -503,7 +499,6 @@ static int cbaf_cc_upload(struct cbaf *cbaf) int result; struct device *dev = &cbaf->usb_iface->dev; struct wusb_cbaf_cc_data *ccd; - char pr_cdid[WUSB_CKHDID_STRSIZE]; ccd = cbaf->buffer; *ccd = cbaf_cc_data_defaults; @@ -513,10 +508,8 @@ static int cbaf_cc_upload(struct cbaf *cbaf) ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); dev_dbg(dev, "Trying to upload CC:\n"); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID); - dev_dbg(dev, " CHID %s\n", pr_cdid); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID); - dev_dbg(dev, " CDID %s\n", pr_cdid); + dev_dbg(dev, " CHID %16ph\n", ccd->CHID.data); + dev_dbg(dev, " CDID %16ph\n", ccd->CDID.data); dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); result = usb_control_msg( diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c index 85a1acf3a729..67b0a4c412b2 100644 --- a/drivers/usb/wusbcore/dev-sysfs.c +++ b/drivers/usb/wusbcore/dev-sysfs.c @@ -50,10 +50,9 @@ static ssize_t wusb_cdid_show(struct device *dev, wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev)); if (wusb_dev == NULL) return -ENODEV; - result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid); - strcat(buf, "\n"); + result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data); wusb_dev_put(wusb_dev); - return result + 1; + return result; } static DEVICE_ATTR_RO(wusb_cdid); diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index fcb06aef2675..a93837d57d53 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -532,7 +532,7 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, } dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID); + sprintf(pr_cdid, "%16ph", dnc->CDID.data); dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n", pr_cdid, wusb_dn_connect_prev_dev_addr(dnc), diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 01f2f21830c0..abf88cea37bb 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -662,9 +662,9 @@ static void __wa_setup_isoc_packet_descr( /* populate isoc packet descriptor. */ packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO; - packet_desc->wLength = cpu_to_le16(sizeof(*packet_desc) + - (sizeof(packet_desc->PacketLength[0]) * - seg->isoc_frame_count)); + packet_desc->wLength = cpu_to_le16(struct_size(packet_desc, + PacketLength, + seg->isoc_frame_count)); for (frame_index = 0; frame_index < seg->isoc_frame_count; ++frame_index) { int offset_index = frame_index + seg->isoc_frame_offset; @@ -2438,7 +2438,7 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) struct wa_rpipe *rpipe; unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index; unsigned first_frame_index = 0, rpipe_ready = 0; - int expected_size; + size_t expected_size; /* We have a xfer result buffer; check it */ dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n", @@ -2460,11 +2460,10 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) goto error_bad_seg; seg = xfer->seg[wa->dti_isoc_xfer_seg]; rpipe = xfer->ep->hcpriv; - expected_size = sizeof(*packet_status) + - (sizeof(packet_status->PacketStatus[0]) * - seg->isoc_frame_count); + expected_size = struct_size(packet_status, PacketStatus, + seg->isoc_frame_count); if (urb->actual_length != expected_size) { - dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %d needed)\n", + dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n", urb->actual_length, expected_size); goto error_bad_seg; } diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index e5ba6140c1ba..d0b404d258e8 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -80,17 +80,13 @@ static ssize_t wusb_chid_show(struct device *dev, { struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); const struct wusb_ckhdid *chid; - ssize_t result = 0; if (wusbhc->wuie_host_info != NULL) chid = &wusbhc->wuie_host_info->CHID; else chid = &wusb_ckhdid_zero; - result += ckhdid_printf(buf, PAGE_SIZE, chid); - result += sprintf(buf + result, "\n"); - - return result; + return sprintf(buf, "%16ph\n", chid->data); } /* |