diff options
Diffstat (limited to 'drivers/usb')
132 files changed, 1577 insertions, 423 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index d65a64c29b85..5160a4a966b3 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -43,7 +43,6 @@ #include "usbatm.h" #define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott" -#define DRIVER_VERSION "0.4" #define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver" static const char cxacru_driver_name[] = "cxacru"; @@ -1380,4 +1379,3 @@ module_usb_driver(cxacru_usb_driver); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 5083eb5b0d5e..3676adb40d89 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -40,8 +40,7 @@ #include "usbatm.h" #define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>" -#define DRIVER_VERSION "1.10" -#define DRIVER_DESC "Alcatel SpeedTouch USB driver version " DRIVER_VERSION +#define DRIVER_DESC "Alcatel SpeedTouch USB driver" static const char speedtch_driver_name[] = "speedtch"; @@ -738,7 +737,7 @@ static int speedtch_post_reset(struct usb_interface *intf) ** USB ** **********/ -static struct usb_device_id speedtch_usb_ids[] = { +static const struct usb_device_id speedtch_usb_ids[] = { {USB_DEVICE(0x06b9, 0x4061)}, {} }; @@ -962,4 +961,3 @@ module_usb_driver(speedtch_usb_driver); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index df67815f74e6..ba7616395db2 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2212,7 +2212,7 @@ static int uea_boot(struct uea_softc *sc) ret = usb_submit_urb(sc->urb_int, GFP_KERNEL); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), - "urb submition failed with error %d\n", ret); + "urb submission failed with error %d\n", ret); goto err1; } @@ -2522,7 +2522,7 @@ static struct attribute *attrs[] = { &dev_attr_stat_firmid.attr, NULL, }; -static struct attribute_group attr_grp = { +static const struct attribute_group attr_grp = { .attrs = attrs, }; diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 3e80aa3b917a..8607af758bbd 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -93,8 +93,7 @@ static int usbatm_print_packet(struct usbatm_data *instance, const unsigned char #endif #define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>" -#define DRIVER_VERSION "1.10" -#define DRIVER_DESC "Generic USB ATM/DSL I/O, version " DRIVER_VERSION +#define DRIVER_DESC "Generic USB ATM/DSL I/O" static const char usbatm_driver_name[] = "usbatm"; @@ -174,7 +173,7 @@ static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __us static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb); static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t *pos, char *page); -static struct atmdev_ops usbatm_atm_devops = { +static const struct atmdev_ops usbatm_atm_devops = { .dev_close = usbatm_atm_dev_close, .open = usbatm_atm_open, .close = usbatm_atm_close, @@ -1315,7 +1314,6 @@ module_exit(usbatm_usb_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); /************ ** debug ** diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c index a87597f88a84..c73c1ec3005e 100644 --- a/drivers/usb/atm/xusbatm.c +++ b/drivers/usb/atm/xusbatm.c @@ -228,4 +228,3 @@ module_exit(xusbatm_exit); MODULE_AUTHOR("Roman Kagan, Duncan Sands"); MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c index c2d13968da82..30d3f346686e 100644 --- a/drivers/usb/c67x00/c67x00-hcd.c +++ b/drivers/usb/c67x00/c67x00-hcd.c @@ -305,7 +305,7 @@ static int c67x00_hcd_get_frame(struct usb_hcd *hcd) return temp_val ? (temp_val - 1) : HOST_FRAME_MASK; } -static struct hc_driver c67x00_hc_driver = { +static const struct hc_driver c67x00_hc_driver = { .description = "c67x00-hcd", .product_desc = "Cypress C67X00 Host Controller", .hcd_priv_size = sizeof(struct c67x00_hcd), diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 39fca5715ed3..ddcbddf8361a 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_zevio.o obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o obj-$(CONFIG_USB_CHIPIDEA_OF) += usbmisc_imx.o ci_hdrc_imx.o +obj-$(CONFIG_USB_CHIPIDEA_OF) += ci_hdrc_tegra.o diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 0bdfcdcbf7a5..bb626120296f 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -251,7 +251,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev) if (ret) goto err_mux; - ulpi_node = of_find_node_by_name(pdev->dev.of_node, "ulpi"); + ulpi_node = of_find_node_by_name(of_node_get(pdev->dev.of_node), "ulpi"); if (ulpi_node) { phy_node = of_get_next_available_child(ulpi_node, NULL); ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy"); diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c index b635ab67490d..39414e4b2d81 100644 --- a/drivers/usb/chipidea/ci_hdrc_pci.c +++ b/drivers/usb/chipidea/ci_hdrc_pci.c @@ -170,5 +170,4 @@ module_pci_driver(ci_hdrc_pci_driver); MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); MODULE_LICENSE("GPL"); -MODULE_VERSION("June 2008"); MODULE_ALIAS("platform:ci13xxx_pci"); diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c new file mode 100644 index 000000000000..bfcee2702d50 --- /dev/null +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016, NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/reset.h> + +#include <linux/usb/chipidea.h> + +#include "ci.h" + +struct tegra_udc { + struct ci_hdrc_platform_data data; + struct platform_device *dev; + + struct usb_phy *phy; + struct clk *clk; +}; + +struct tegra_udc_soc_info { + unsigned long flags; +}; + +static const struct tegra_udc_soc_info tegra20_udc_soc_info = { + .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, +}; + +static const struct tegra_udc_soc_info tegra30_udc_soc_info = { + .flags = 0, +}; + +static const struct tegra_udc_soc_info tegra114_udc_soc_info = { + .flags = 0, +}; + +static const struct tegra_udc_soc_info tegra124_udc_soc_info = { + .flags = 0, +}; + +static const struct of_device_id tegra_udc_of_match[] = { + { + .compatible = "nvidia,tegra20-udc", + .data = &tegra20_udc_soc_info, + }, { + .compatible = "nvidia,tegra30-udc", + .data = &tegra30_udc_soc_info, + }, { + .compatible = "nvidia,tegra114-udc", + .data = &tegra114_udc_soc_info, + }, { + .compatible = "nvidia,tegra124-udc", + .data = &tegra124_udc_soc_info, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, tegra_udc_of_match); + +static int tegra_udc_probe(struct platform_device *pdev) +{ + const struct tegra_udc_soc_info *soc; + struct tegra_udc *udc; + int err; + + udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); + if (!udc) + return -ENOMEM; + + soc = of_device_get_match_data(&pdev->dev); + if (!soc) { + dev_err(&pdev->dev, "failed to match OF data\n"); + return -EINVAL; + } + + udc->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); + if (IS_ERR(udc->phy)) { + err = PTR_ERR(udc->phy); + dev_err(&pdev->dev, "failed to get PHY: %d\n", err); + return err; + } + + udc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(udc->clk)) { + err = PTR_ERR(udc->clk); + dev_err(&pdev->dev, "failed to get clock: %d\n", err); + return err; + } + + err = clk_prepare_enable(udc->clk); + if (err < 0) { + dev_err(&pdev->dev, "failed to enable clock: %d\n", err); + return err; + } + + /* + * Tegra's USB PHY driver doesn't implement optional phy_init() + * hook, so we have to power on UDC controller before ChipIdea + * driver initialization kicks in. + */ + usb_phy_set_suspend(udc->phy, 0); + + /* setup and register ChipIdea HDRC device */ + udc->data.name = "tegra-udc"; + udc->data.flags = soc->flags; + udc->data.usb_phy = udc->phy; + udc->data.capoffset = DEF_CAPOFFSET; + + udc->dev = ci_hdrc_add_device(&pdev->dev, pdev->resource, + pdev->num_resources, &udc->data); + if (IS_ERR(udc->dev)) { + err = PTR_ERR(udc->dev); + dev_err(&pdev->dev, "failed to add HDRC device: %d\n", err); + goto fail_power_off; + } + + platform_set_drvdata(pdev, udc); + + return 0; + +fail_power_off: + usb_phy_set_suspend(udc->phy, 1); + clk_disable_unprepare(udc->clk); + return err; +} + +static int tegra_udc_remove(struct platform_device *pdev) +{ + struct tegra_udc *udc = platform_get_drvdata(pdev); + + usb_phy_set_suspend(udc->phy, 1); + clk_disable_unprepare(udc->clk); + + return 0; +} + +static struct platform_driver tegra_udc_driver = { + .driver = { + .name = "tegra-udc", + .of_match_table = tegra_udc_of_match, + }, + .probe = tegra_udc_probe, + .remove = tegra_udc_remove, +}; +module_platform_driver(tegra_udc_driver); + +MODULE_DESCRIPTION("NVIDIA Tegra USB device mode driver"); +MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); +MODULE_ALIAS("platform:tegra-udc"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index d162cc0bb8ce..99425db9ba62 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -52,6 +52,8 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev) if (!ci_pdata) { ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL); + if (!ci_pdata) + return -ENOMEM; *ci_pdata = ci_default_pdata; /* struct copy */ } diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index b17ed3a9a304..43ea5fb87b9a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -736,7 +736,7 @@ static int ci_extcon_register(struct ci_hdrc *ci) id = &ci->platdata->id_extcon; id->ci = ci; - if (!IS_ERR(id->edev)) { + if (!IS_ERR_OR_NULL(id->edev)) { ret = devm_extcon_register_notifier(ci->dev, id->edev, EXTCON_USB_HOST, &id->nb); if (ret < 0) { @@ -747,7 +747,7 @@ static int ci_extcon_register(struct ci_hdrc *ci) vbus = &ci->platdata->vbus_extcon; vbus->ci = ci; - if (!IS_ERR(vbus->edev)) { + if (!IS_ERR_OR_NULL(vbus->edev)) { ret = devm_extcon_register_notifier(ci->dev, vbus->edev, EXTCON_USB, &vbus->nb); if (ret < 0) { @@ -887,7 +887,7 @@ static struct attribute *ci_attrs[] = { NULL, }; -static struct attribute_group ci_attr_group = { +static const struct attribute_group ci_attr_group = { .attrs = ci_attrs, }; diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 949183ede16f..5ea0246f650d 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -193,7 +193,7 @@ static struct attribute *inputs_attrs[] = { NULL, }; -static struct attribute_group inputs_attr_group = { +static const struct attribute_group inputs_attr_group = { .name = "inputs", .attrs = inputs_attrs, }; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index d68b125796f9..fe8a90543ea3 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -944,7 +944,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) */ static int isr_setup_status_phase(struct ci_hdrc *ci) { - int retval; struct ci_hw_ep *hwep; /* @@ -960,9 +959,7 @@ static int isr_setup_status_phase(struct ci_hdrc *ci) ci->status->context = ci; ci->status->complete = isr_setup_status_complete; - retval = _ep_queue(&hwep->ep, ci->status, GFP_ATOMIC); - - return retval; + return _ep_queue(&hwep->ep, ci->status, GFP_ATOMIC); } /** @@ -1899,6 +1896,9 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.name = ci->platdata->name; ci->gadget.otg_caps = otg_caps; + if (ci->platdata->flags & CI_HDRC_REQUIRES_ALIGNED_DMA) + ci->gadget.quirk_avoids_skb_reserve = 1; + if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support || otg_caps->adp_support)) ci->gadget.is_otg = 1; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 8f972247b1c1..5aacea1978a5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -26,10 +26,6 @@ #include <asm/unaligned.h> #include <linux/usb/cdc-wdm.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.03" #define DRIVER_AUTHOR "Oliver Neukum" #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 578f424decc2..6ebfabfa0dc7 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1085,7 +1085,7 @@ static struct attribute *capability_attrs[] = { NULL, }; -static struct attribute_group capability_attr_grp = { +static const struct attribute_group capability_attr_grp = { .attrs = capability_attrs, }; @@ -1151,7 +1151,7 @@ static struct attribute *data_attrs[] = { NULL, }; -static struct attribute_group data_attr_grp = { +static const struct attribute_group data_attr_grp = { .attrs = data_attrs, }; diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 5ef8da6e67c3..552ff7ac5a6b 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -190,10 +190,7 @@ EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy); */ bool of_usb_host_tpl_support(struct device_node *np) { - if (of_find_property(np, "tpl-support", NULL)) - return true; - - return false; + return of_property_read_bool(np, "tpl-support"); } EXPORT_SYMBOL_GPL(of_usb_host_tpl_support); @@ -227,8 +224,8 @@ int of_usb_update_otg_caps(struct device_node *np, otg_caps->otg_rev = otg_rev; break; default: - pr_err("%s: unsupported otg-rev: 0x%x\n", - np->full_name, otg_rev); + pr_err("%pOF: unsupported otg-rev: 0x%x\n", + np, otg_rev); return -EINVAL; } } else { @@ -240,11 +237,11 @@ int of_usb_update_otg_caps(struct device_node *np, otg_caps->otg_rev = 0; } - if (of_find_property(np, "hnp-disable", NULL)) + if (of_property_read_bool(np, "hnp-disable")) otg_caps->hnp_support = false; - if (of_find_property(np, "srp-disable", NULL)) + if (of_property_read_bool(np, "srp-disable")) otg_caps->srp_support = false; - if (of_find_property(np, "adp-disable", NULL) || + if (of_property_read_bool(np, "adp-disable") || (otg_caps->otg_rev < 0x0200)) otg_caps->adp_support = false; diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 930e8f35f8df..4aa5195db8ea 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -135,7 +135,7 @@ static void ulpi_dev_release(struct device *dev) kfree(to_ulpi_dev(dev)); } -static struct device_type ulpi_dev_type = { +static const struct device_type ulpi_dev_type = { .name = "ulpi_device", .groups = ulpi_dev_attr_groups, .release = ulpi_dev_release, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ebe27595c4af..318bb3b96687 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -210,7 +210,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma) dec_usb_memory_use_count(usbm, &usbm->vma_use_count); } -static struct vm_operations_struct usbdev_vm_ops = { +static const struct vm_operations_struct usbdev_vm_ops = { .open = usbdev_vm_open, .close = usbdev_vm_close }; @@ -623,6 +623,8 @@ static void async_completed(struct urb *urb) if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && as->status != -ENOENT) cancel_bulk_urbs(ps, as->bulk_addr); + + wake_up(&ps->wait); spin_unlock(&ps->lock); if (signr) { @@ -630,8 +632,6 @@ static void async_completed(struct urb *urb) put_pid(pid); put_cred(cred); } - - wake_up(&ps->wait); } static void destroy_async(struct usb_dev_state *ps, struct list_head *list) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ab1bb3b538ac..75ad6718858c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -972,7 +972,7 @@ static struct attribute *usb_bus_attrs[] = { NULL, }; -static struct attribute_group usb_bus_attr_group = { +static const struct attribute_group usb_bus_attr_group = { .name = NULL, /* we want them in the same directory */ .attrs = usb_bus_attrs, }; @@ -1888,7 +1888,7 @@ void usb_hcd_flush_endpoint(struct usb_device *udev, /* No more submits can occur */ spin_lock_irq(&hcd_urb_list_lock); rescan: - list_for_each_entry (urb, &ep->urb_list, urb_list) { + list_for_each_entry_reverse(urb, &ep->urb_list, urb_list) { int is_in; if (urb->unlinked) @@ -2485,6 +2485,8 @@ void usb_hc_died (struct usb_hcd *hcd) } if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) { hcd = hcd->shared_hcd; + clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); + set_bit(HCD_FLAG_DEAD, &hcd->flags); if (hcd->rh_registered) { clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6e6797d145dd..41eaf0b52518 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2614,7 +2614,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) #define USE_NEW_SCHEME(i) ((i) / 2 == (int)old_scheme_first) -#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ +#define HUB_ROOT_RESET_TIME 60 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 #define HUB_BH_RESET_TIME 50 #define HUB_LONG_RESET_TIME 200 @@ -4342,6 +4342,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, enum usb_device_speed oldspeed = udev->speed; const char *speed; int devnum = udev->devnum; + const char *driver_name; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -4409,11 +4410,23 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, else speed = usb_speed_string(udev->speed); + /* + * The controller driver may be NULL if the controller device + * is the middle device between platform device and roothub. + * This middle device may not need a device driver due to + * all hardware control can be at platform device driver, this + * platform device is usually a dual-role USB controller device. + */ + if (udev->bus->controller->driver) + driver_name = udev->bus->controller->driver->name; + else + driver_name = udev->bus->sysdev->driver->name; + if (udev->speed < USB_SPEED_SUPER) dev_info(&udev->dev, "%s %s USB device number %d using %s\n", (udev->config) ? "reset" : "new", speed, - devnum, udev->bus->controller->driver->name); + devnum, driver_name); /* Set up TT records, if needed */ if (hdev->tt) { @@ -4545,7 +4558,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, "%s SuperSpeed%s USB device number %d using %s\n", (udev->config) ? "reset" : "new", (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "", - devnum, udev->bus->controller->driver->name); + devnum, driver_name); } /* cope with hardware quirkiness: @@ -4725,7 +4738,8 @@ hub_power_remaining(struct usb_hub *hub) static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) { - int status, i; + int status = -ENODEV; + int i; unsigned unit_load; struct usb_device *hdev = hub->hdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); @@ -4929,9 +4943,10 @@ loop: done: hub_port_disable(hub, port1, 1); - if (hcd->driver->relinquish_port && !hub->hdev->parent) - hcd->driver->relinquish_port(hcd, port1); - + if (hcd->driver->relinquish_port && !hub->hdev->parent) { + if (status != -ENOTCONN && status != -ENODEV) + hcd->driver->relinquish_port(hcd, port1); + } } /* Handle physical or logical connection change events. diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index 16c19a31dad1..1af877942110 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -149,8 +149,8 @@ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data, count = of_count_phandle_with_args(led_np, "trigger-sources", "#trigger-source-cells"); if (count < 0) { - dev_warn(dev, "Failed to get trigger sources for %s\n", - led_np->full_name); + dev_warn(dev, "Failed to get trigger sources for %pOF\n", + led_np); return false; } @@ -205,6 +205,7 @@ static int usbport_trig_add_port(struct usbport_trig_data *usbport_data, } snprintf(port->port_name, len, "%s-port%d", hub_name, portnum); + sysfs_attr_init(&port->attr.attr); port->attr.attr.name = port->port_name; port->attr.attr.mode = S_IRUSR | S_IWUSR; port->attr.show = usbport_trig_port_show; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 3116edfcdc18..82806e311202 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -57,8 +57,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Logitech HD Pro Webcams C920 and C930e */ + /* Logitech HD Pro Webcams C920, C920-C and C930e */ { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, /* Logitech ConferenceCam CC3000e */ @@ -150,6 +151,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* appletouch */ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */ + { USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM }, + /* Avision AV600U */ { USB_DEVICE(0x0638, 0x0a13), .driver_info = USB_QUIRK_STRING_FETCH_255 }, @@ -214,6 +218,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Corsair Strafe RGB */ + { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Acer C120 LED Projector */ { USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM }, @@ -249,6 +256,7 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = { { USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME }, { USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME }, { USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x03f0, 0x2b4a), .driver_info = USB_QUIRK_RESET_RESUME }, /* Logitech Optical Mouse M90/M100 */ { USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index dfc68ed24db1..d930bfda4010 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -113,7 +113,7 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr, { struct device_node *of_node = dev->of_node; - return sprintf(buf, "%s\n", of_node_full_name(of_node)); + return sprintf(buf, "%pOF\n", of_node); } static DEVICE_ATTR_RO(devspec); #endif diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index c4066cd77e47..0d8e09ccb59c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4179,7 +4179,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) return ret; } -static struct usb_ep_ops dwc2_hsotg_ep_ops = { +static const struct usb_ep_ops dwc2_hsotg_ep_ops = { .enable = dwc2_hsotg_ep_enable, .disable = dwc2_hsotg_ep_disable, .alloc_request = dwc2_hsotg_ep_alloc_request, diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 740c7e86d31b..c2631145f404 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4388,6 +4388,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&hsotg->lock, flags); + if (dwc2_is_device_mode(hsotg)) + goto unlock; + if (hsotg->lx_state != DWC2_L0) goto unlock; @@ -4446,6 +4449,9 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) spin_lock_irqsave(&hsotg->lock, flags); + if (dwc2_is_device_mode(hsotg)) + goto unlock; + if (hsotg->lx_state != DWC2_L2) goto unlock; diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 12ee23f53cdd..d2ed9523e77c 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -15,7 +15,6 @@ * GNU General Public License for more details. */ -#include <linux/clk.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> @@ -23,6 +22,7 @@ #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/of_platform.h> +#include <linux/pm_runtime.h> /* USBSS register offsets */ #define USBSS_REVISION 0x0000 @@ -41,7 +41,6 @@ struct dwc3_keystone { struct device *dev; - struct clk *clk; void __iomem *usbss; }; @@ -106,17 +105,13 @@ static int kdwc3_probe(struct platform_device *pdev) if (IS_ERR(kdwc->usbss)) return PTR_ERR(kdwc->usbss); - kdwc->clk = devm_clk_get(kdwc->dev, "usb"); - if (IS_ERR(kdwc->clk)) { - dev_err(kdwc->dev, "unable to get usb clock\n"); - return PTR_ERR(kdwc->clk); - } + pm_runtime_enable(kdwc->dev); - error = clk_prepare_enable(kdwc->clk); + error = pm_runtime_get_sync(kdwc->dev); if (error < 0) { - dev_err(kdwc->dev, "unable to enable usb clock, error %d\n", + dev_err(kdwc->dev, "pm_runtime_get_sync failed, error %d\n", error); - return error; + goto err_irq; } irq = platform_get_irq(pdev, 0); @@ -147,7 +142,8 @@ static int kdwc3_probe(struct platform_device *pdev) err_core: kdwc3_disable_irqs(kdwc); err_irq: - clk_disable_unprepare(kdwc->clk); + pm_runtime_put_sync(kdwc->dev); + pm_runtime_disable(kdwc->dev); return error; } @@ -167,7 +163,9 @@ static int kdwc3_remove(struct platform_device *pdev) kdwc3_disable_irqs(kdwc); device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); - clk_disable_unprepare(kdwc->clk); + pm_runtime_put_sync(kdwc->dev); + pm_runtime_disable(kdwc->dev); + platform_set_drvdata(pdev, NULL); return 0; diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index fe414e7a9c78..4cef7d4f9cd0 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -25,7 +25,6 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/clk.h> -#include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/pm_runtime.h> @@ -96,7 +95,8 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) platform_set_drvdata(pdev, simple); simple->dev = dev; - ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np)); + ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np, + "clocks", "#clock-cells")); if (ret) return ret; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index f5aaa0cf3873..3530795bbb8f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -478,8 +478,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "missing IRQ resource\n"); - return -EINVAL; + dev_err(dev, "missing IRQ resource: %d\n", irq); + return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 7e995df7a797..54343fbd85ee 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -345,7 +345,7 @@ static int dwc3_pci_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static struct dev_pm_ops dwc3_pci_dev_pm_ops = { +static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume, NULL) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6b299c7b7656..f064f1549333 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -896,9 +896,40 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, if (!node) { trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; + /* + * USB Specification 2.0 Section 5.9.2 states that: "If + * there is only a single transaction in the microframe, + * only a DATA0 data packet PID is used. If there are + * two transactions per microframe, DATA1 is used for + * the first transaction data packet and DATA0 is used + * for the second transaction data packet. If there are + * three transactions per microframe, DATA2 is used for + * the first transaction data packet, DATA1 is used for + * the second, and DATA0 is used for the third." + * + * IOW, we should satisfy the following cases: + * + * 1) length <= maxpacket + * - DATA0 + * + * 2) maxpacket < length <= (2 * maxpacket) + * - DATA1, DATA0 + * + * 3) (2 * maxpacket) < length <= (3 * maxpacket) + * - DATA2, DATA1, DATA0 + */ if (speed == USB_SPEED_HIGH) { struct usb_ep *ep = &dep->endpoint; - trb->size |= DWC3_TRB_SIZE_PCM1(ep->mult - 1); + unsigned int mult = ep->mult - 1; + unsigned int maxp = usb_endpoint_maxp(ep->desc); + + if (length <= (2 * maxp)) + mult--; + + if (length <= maxp) + mult--; + + trb->size |= DWC3_TRB_SIZE_PCM1(mult); } } else { trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 35cc641d9f31..31cce7805eb2 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -130,7 +130,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS config U_SERIAL_CONSOLE bool "Serial gadget console support" - depends on USB_G_SERIAL + depends on USB_U_SERIAL help It supports the serial gadget can be used as a console. diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d21874b35cf6..9990944a7245 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -961,10 +961,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) /* In the meantime, endpoint got disabled or changed. */ ret = -ESHUTDOWN; } else if (halt) { - /* Halt */ - if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) - usb_ep_set_halt(ep->ep); - ret = -EBADMSG; + ret = usb_ep_set_halt(ep->ep); + if (!ret) + ret = -EBADMSG; } else if (unlikely(data_len == -EINVAL)) { /* * Sanity Check: even though data_len can't be used diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 5eea44823ca0..d8e359ef6eb1 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -44,6 +44,7 @@ struct f_hidg { /* configuration */ unsigned char bInterfaceSubClass; unsigned char bInterfaceProtocol; + unsigned char protocol; unsigned short report_desc_length; char *report_desc; unsigned short report_length; @@ -527,7 +528,9 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_GET_PROTOCOL): VDBG(cdev, "get_protocol\n"); - goto stall; + length = min_t(unsigned int, length, 1); + ((u8 *) req->buf)[0] = hidg->protocol; + goto respond; break; case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 @@ -539,6 +542,17 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_SET_PROTOCOL): VDBG(cdev, "set_protocol\n"); + if (value > HID_REPORT_PROTOCOL) + goto stall; + length = 0; + /* + * We assume that programs implementing the Boot protocol + * are also compatible with the Report Protocol + */ + if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { + hidg->protocol = value; + goto respond; + } goto stall; break; @@ -768,6 +782,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; + hidg->protocol = HID_REPORT_PROTOCOL; hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_ss_in_comp_desc.wBytesPerInterval = cpu_to_le16(hidg->report_length); diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a5719f271bf0..5d3d7941d2c2 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -98,6 +98,7 @@ struct f_midi { DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); spinlock_t transmit_lock; unsigned int in_last_port; + unsigned char free_ref; struct gmidi_in_port in_ports_array[/* in_ports */]; }; @@ -108,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f) } static void f_midi_transmit(struct f_midi *midi); +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); @@ -163,6 +165,13 @@ static struct usb_endpoint_descriptor bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_ss_ep_comp_descriptor bulk_out_ss_comp_desc = { + .bLength = sizeof(bulk_out_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + /* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ static struct usb_ms_endpoint_descriptor_16 ms_out_desc = { /* .bLength = DYNAMIC */ @@ -180,6 +189,13 @@ static struct usb_endpoint_descriptor bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_ss_ep_comp_descriptor bulk_in_ss_comp_desc = { + .bLength = sizeof(bulk_in_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + /* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ static struct usb_ms_endpoint_descriptor_16 ms_in_desc = { /* .bLength = DYNAMIC */ @@ -755,13 +771,13 @@ static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) clear_bit(substream->number, &midi->out_triggered); } -static struct snd_rawmidi_ops gmidi_in_ops = { +static const struct snd_rawmidi_ops gmidi_in_ops = { .open = f_midi_in_open, .close = f_midi_in_close, .trigger = f_midi_in_trigger, }; -static struct snd_rawmidi_ops gmidi_out_ops = { +static const struct snd_rawmidi_ops gmidi_out_ops = { .open = f_midi_out_open, .close = f_midi_out_close, .trigger = f_midi_out_trigger @@ -818,6 +834,8 @@ static int f_midi_register_card(struct f_midi *midi) SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = midi; + rmidi->private_free = f_midi_rmidi_free; + midi->free_ref++; /* * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. @@ -853,7 +871,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_midi *midi = func_to_midi(f); struct usb_string *us; - int status, n, jack = 1, i = 0; + int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); @@ -895,7 +913,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail; /* allocate temporary function list */ - midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function), + midi_function = kcalloc((MAX_PORTS * 4) + 11, sizeof(*midi_function), GFP_KERNEL); if (!midi_function) { status = -ENOMEM; @@ -985,6 +1003,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) ms_in_desc.bNumEmbMIDIJack = midi->out_ports; /* ... and add them to the list */ + endpoint_descriptor_index = i; midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc; midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; @@ -1009,13 +1028,34 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail_f_midi; } + if (gadget_is_superspeed(c->cdev->gadget)) { + bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024); + bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024); + i = endpoint_descriptor_index; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_out_ss_comp_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &ms_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_in_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_in_ss_comp_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &ms_in_desc; + f->ss_descriptors = usb_copy_descriptors(midi_function); + if (!f->ss_descriptors) + goto fail_f_midi; + } + kfree(midi_function); return 0; fail_f_midi: kfree(midi_function); - usb_free_descriptors(f->hs_descriptors); + usb_free_all_descriptors(f); fail: f_midi_unregister_card(midi); fail_register: @@ -1197,14 +1237,21 @@ static void f_midi_free(struct usb_function *f) midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); - kfree(midi->id); mutex_lock(&opts->lock); - kfifo_free(&midi->in_req_fifo); - kfree(midi); - --opts->refcnt; + if (!--midi->free_ref) { + kfree(midi->id); + kfifo_free(&midi->in_req_fifo); + kfree(midi); + --opts->refcnt; + } mutex_unlock(&opts->lock); } +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi) +{ + f_midi_free(rmidi->private_data); +} + static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = f->config->cdev; @@ -1219,7 +1266,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) card = midi->card; midi->card = NULL; if (card) - snd_card_free(card); + snd_card_free_when_closed(card); usb_free_all_descriptors(f); } @@ -1263,6 +1310,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->buflen = opts->buflen; midi->qlen = opts->qlen; midi->in_last_port = 0; + midi->free_ref = 1; status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL); if (status) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 24e34cfcb4bd..45b334ceaf2e 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -925,8 +925,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) */ ncm->port.is_zlp_ok = gadget_is_zlp_supported(cdev->gadget); - ncm->port.no_skb_reserve = - gadget_avoids_skb_reserve(cdev->gadget); ncm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ncm\n"); net = gether_connect(&ncm->port); diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 16562e461121..e1d5853ef1e4 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -691,6 +691,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; } + rndis_iad_descriptor.bFunctionClass = rndis_opts->class; + rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; + rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; + /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, @@ -866,11 +870,23 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); /* f_rndis_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); +/* f_rndis_opts_class */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, class); + +/* f_rndis_opts_subclass */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); + +/* f_rndis_opts_protocol */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); + static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, &rndis_opts_attr_qmult, &rndis_opts_attr_ifname, + &rndis_opts_attr_class, + &rndis_opts_attr_subclass, + &rndis_opts_attr_protocol, NULL, }; @@ -916,6 +932,10 @@ static struct usb_function_instance *rndis_alloc_inst(void) } INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); + opts->class = rndis_iad_descriptor.bFunctionClass; + opts->subclass = rndis_iad_descriptor.bFunctionSubClass; + opts->protocol = rndis_iad_descriptor.bFunctionProtocol; + descs[0] = &opts->rndis_os_desc; names[0] = "rndis"; config_group_init_type_name(&opts->func_inst.group, "", diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 5dd73b9e5172..3971bbab88bd 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -79,7 +79,7 @@ struct snd_uac_chip { unsigned int p_framesize; }; -static struct snd_pcm_hardware uac_pcm_hardware = { +static const struct snd_pcm_hardware uac_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, @@ -354,7 +354,7 @@ static int uac_pcm_null(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops uac_pcm_ops = { +static const struct snd_pcm_ops uac_pcm_ops = { .open = uac_pcm_open, .close = uac_pcm_null, .ioctl = snd_pcm_lib_ioctl, diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index a8b40d07e927..bdbc3fdc7c4f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1073,7 +1073,7 @@ struct net_device *gether_connect(struct gether *link) if (result == 0) { dev->zlp = link->is_zlp_ok; - dev->no_skb_reserve = link->no_skb_reserve; + dev->no_skb_reserve = gadget_avoids_skb_reserve(dev->gadget); DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult)); dev->header_len = link->header_len; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 81d94a7ae4b4..c77145bd6b5b 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -64,7 +64,6 @@ struct gether { struct usb_ep *out_ep; bool is_zlp_ok; - bool no_skb_reserve; u16 cdc_filter; diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index c71133de17e7..e4c3f84af4c3 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -153,4 +153,39 @@ out: \ \ CONFIGFS_ATTR_RO(_f_##_opts_, ifname) +#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ + static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ + char *page) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret; \ + \ + mutex_lock(&opts->lock); \ + ret = sprintf(page, "%02x\n", opts->_n_); \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\ + const char *page, \ + size_t len) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret; \ + u8 val; \ + \ + mutex_lock(&opts->lock); \ + ret = sscanf(page, "%02hhx", &val); \ + if (ret > 0) { \ + opts->_n_ = val; \ + ret = len; \ + } \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, _n_) + #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 4eafd5050545..a35ee3c2545d 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -29,6 +29,10 @@ struct f_rndis_opts { struct usb_os_desc rndis_os_desc; char rndis_ext_compat_id[16]; + u8 class; + u8 subclass; + u8 protocol; + /* * Read/write access to configfs attributes is handled by configfs. * diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 9b0805f55ad7..4176216d54be 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -537,7 +537,7 @@ static void gs_rx_push(unsigned long _port) } /* push data to (open) tty */ - if (req->actual) { + if (req->actual && tty) { char *packet = req->buf; unsigned size = req->actual; unsigned n; diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index f9661cd627c8..82c13fce9232 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c @@ -436,5 +436,4 @@ module_usb_composite_driver(webcam_driver); MODULE_AUTHOR("Laurent Pinchart"); MODULE_DESCRIPTION("Webcam Video Gadget"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1.0"); diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig index eb8b55392360..c74ac25dddcd 100644 --- a/drivers/usb/gadget/udc/bdc/Kconfig +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -1,6 +1,7 @@ config USB_BDC_UDC tristate "Broadcom USB3.0 device controller IP driver(BDC)" depends on USB_GADGET && HAS_DMA + default ARCH_BRCMSTB help BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index 916d47135cac..6df0352cdc50 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -27,8 +27,8 @@ #include <linux/usb/gadget.h> #include <asm/unaligned.h> -#define BRCM_BDC_NAME "bdc_usb3" -#define BRCM_BDC_DESC "BDC device controller driver" +#define BRCM_BDC_NAME "bdc" +#define BRCM_BDC_DESC "Broadcom USB Device Controller driver" #define DMA_ADDR_INVALID (~(dma_addr_t)0) @@ -83,14 +83,14 @@ #define BDC_DVCSA 0x50 #define BDC_DVCSB 0x54 -#define BDC_EPSTS0(n) (0x60 + (n * 0x10)) -#define BDC_EPSTS1(n) (0x64 + (n * 0x10)) -#define BDC_EPSTS2(n) (0x68 + (n * 0x10)) -#define BDC_EPSTS3(n) (0x6c + (n * 0x10)) -#define BDC_EPSTS4(n) (0x70 + (n * 0x10)) -#define BDC_EPSTS5(n) (0x74 + (n * 0x10)) -#define BDC_EPSTS6(n) (0x78 + (n * 0x10)) -#define BDC_EPSTS7(n) (0x7c + (n * 0x10)) +#define BDC_EPSTS0 0x60 +#define BDC_EPSTS1 0x64 +#define BDC_EPSTS2 0x68 +#define BDC_EPSTS3 0x6c +#define BDC_EPSTS4 0x70 +#define BDC_EPSTS5 0x74 +#define BDC_EPSTS6 0x78 +#define BDC_EPSTS7 0x7c #define BDC_SRRBAL(n) (0x200 + (n * 0x10)) #define BDC_SRRBAH(n) (0x204 + (n * 0x10)) #define BDC_SRRINT(n) (0x208 + (n * 0x10)) @@ -413,6 +413,9 @@ struct bdc { /* device lock */ spinlock_t lock; + /* generic phy */ + struct phy **phys; + int num_phys; /* num of endpoints for a particular instantiation of IP */ unsigned int num_eps; /* @@ -454,6 +457,7 @@ struct bdc { * Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4 */ struct delayed_work func_wake_notify; + struct clk *clk; }; static inline u32 bdc_readl(void __iomem *base, u32 offset) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index e9bd8d4abca0..7a8af4b916cf 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -24,9 +24,11 @@ #include <linux/dma-mapping.h> #include <linux/dmapool.h> #include <linux/of.h> +#include <linux/phy/phy.h> #include <linux/moduleparam.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/clk.h> #include "bdc.h" #include "bdc_dbg.h" @@ -444,6 +446,43 @@ static int bdc_hw_init(struct bdc *bdc) return 0; } +static int bdc_phy_init(struct bdc *bdc) +{ + int phy_num; + int ret; + + for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { + ret = phy_init(bdc->phys[phy_num]); + if (ret) + goto err_exit_phy; + ret = phy_power_on(bdc->phys[phy_num]); + if (ret) { + phy_exit(bdc->phys[phy_num]); + goto err_exit_phy; + } + } + + return 0; + +err_exit_phy: + while (--phy_num >= 0) { + phy_power_off(bdc->phys[phy_num]); + phy_exit(bdc->phys[phy_num]); + } + + return ret; +} + +static void bdc_phy_exit(struct bdc *bdc) +{ + int phy_num; + + for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { + phy_power_off(bdc->phys[phy_num]); + phy_exit(bdc->phys[phy_num]); + } +} + static int bdc_probe(struct platform_device *pdev) { struct bdc *bdc; @@ -452,12 +491,29 @@ static int bdc_probe(struct platform_device *pdev) int irq; u32 temp; struct device *dev = &pdev->dev; + struct clk *clk; + int phy_num; dev_dbg(dev, "%s()\n", __func__); + + clk = devm_clk_get(dev, "sw_usbd"); + if (IS_ERR(clk)) { + dev_info(dev, "Clock not found in Device Tree\n"); + clk = NULL; + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "could not enable clock\n"); + return ret; + } + bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL); if (!bdc) return -ENOMEM; + bdc->clk = clk; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bdc->regs = devm_ioremap_resource(dev, res); if (IS_ERR(bdc->regs)) { @@ -473,35 +529,66 @@ static int bdc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bdc); bdc->irq = irq; bdc->dev = dev; - dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); + dev_dbg(dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); + + bdc->num_phys = of_count_phandle_with_args(dev->of_node, + "phys", "#phy-cells"); + if (bdc->num_phys > 0) { + bdc->phys = devm_kcalloc(dev, bdc->num_phys, + sizeof(struct phy *), GFP_KERNEL); + if (!bdc->phys) + return -ENOMEM; + } else { + bdc->num_phys = 0; + } + dev_info(dev, "Using %d phy(s)\n", bdc->num_phys); + + for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { + bdc->phys[phy_num] = devm_of_phy_get_by_index( + dev, dev->of_node, phy_num); + if (IS_ERR(bdc->phys[phy_num])) { + ret = PTR_ERR(bdc->phys[phy_num]); + dev_err(bdc->dev, + "BDC phy specified but not found:%d\n", ret); + return ret; + } + } + + ret = bdc_phy_init(bdc); + if (ret) { + dev_err(bdc->dev, "BDC phy init failure:%d\n", ret); + return ret; + } temp = bdc_readl(bdc->regs, BDC_BDCCAP1); if ((temp & BDC_P64) && !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { - dev_dbg(bdc->dev, "Using 64-bit address\n"); + dev_dbg(dev, "Using 64-bit address\n"); } else { - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) { - dev_err(bdc->dev, "No suitable DMA config available, abort\n"); + dev_err(dev, + "No suitable DMA config available, abort\n"); return -ENOTSUPP; } - dev_dbg(bdc->dev, "Using 32-bit address\n"); + dev_dbg(dev, "Using 32-bit address\n"); } ret = bdc_hw_init(bdc); if (ret) { - dev_err(bdc->dev, "BDC init failure:%d\n", ret); - return ret; + dev_err(dev, "BDC init failure:%d\n", ret); + goto phycleanup; } ret = bdc_udc_init(bdc); if (ret) { - dev_err(bdc->dev, "BDC Gadget init failure:%d\n", ret); + dev_err(dev, "BDC Gadget init failure:%d\n", ret); goto cleanup; } return 0; cleanup: bdc_hw_exit(bdc); - +phycleanup: + bdc_phy_exit(bdc); return ret; } @@ -513,13 +600,56 @@ static int bdc_remove(struct platform_device *pdev) dev_dbg(bdc->dev, "%s ()\n", __func__); bdc_udc_exit(bdc); bdc_hw_exit(bdc); + bdc_phy_exit(bdc); + clk_disable_unprepare(bdc->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bdc_suspend(struct device *dev) +{ + struct bdc *bdc = dev_get_drvdata(dev); + clk_disable_unprepare(bdc->clk); return 0; } +static int bdc_resume(struct device *dev) +{ + struct bdc *bdc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(bdc->clk); + if (ret) { + dev_err(bdc->dev, "err enabling the clock\n"); + return ret; + } + ret = bdc_reinit(bdc); + if (ret) { + dev_err(bdc->dev, "err in bdc reinit\n"); + return ret; + } + + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend, + bdc_resume); + +static const struct of_device_id bdc_of_match[] = { + { .compatible = "brcm,bdc-v0.16" }, + { .compatible = "brcm,bdc" }, + { /* sentinel */ } +}; + static struct platform_driver bdc_driver = { .driver = { .name = BRCM_BDC_NAME, + .owner = THIS_MODULE, + .pm = &bdc_pm_ops, + .of_match_table = bdc_of_match, }, .probe = bdc_probe, .remove = bdc_remove, diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c index 5945dbc47825..ac98f6f681b7 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_dbg.c +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c @@ -40,28 +40,28 @@ void bdc_dump_epsts(struct bdc *bdc) { u32 temp; - temp = bdc_readl(bdc->regs, BDC_EPSTS0(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS0); dev_vdbg(bdc->dev, "BDC_EPSTS0:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS1(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS1); dev_vdbg(bdc->dev, "BDC_EPSTS1:0x%x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS2(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS2); dev_vdbg(bdc->dev, "BDC_EPSTS2:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS3(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS3); dev_vdbg(bdc->dev, "BDC_EPSTS3:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS4(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS4); dev_vdbg(bdc->dev, "BDC_EPSTS4:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS5(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS5); dev_vdbg(bdc->dev, "BDC_EPSTS5:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS6(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS6); dev_vdbg(bdc->dev, "BDC_EPSTS6:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS7(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS7); dev_vdbg(bdc->dev, "BDC_EPSTS7:0x%08x\n", temp); } diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index ff1ef24d1777..bfd8f7ade935 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -777,9 +777,9 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) */ /* The current hw dequeue pointer */ - tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0)); + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0); deq_ptr_64 = tmp_32; - tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0)); + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1); deq_ptr_64 |= ((u64)tmp_32 << 32); /* we have the dma addr of next bd that will be fetched by hardware */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c index aae7458d8986..c84346146456 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_udc.c +++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c @@ -249,6 +249,7 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport) disconn = true; else if ((uspc & BDC_PCS) && !BDC_PST(uspc)) connected = true; + clear_flags |= BDC_PCC; } /* Change in VBus and VBus is present */ @@ -259,16 +260,16 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport) bdc_softconn(bdc); usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED); } - clear_flags = BDC_VBC; + clear_flags |= BDC_VBC; } else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) { /* Hot reset, warm reset, 2.0 bus reset or disconn */ dev_dbg(bdc->dev, "Port reset or disconn\n"); bdc_uspc_disconnected(bdc, disconn); - clear_flags = BDC_PCC|BDC_PCS|BDC_PRS|BDC_PRC; + clear_flags |= BDC_PRC; } else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) { /* Change in Link state */ handle_link_state_change(bdc, uspc); - clear_flags = BDC_PSC|BDC_PCS; + clear_flags |= BDC_PSC; } /* diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index e6f04eee95c4..75c51ca4ee0f 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -812,6 +812,8 @@ int usb_gadget_map_request_by_dev(struct device *dev, dev_err(dev, "failed to map buffer\n"); return -EFAULT; } + + req->dma_mapped = 1; } return 0; @@ -836,9 +838,10 @@ void usb_gadget_unmap_request_by_dev(struct device *dev, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->num_mapped_sgs = 0; - } else { + } else if (req->dma_mapped) { dma_unmap_single(dev, req->dma, req->length, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->dma_mapped = 0; } } EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); @@ -1130,6 +1133,7 @@ static int check_pending_gadget_drivers(struct usb_udc *udc) * @release: a gadget release function. * * Returns zero on success, negative errno otherwise. + * Calls the gadget release function in the latter case. */ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) @@ -1137,10 +1141,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, struct usb_udc *udc; int ret = -ENOMEM; - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - goto err1; - dev_set_name(&gadget->dev, "gadget"); INIT_WORK(&gadget->work, usb_gadget_state_work); gadget->dev.parent = parent; @@ -1150,7 +1150,13 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, else gadget->dev.release = usb_udc_nop_release; - ret = device_register(&gadget->dev); + device_initialize(&gadget->dev); + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto err1; + + ret = device_add(&gadget->dev); if (ret) goto err2; @@ -1197,10 +1203,10 @@ err3: device_del(&gadget->dev); err2: - put_device(&gadget->dev); kfree(udc); err1: + put_device(&gadget->dev); return ret; } EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 3c3760315910..a030d7923d7d 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2776,7 +2776,7 @@ static int __init init(void) if (retval < 0) { i--; while (i >= 0) - platform_device_del(the_udc_pdev[i]); + platform_device_del(the_udc_pdev[i--]); goto err_add_udc; } } diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 303328ce59ee..a3e72d690eef 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -62,7 +62,7 @@ static const char *const ep_name[] = { "ep3", }; -static struct usb_endpoint_descriptor qe_ep0_desc = { +static const struct usb_endpoint_descriptor qe_ep0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 8a708d0a1042..4103bf7cf52a 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -39,7 +39,6 @@ #include "mv_udc.h" #define DRIVER_DESC "Marvell PXA USB Device Controller driver" -#define DRIVER_VERSION "8 Nov 2010" #define ep_dir(ep) (((ep)->ep_num == 0) ? \ ((ep)->udc->ep0_dir) : ((ep)->direction)) @@ -2427,5 +2426,4 @@ module_platform_driver(udc_driver); MODULE_ALIAS("platform:mv-udc"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 62dc9c7798e7..df37c1e6e9d5 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -8,6 +8,7 @@ * the Free Software Foundation; version 2 of the License. */ +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/err.h> @@ -20,6 +21,8 @@ #include <linux/pm_runtime.h> #include <linux/sizes.h> #include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/uaccess.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -347,6 +350,7 @@ struct renesas_usb3 { bool workaround_for_vbus; bool extcon_host; /* check id and set EXTCON_USB_HOST */ bool extcon_usb; /* check vbus and set EXTCON_USB */ + bool forced_b_device; }; #define gadget_to_renesas_usb3(_gadget) \ @@ -663,7 +667,9 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev) spin_lock_irqsave(&usb3->lock, flags); usb3_set_mode(usb3, host); usb3_vbus_out(usb3, a_dev); - if (!host && a_dev) /* for A-Peripheral */ + /* for A-Peripheral or forced B-device mode */ + if ((!host && a_dev) || + (usb3->workaround_for_vbus && usb3->forced_b_device)) usb3_connect(usb3); spin_unlock_irqrestore(&usb3->lock, flags); } @@ -677,7 +683,7 @@ static void usb3_check_id(struct renesas_usb3 *usb3) { usb3->extcon_host = usb3_is_a_device(usb3); - if (usb3->extcon_host) + if (usb3->extcon_host && !usb3->forced_b_device) usb3_mode_config(usb3, true, true); else usb3_mode_config(usb3, false, false); @@ -838,21 +844,32 @@ static struct renesas_usb3_request *usb3_get_request(struct renesas_usb3_ep return usb3_req; } -static void usb3_request_done(struct renesas_usb3_ep *usb3_ep, - struct renesas_usb3_request *usb3_req, int status) +static void __usb3_request_done(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req, + int status) { struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); - unsigned long flags; dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n", usb3_ep->num, usb3_req->req.length, usb3_req->req.actual, status); usb3_req->req.status = status; - spin_lock_irqsave(&usb3->lock, flags); usb3_ep->started = false; list_del_init(&usb3_req->queue); - spin_unlock_irqrestore(&usb3->lock, flags); + spin_unlock(&usb3->lock); usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req); + spin_lock(&usb3->lock); +} + +static void usb3_request_done(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req, int status) +{ + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + unsigned long flags; + + spin_lock_irqsave(&usb3->lock, flags); + __usb3_request_done(usb3_ep, usb3_req, status); + spin_unlock_irqrestore(&usb3->lock, flags); } static void usb3_irq_epc_pipe0_status_end(struct renesas_usb3 *usb3) @@ -2181,7 +2198,7 @@ static void renesas_usb3_ep_fifo_flush(struct usb_ep *_ep) } } -static struct usb_ep_ops renesas_usb3_ep_ops = { +static const struct usb_ep_ops renesas_usb3_ep_ops = { .enable = renesas_usb3_ep_enable, .disable = renesas_usb3_ep_disable, @@ -2272,6 +2289,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, if (!usb3->driver) return -ENODEV; + if (usb3->forced_b_device) + return -EBUSY; + if (!strncmp(buf, "host", strlen("host"))) new_mode_is_host = true; else if (!strncmp(buf, "peripheral", strlen("peripheral"))) @@ -2299,6 +2319,70 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(role); +static int renesas_usb3_b_device_show(struct seq_file *s, void *unused) +{ + struct renesas_usb3 *usb3 = s->private; + + seq_printf(s, "%d\n", usb3->forced_b_device); + + return 0; +} + +static int renesas_usb3_b_device_open(struct inode *inode, struct file *file) +{ + return single_open(file, renesas_usb3_b_device_show, inode->i_private); +} + +static ssize_t renesas_usb3_b_device_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct renesas_usb3 *usb3 = s->private; + char buf[32]; + + if (!usb3->driver) + return -ENODEV; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1)) + usb3->forced_b_device = true; + else + usb3->forced_b_device = false; + + /* Let this driver call usb3_connect() anyway */ + usb3_check_id(usb3); + + return count; +} + +static const struct file_operations renesas_usb3_b_device_fops = { + .open = renesas_usb3_b_device_open, + .write = renesas_usb3_b_device_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, + struct device *dev) +{ + struct dentry *root, *file; + + root = debugfs_create_dir(dev_name(dev), NULL); + if (IS_ERR_OR_NULL(root)) { + dev_info(dev, "%s: Can't create the root\n", __func__); + return; + } + + file = debugfs_create_file("b_device", 0644, root, usb3, + &renesas_usb3_b_device_fops); + if (!file) + dev_info(dev, "%s: Can't create debugfs mode\n", __func__); +} + /*------- platform_driver ------------------------------------------------*/ static int renesas_usb3_remove(struct platform_device *pdev) { @@ -2421,22 +2505,40 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev, } } -static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795 = { +static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = { .ramsize_per_ramif = SZ_16K, .num_ramif = 2, .ramsize_per_pipe = SZ_4K, .workaround_for_vbus = true, }; +static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { + .ramsize_per_ramif = SZ_16K, + .num_ramif = 4, + .ramsize_per_pipe = SZ_4K, +}; + static const struct of_device_id usb3_of_match[] = { { .compatible = "renesas,r8a7795-usb3-peri", - .data = &renesas_usb3_priv_r8a7795, + .data = &renesas_usb3_priv_gen3, + }, + { + .compatible = "renesas,rcar-gen3-usb3-peri", + .data = &renesas_usb3_priv_gen3, }, { }, }; MODULE_DEVICE_TABLE(of, usb3_of_match); +static const struct soc_device_attribute renesas_usb3_quirks_match[] = { + { + .soc_id = "r8a7795", .revision = "ES1.*", + .data = &renesas_usb3_priv_r8a7795_es1, + }, + { /* sentinel */ }, +}; + static const unsigned int renesas_usb3_cable[] = { EXTCON_USB, EXTCON_USB_HOST, @@ -2450,15 +2552,23 @@ static int renesas_usb3_probe(struct platform_device *pdev) const struct of_device_id *match; int irq, ret; const struct renesas_usb3_priv *priv; + const struct soc_device_attribute *attr; match = of_match_node(usb3_of_match, pdev->dev.of_node); if (!match) return -ENODEV; - priv = match->data; + + attr = soc_device_match(renesas_usb3_quirks_match); + if (attr) + priv = attr->data; + else + priv = match->data; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); + return irq; + } usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); if (!usb3) @@ -2516,6 +2626,8 @@ static int renesas_usb3_probe(struct platform_device *pdev) usb3->workaround_for_vbus = priv->workaround_for_vbus; + renesas_usb3_debugfs_init(usb3, &pdev->dev); + dev_info(&pdev->dev, "probed\n"); return 0; diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 4643a01262b4..394abd5d65c0 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -51,7 +51,6 @@ #include "s3c2410_udc.h" #define DRIVER_DESC "S3C2410 USB Device Controller Gadget" -#define DRIVER_VERSION "29 Apr 2007" #define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \ "Arnaud Patard <arnaud.patard@rtp-net.org>" @@ -1996,7 +1995,7 @@ static int __init udc_init(void) { int retval; - dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION); + dprintk(DEBUG_NORMAL, "%s\n", gadget_name); s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL); if (IS_ERR(s3c2410_udc_debugfs_root)) { @@ -2027,5 +2026,4 @@ module_exit(udc_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index f7b4d0f159e4..e8a5fdaee37d 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -184,7 +184,7 @@ static int udc_plat_probe(struct platform_device *pdev) goto exit_phy; } - ret = extcon_get_cable_state_(udc->edev, EXTCON_USB); + ret = extcon_get_state(udc->edev, EXTCON_USB); if (ret < 0) { dev_err(dev, "Can't get cable state\n"); goto exit_extcon; @@ -273,7 +273,7 @@ static int udc_plat_suspend(struct device *dev) udc = dev_get_drvdata(dev); stop_udc(udc); - if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) { + if (extcon_get_state(udc->edev, EXTCON_USB) > 0) { dev_dbg(udc->dev, "device -> idle\n"); stop_udc(udc); } @@ -303,7 +303,7 @@ static int udc_plat_resume(struct device *dev) return ret; } - if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) { + if (extcon_get_state(udc->edev, EXTCON_USB) > 0) { dev_dbg(udc->dev, "idle -> device\n"); start_udc(udc); } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 4a08b70c81aa..d025cc06dda7 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -642,7 +642,7 @@ static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) #define ehci_start_port_reset NULL #endif /* CONFIG_USB_OTG */ -static struct ehci_driver_overrides ehci_fsl_overrides __initdata = { +static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = { .extra_priv_size = sizeof(struct ehci_fsl), .reset = ehci_fsl_setup, }; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 94ea9fff13e6..4d308533bc83 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -130,8 +130,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "EHCI irq failed\n"); - return -ENODEV; + dev_err(dev, "EHCI irq failed: %d\n", irq); + return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index e90ddb530765..ba557cdba8ef 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -55,8 +55,8 @@ static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np) return &dr_mode_data[i]; } } - pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n", - np->full_name); + pr_warn("%pOF: Invalid 'dr_mode' property, fallback to host mode\n", + np); return &dr_mode_data[0]; /* mode not specified, use host */ } diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 1db0626c8bf4..da3b18038d23 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -614,7 +614,7 @@ error: return result; } -static struct hc_driver hwahc_hc_driver = { +static const struct hc_driver hwahc_hc_driver = { .description = "hwa-hcd", .product_desc = "Wireless USB HWA host controller", .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd), @@ -860,7 +860,7 @@ static void hwahc_disconnect(struct usb_interface *usb_iface) usb_put_hcd(usb_hcd); } -static struct usb_device_id hwahc_id_table[] = { +static const struct usb_device_id hwahc_id_table[] = { /* Alereon 5310 */ { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01), .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC | diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index f542045dc2a6..39ae7fb64b6f 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1779,7 +1779,7 @@ static void imx21_hc_stop(struct usb_hcd *hcd) /* Driver glue */ /* =========================================== */ -static struct hc_driver imx21_hc_driver = { +static const struct hc_driver imx21_hc_driver = { .description = hcd_name, .product_desc = "IMX21 USB Host Controller", .hcd_priv_size = sizeof(struct imx21), @@ -1849,8 +1849,10 @@ static int imx21_probe(struct platform_device *pdev) if (!res) return -ENODEV; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); + return irq; + } hcd = usb_create_hcd(&imx21_hc_driver, &pdev->dev, dev_name(&pdev->dev)); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index d089b3fb7a13..73fec38754f9 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1511,7 +1511,7 @@ static int isp116x_bus_resume(struct usb_hcd *hcd) #endif -static struct hc_driver isp116x_hc_driver = { +static const struct hc_driver isp116x_hc_driver = { .description = hcd_name, .product_desc = "ISP116x Host Controller", .hcd_priv_size = sizeof(struct isp116x), diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 0f2b4b358e1a..9b7e307e2d54 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2591,7 +2591,7 @@ static int isp1362_hc_start(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -static struct hc_driver isp1362_hc_driver = { +static const struct hc_driver isp1362_hc_driver = { .description = hcd_name, .product_desc = "ISP1362 Host Controller", .hcd_priv_size = sizeof(struct isp1362_hcd), diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 369869a29ebd..0ece9a9341e5 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1811,7 +1811,7 @@ max3421_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { } -static struct hc_driver max3421_hcd_desc = { +static const struct hc_driver max3421_hcd_desc = { .description = "max3421", .product_desc = DRIVER_DESC, .hcd_priv_size = sizeof(struct max3421_hcd), diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c8989c62a262..658d9d1f9ea3 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -98,6 +98,7 @@ enum amd_chipset_gen { AMD_CHIPSET_HUDSON2, AMD_CHIPSET_BOLTON, AMD_CHIPSET_YANGTZE, + AMD_CHIPSET_TAISHAN, AMD_CHIPSET_UNKNOWN, }; @@ -145,20 +146,26 @@ static int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo) pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); - if (!pinfo->smbus_dev) { - pinfo->sb_type.gen = NOT_AMD_CHIPSET; - return 0; + if (pinfo->smbus_dev) { + rev = pinfo->smbus_dev->revision; + if (rev >= 0x11 && rev <= 0x14) + pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; + else if (rev >= 0x15 && rev <= 0x18) + pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; + else if (rev >= 0x39 && rev <= 0x3a) + pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; + } else { + pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + 0x145c, NULL); + if (pinfo->smbus_dev) { + rev = pinfo->smbus_dev->revision; + pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN; + } else { + pinfo->sb_type.gen = NOT_AMD_CHIPSET; + return 0; + } } - - rev = pinfo->smbus_dev->revision; - if (rev >= 0x11 && rev <= 0x14) - pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; - else if (rev >= 0x15 && rev <= 0x18) - pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; - else if (rev >= 0x39 && rev <= 0x3a) - pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; } - pinfo->sb_type.rev = rev; return 1; } @@ -260,11 +267,12 @@ int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev) { /* Make sure amd chipset type has already been initialized */ usb_amd_find_chipset_info(); - if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE) - return 0; - - dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n"); - return 1; + if (amd_chipset.sb_type.gen == AMD_CHIPSET_YANGTZE || + amd_chipset.sb_type.gen == AMD_CHIPSET_TAISHAN) { + dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n"); + return 1; + } + return 0; } EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk); @@ -1150,3 +1158,23 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); + +bool usb_xhci_needs_pci_reset(struct pci_dev *pdev) +{ + /* + * Our dear uPD72020{1,2} friend only partially resets when + * asked to via the XHCI interface, and may end up doing DMA + * at the wrong addresses, as it keeps the top 32bit of some + * addresses from its previous programming under obscure + * circumstances. + * Give it a good wack at probe time. Unfortunately, this + * needs to happen before we've had a chance to discover any + * quirk, or the system will be in a rather bad state. + */ + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + (pdev->device == 0x0014 || pdev->device == 0x0015)) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(usb_xhci_needs_pci_reset); diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 655994480198..5582cbafecd4 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -15,6 +15,7 @@ void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev); void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); void sb800_prefetch(struct device *dev, int on); +bool usb_xhci_needs_pci_reset(struct pci_dev *pdev); #else struct pci_dev; static inline void usb_amd_quirk_pll_disable(void) {} diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 7bf78be1fd32..5e5fc9d7d533 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2312,7 +2312,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) #define r8a66597_bus_resume NULL #endif -static struct hc_driver r8a66597_hc_driver = { +static const struct hc_driver r8a66597_hc_driver = { .description = hcd_name, .hcd_priv_size = sizeof(struct r8a66597), .irq = r8a66597_irq, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index fd2a11473be7..24ad1d6cec25 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1554,7 +1554,7 @@ sl811h_start(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -static struct hc_driver sl811h_hc_driver = { +static const struct hc_driver sl811h_hc_driver = { .description = hcd_name, .hcd_priv_size = sizeof(struct sl811), diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 43d52931b5bf..c38855aed62c 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2941,7 +2941,7 @@ static int u132_bus_resume(struct usb_hcd *hcd) #define u132_bus_suspend NULL #define u132_bus_resume NULL #endif -static struct hc_driver u132_hc_driver = { +static const struct hc_driver u132_hc_driver = { .description = hcd_name, .hcd_priv_size = sizeof(struct u132), .irq = NULL, diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 5b3603c360ab..cf84269c3e6d 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -213,7 +213,7 @@ static void whc_endpoint_reset(struct usb_hcd *usb_hcd, } -static struct hc_driver whc_hc_driver = { +static const struct hc_driver whc_hc_driver = { .description = "whci-hcd", .product_desc = "Wireless host controller", .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd), diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 00721e8807ab..ad89a6d4111b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1179,6 +1179,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; } + /* + * For xHCI 1.1 according to section 4.19.1.2.4.1 a + * root hub port's transition to compliance mode upon + * detecting LFPS timeout may be controlled by an + * Compliance Transition Enabled (CTE) flag (not + * software visible). This flag is set by writing 0xA + * to PORTSC PLS field which will allow transition to + * compliance mode the next time LFPS timeout is + * encountered. A warm reset will clear it. + * + * The CTE flag is only supported if the HCCPARAMS2 CTC + * flag is set, otherwise, the compliance substate is + * automatically entered as on 1.0 and prior. + */ + if (link_state == USB_SS_PORT_LS_COMP_MOD) { + if (!HCC2_CTC(xhci->hcc_params2)) { + xhci_dbg(xhci, "CTC flag is 0, port already supports entering compliance mode\n"); + break; + } + + if ((temp & PORT_CONNECT)) { + xhci_warn(xhci, "Can't set compliance mode when port is connected\n"); + goto error; + } + + xhci_dbg(xhci, "Enable compliance mode transition for port %d\n", + wIndex); + xhci_set_link_state(xhci, port_array, wIndex, + link_state); + temp = readl(port_array[wIndex]); + break; + } + /* Software should not attempt to set * port link state above '3' (U3) and the port * must be enabled. @@ -1521,15 +1554,14 @@ static bool xhci_port_missing_cas_quirk(int port_index, int xhci_bus_resume(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int max_ports, port_index; - __le32 __iomem **port_array; struct xhci_bus_state *bus_state; - u32 temp; + __le32 __iomem **port_array; unsigned long flags; - unsigned long port_was_suspended = 0; - bool need_usb2_u3_exit = false; + int max_ports, port_index; int slot_id; int sret; + u32 next_state; + u32 temp, portsc; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -1548,68 +1580,77 @@ int xhci_bus_resume(struct usb_hcd *hcd) temp &= ~CMD_EIE; writel(temp, &xhci->op_regs->command); + /* bus specific resume for ports we suspended at bus_suspend */ + if (hcd->speed >= HCD_USB3) + next_state = XDEV_U0; + else + next_state = XDEV_RESUME; + port_index = max_ports; while (port_index--) { - /* Check whether need resume ports. If needed - resume port and disable remote wakeup */ - u32 temp; - - temp = readl(port_array[port_index]); + portsc = readl(port_array[port_index]); /* warm reset CAS limited ports stuck in polling/compliance */ if ((xhci->quirks & XHCI_MISSING_CAS) && (hcd->speed >= HCD_USB3) && xhci_port_missing_cas_quirk(port_index, port_array)) { xhci_dbg(xhci, "reset stuck port %d\n", port_index); + clear_bit(port_index, &bus_state->bus_suspended); continue; } - if (DEV_SUPERSPEED_ANY(temp)) - temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); - else - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - if (test_bit(port_index, &bus_state->bus_suspended) && - (temp & PORT_PLS_MASK)) { - set_bit(port_index, &port_was_suspended); - if (!DEV_SUPERSPEED_ANY(temp)) { - xhci_set_link_state(xhci, port_array, - port_index, XDEV_RESUME); - need_usb2_u3_exit = true; + /* resume if we suspended the link, and it is still suspended */ + if (test_bit(port_index, &bus_state->bus_suspended)) + switch (portsc & PORT_PLS_MASK) { + case XDEV_U3: + portsc = xhci_port_state_to_neutral(portsc); + portsc &= ~PORT_PLS_MASK; + portsc |= PORT_LINK_STROBE | next_state; + break; + case XDEV_RESUME: + /* resume already initiated */ + break; + default: + /* not in a resumeable state, ignore it */ + clear_bit(port_index, + &bus_state->bus_suspended); + break; } - } else - writel(temp, port_array[port_index]); - } - - if (need_usb2_u3_exit) { - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(USB_RESUME_TIMEOUT); - spin_lock_irqsave(&xhci->lock, flags); + /* disable wake for all ports, write new link state if needed */ + portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); + writel(portsc, port_array[port_index]); } - port_index = max_ports; - while (port_index--) { - if (!(port_was_suspended & BIT(port_index))) - continue; - /* Clear PLC to poll it later after XDEV_U0 */ - xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC); - xhci_set_link_state(xhci, port_array, port_index, XDEV_U0); + /* USB2 specific resume signaling delay and U0 link state transition */ + if (hcd->speed < HCD_USB3) { + if (bus_state->bus_suspended) { + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(USB_RESUME_TIMEOUT); + spin_lock_irqsave(&xhci->lock, flags); + } + for_each_set_bit(port_index, &bus_state->bus_suspended, + BITS_PER_LONG) { + /* Clear PLC to poll it later for U0 transition */ + xhci_test_and_clear_bit(xhci, port_array, port_index, + PORT_PLC); + xhci_set_link_state(xhci, port_array, port_index, + XDEV_U0); + } } - port_index = max_ports; - while (port_index--) { - if (!(port_was_suspended & BIT(port_index))) - continue; - /* Poll and Clear PLC */ + /* poll for U0 link state complete, both USB2 and USB3 */ + for_each_set_bit(port_index, &bus_state->bus_suspended, BITS_PER_LONG) { sret = xhci_handshake(port_array[port_index], PORT_PLC, PORT_PLC, 10 * 1000); - if (sret) + if (sret) { xhci_warn(xhci, "port %d resume PLC timeout\n", port_index); + continue; + } xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC); slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) xhci_ring_device(xhci, slot_id); } - (void) readl(&xhci->op_regs->command); bus_state->next_statechange = jiffies + msecs_to_jiffies(5); diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 67d5dc79b6b5..8fb60657ed4f 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -795,6 +795,7 @@ static const struct dev_pm_ops xhci_mtk_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id mtk_xhci_of_match[] = { { .compatible = "mediatek,mt8173-xhci"}, + { .compatible = "mediatek,mtk-xhci"}, { }, }; MODULE_DEVICE_TABLE(of, mtk_xhci_of_match); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 5b0fa553c8bc..8071c8fdd15e 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -284,6 +284,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) driver = (struct hc_driver *)id->driver_data; + /* For some HW implementation, a XHCI reset is just not enough... */ + if (usb_xhci_needs_pci_reset(dev)) { + dev_info(&dev->dev, "Resetting\n"); + if (pci_reset_function_locked(dev)) + dev_warn(&dev->dev, "Reset failed"); + } + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index c04144b25a67..163bafde709f 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -107,14 +107,6 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { }; static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { - .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2, - .init_quirk = xhci_rcar_init_quirk, - .plat_start = xhci_rcar_start, - .resume_quirk = xhci_rcar_resume_quirk, -}; - -static const struct xhci_plat_priv xhci_plat_renesas_rcar_r8a7796 = { - .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3, .init_quirk = xhci_rcar_init_quirk, .plat_start = xhci_rcar_start, .resume_quirk = xhci_rcar_resume_quirk, @@ -145,7 +137,7 @@ static const struct of_device_id usb_xhci_of_match[] = { .data = &xhci_plat_renesas_rcar_gen3, }, { .compatible = "renesas,xhci-r8a7796", - .data = &xhci_plat_renesas_rcar_r8a7796, + .data = &xhci_plat_renesas_rcar_gen3, }, { .compatible = "renesas,rcar-gen2-xhci", .data = &xhci_plat_renesas_rcar_gen2, diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 07278228214b..198bc188ab25 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -13,13 +13,15 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/usb/phy.h> +#include <linux/sys_soc.h> #include "xhci.h" #include "xhci-plat.h" #include "xhci-rcar.h" /* -* - The V3 firmware is for r8a7796 (with good performance). +* - The V3 firmware is for r8a7796 (with good performance) and r8a7795 es2.0 +* or later. * - The V2 firmware can be used on both r8a7795 (es1.x) and r8a7796. * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes * performance degradation. So, this driver continues to use the V1 if R-Car @@ -67,6 +69,26 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); #define RCAR_USB3_RX_POL_VAL BIT(21) #define RCAR_USB3_TX_POL_VAL BIT(4) +/* For soc_device_attribute */ +#define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */ +#define RCAR_XHCI_FIRMWARE_V3 BIT(1) /* FIRMWARE V3 */ + +static const struct soc_device_attribute rcar_quirks_match[] = { + { + .soc_id = "r8a7795", .revision = "ES1.*", + .data = (void *)RCAR_XHCI_FIRMWARE_V2, + }, + { + .soc_id = "r8a7795", + .data = (void *)RCAR_XHCI_FIRMWARE_V3, + }, + { + .soc_id = "r8a7796", + .data = (void *)RCAR_XHCI_FIRMWARE_V3, + }, + { /* sentinel */ }, +}; + static void xhci_rcar_start_gen2(struct usb_hcd *hcd) { /* LCLK Select */ @@ -122,9 +144,23 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) int retval, index, j, time; int timeout = 10000; u32 data, val, temp; + u32 quirks = 0; + const struct soc_device_attribute *attr; + const char *firmware_name; + + attr = soc_device_match(rcar_quirks_match); + if (attr) + quirks = (uintptr_t)attr->data; + + if (quirks & RCAR_XHCI_FIRMWARE_V2) + firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; + else if (quirks & RCAR_XHCI_FIRMWARE_V3) + firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3; + else + firmware_name = priv->firmware_name; /* request R-Car USB3.0 firmware */ - retval = request_firmware(&fw, priv->firmware_name, dev); + retval = request_firmware(&fw, firmware_name, dev); if (retval) return retval; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cc368ad2b51e..a9443651ce0f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1572,7 +1572,7 @@ static void handle_port_status(struct xhci_hcd *xhci, { struct usb_hcd *hcd; u32 port_id; - u32 temp, temp1; + u32 portsc, cmd_reg; int max_ports; int slot_id; unsigned int faked_port_index; @@ -1636,26 +1636,28 @@ static void handle_port_status(struct xhci_hcd *xhci, /* Find the faked port hub number */ faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci, port_id); + portsc = readl(port_array[faked_port_index]); + + trace_xhci_handle_port_status(faked_port_index, portsc); - temp = readl(port_array[faked_port_index]); if (hcd->state == HC_STATE_SUSPENDED) { xhci_dbg(xhci, "resume root hub\n"); usb_hcd_resume_root_hub(hcd); } - if (hcd->speed >= HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE) + if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) bus_state->port_remote_wakeup &= ~(1 << faked_port_index); - if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { + if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { xhci_dbg(xhci, "port resume event for port %d\n", port_id); - temp1 = readl(&xhci->op_regs->command); - if (!(temp1 & CMD_RUN)) { + cmd_reg = readl(&xhci->op_regs->command); + if (!(cmd_reg & CMD_RUN)) { xhci_warn(xhci, "xHC is not running.\n"); goto cleanup; } - if (DEV_SUPERSPEED_ANY(temp)) { + if (DEV_SUPERSPEED_ANY(portsc)) { xhci_dbg(xhci, "remote wake SS port %d\n", port_id); /* Set a flag to say the port signaled remote wakeup, * so we can tell the difference between the end of @@ -1683,8 +1685,8 @@ static void handle_port_status(struct xhci_hcd *xhci, } } - if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 && - DEV_SUPERSPEED_ANY(temp)) { + if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_U0 && + DEV_SUPERSPEED_ANY(portsc)) { xhci_dbg(xhci, "resume SS port %d finished\n", port_id); /* We've just brought the device into U0 through either the * Resume state after a device remote wakeup, or through the @@ -1714,7 +1716,7 @@ static void handle_port_status(struct xhci_hcd *xhci, * RExit to a disconnect state). If so, let the the driver know it's * out of the RExit state. */ - if (!DEV_SUPERSPEED_ANY(temp) && + if (!DEV_SUPERSPEED_ANY(portsc) && test_and_clear_bit(faked_port_index, &bus_state->rexit_ports)) { complete(&bus_state->rexit_done[faked_port_index]); diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 8ce96de10e8a..f20753b99624 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -453,6 +453,29 @@ DEFINE_EVENT(xhci_log_ring, xhci_inc_deq, TP_PROTO(struct xhci_ring *ring), TP_ARGS(ring) ); + +DECLARE_EVENT_CLASS(xhci_log_portsc, + TP_PROTO(u32 portnum, u32 portsc), + TP_ARGS(portnum, portsc), + TP_STRUCT__entry( + __field(u32, portnum) + __field(u32, portsc) + ), + TP_fast_assign( + __entry->portnum = portnum; + __entry->portsc = portsc; + ), + TP_printk("port-%d: %s", + __entry->portnum, + xhci_decode_portsc(__entry->portsc) + ) +); + +DEFINE_EVENT(xhci_log_portsc, xhci_handle_port_status, + TP_PROTO(u32 portnum, u32 portsc), + TP_ARGS(portnum, portsc) +); + #endif /* __XHCI_TRACE_H */ /* this part must be outside header guard */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e3e935291ed6..2abaa4d6d39d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -311,12 +311,19 @@ struct xhci_op_regs { */ #define PORT_PLS_MASK (0xf << 5) #define XDEV_U0 (0x0 << 5) +#define XDEV_U1 (0x1 << 5) #define XDEV_U2 (0x2 << 5) #define XDEV_U3 (0x3 << 5) +#define XDEV_DISABLED (0x4 << 5) +#define XDEV_RXDETECT (0x5 << 5) #define XDEV_INACTIVE (0x6 << 5) #define XDEV_POLLING (0x7 << 5) -#define XDEV_COMP_MODE (0xa << 5) +#define XDEV_RECOVERY (0x8 << 5) +#define XDEV_HOT_RESET (0x9 << 5) +#define XDEV_COMP_MODE (0xa << 5) +#define XDEV_TEST_MODE (0xb << 5) #define XDEV_RESUME (0xf << 5) + /* true: port has power (see HCC_PPC) */ #define PORT_POWER (1 << 9) /* bits 10:13 indicate device speed: @@ -2392,6 +2399,87 @@ static inline const char *xhci_decode_slot_context(u32 info, u32 info2, return str; } + +static inline const char *xhci_portsc_link_state_string(u32 portsc) +{ + switch (portsc & PORT_PLS_MASK) { + case XDEV_U0: + return "U0"; + case XDEV_U1: + return "U1"; + case XDEV_U2: + return "U2"; + case XDEV_U3: + return "U3"; + case XDEV_DISABLED: + return "Disabled"; + case XDEV_RXDETECT: + return "RxDetect"; + case XDEV_INACTIVE: + return "Inactive"; + case XDEV_POLLING: + return "Polling"; + case XDEV_RECOVERY: + return "Recovery"; + case XDEV_HOT_RESET: + return "Hot Reset"; + case XDEV_COMP_MODE: + return "Compliance mode"; + case XDEV_TEST_MODE: + return "Test mode"; + case XDEV_RESUME: + return "Resume"; + default: + break; + } + return "Unknown"; +} + +static inline const char *xhci_decode_portsc(u32 portsc) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "%s %s %s Link:%s ", + portsc & PORT_POWER ? "Powered" : "Powered-off", + portsc & PORT_CONNECT ? "Connected" : "Not-connected", + portsc & PORT_PE ? "Enabled" : "Disabled", + xhci_portsc_link_state_string(portsc)); + + if (portsc & PORT_OC) + ret += sprintf(str + ret, "OverCurrent "); + if (portsc & PORT_RESET) + ret += sprintf(str + ret, "In-Reset "); + + ret += sprintf(str + ret, "Change: "); + if (portsc & PORT_CSC) + ret += sprintf(str + ret, "CSC "); + if (portsc & PORT_PEC) + ret += sprintf(str + ret, "PEC "); + if (portsc & PORT_WRC) + ret += sprintf(str + ret, "WRC "); + if (portsc & PORT_OCC) + ret += sprintf(str + ret, "OCC "); + if (portsc & PORT_RC) + ret += sprintf(str + ret, "PRC "); + if (portsc & PORT_PLC) + ret += sprintf(str + ret, "PLC "); + if (portsc & PORT_CEC) + ret += sprintf(str + ret, "CEC "); + if (portsc & PORT_CAS) + ret += sprintf(str + ret, "CAS "); + + ret += sprintf(str + ret, "Wake: "); + if (portsc & PORT_WKCONN_E) + ret += sprintf(str + ret, "WCE "); + if (portsc & PORT_WKDISC_E) + ret += sprintf(str + ret, "WDE "); + if (portsc & PORT_WKOC_E) + ret += sprintf(str + ret, "WOE "); + + return str; +} + static inline const char *xhci_ep_state_string(u8 state) { switch (state) { diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index a4dbb0cd80da..0b21ba757bba 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -137,10 +137,6 @@ #include "microtek.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4.3" #define DRIVER_AUTHOR "John Fremlin <vii@penguinpowered.com>, Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>" #define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver" diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index ac31d19cc54b..8e59e0c02b8a 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c @@ -396,7 +396,6 @@ static int handshake(struct usb_hcd *hcd, u32 reg, /* reset a non-running (STS_HALT == 1) controller */ static int ehci_reset(struct usb_hcd *hcd) { - int retval; struct isp1760_hcd *priv = hcd_to_priv(hcd); u32 command = reg_read32(hcd->regs, HC_USBCMD); @@ -405,9 +404,8 @@ static int ehci_reset(struct usb_hcd *hcd) reg_write32(hcd->regs, HC_USBCMD, command); hcd->state = HC_STATE_HALT; priv->next_statechange = jiffies; - retval = handshake(hcd, HC_USBCMD, - CMD_RESET, 0, 250 * 1000); - return retval; + + return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000); } static struct isp1760_qh *qh_alloc(gfp_t flags) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index dfd54ea4808f..1c0ada75c35d 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -29,8 +29,6 @@ #include <linux/mutex.h> #include <linux/uaccess.h> -/* Version Information */ -#define DRIVER_VERSION "v0.0.13" #define DRIVER_AUTHOR "John Homppi" #define DRIVER_DESC "adutux (see www.ontrak.net)" diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 15d4e64d3b65..abec6e604a62 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -42,12 +42,10 @@ static int chaoskey_rng_read(struct hwrng *rng, void *data, dev_err(&(usb_if)->dev, format, ## arg) /* Version Information */ -#define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Keith Packard, keithp@keithp.com" #define DRIVER_DESC "Altus Metrum ChaosKey driver" #define DRIVER_SHORT "chaoskey" -MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 9d8bb8dacdcd..63207c42acf6 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/usb.h> -#define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "Erik Rigtorp" #define DRIVER_DESC "Cypress USB Thermometer driver" diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 8291499d0581..424ff12f3b51 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -305,9 +305,9 @@ static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) { - int result; if (ftdi->platform_dev.dev.parent) return -EBUSY; + ftdi_elan_get_kref(ftdi); ftdi->platform_data.potpg = 100; ftdi->platform_data.reset = NULL; @@ -324,8 +324,8 @@ static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) request_module("u132_hcd"); dev_info(&ftdi->udev->dev, "registering '%s'\n", ftdi->platform_dev.name); - result = platform_device_register(&ftdi->platform_dev); - return result; + + return platform_device_register(&ftdi->platform_dev); } static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) @@ -857,7 +857,7 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi, target->actual = 0; target->non_null = (ed_length >> 15) & 0x0001; target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02) { + if (ed_type == 0x02 || ed_type == 0x03) { if (payload == 0 || target->abandoning > 0) { target->abandoning = 0; mutex_unlock(&ftdi->u132_lock); @@ -873,31 +873,6 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi, mutex_unlock(&ftdi->u132_lock); return b; } - } else if (ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else if (ed_type == 0x01) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; } else { target->abandoning = 0; mutex_unlock(&ftdi->u132_lock); diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 81fcbf024c65..39d8fedfaf3b 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -33,8 +33,6 @@ #define HEADER "P5 225 289 255 " #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) -/* version information */ -#define DRIVER_VERSION "0.6" #define DRIVER_SHORT "idmouse" #define DRIVER_AUTHOR "Florian 'Floe' Echtler <echtler@fs.tum.de>" #define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver" diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 7ca4c7e0ea0d..be5881303681 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -21,10 +21,8 @@ #include <linux/poll.h> #include <linux/usb/iowarrior.h> -/* Version Information */ -#define DRIVER_VERSION "v0.4.0" #define DRIVER_AUTHOR "Christian Lucht <lucht@codemercs.com>" -#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)" +#define DRIVER_DESC "USB IO-Warrior driver" #define USB_VENDOR_ID_CODEMERCS 1984 /* low speed iowarrior */ diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 9d9487c66f87..680bddb3ce05 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -112,7 +112,6 @@ static const struct usb_device_id ld_usb_table[] = { { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, ld_usb_table); -MODULE_VERSION("V0.14"); MODULE_AUTHOR("Michael Hund <mhund@ld-didactic.de>"); MODULE_DESCRIPTION("LD USB Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 0782ac6f5edf..5628f678ab59 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -88,8 +88,6 @@ #include <linux/poll.h> -/* Version Information */ -#define DRIVER_VERSION "v0.96" #define DRIVER_AUTHOR "Juergen Stuber <starblue@sourceforge.net>" #define DRIVER_DESC "LEGO USB Tower Driver" diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index 2142132a1f82..ddddd6387f66 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -178,6 +178,25 @@ static ssize_t hot_reset_store(struct device *dev, } static DEVICE_ATTR_WO(hot_reset); +static ssize_t warm_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + int ret; + + ret = lvs_rh_set_port_feature(hdev, lvs->portnum, + USB_PORT_FEAT_BH_PORT_RESET); + if (ret < 0) { + dev_err(dev, "can't issue warm reset %d\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(warm_reset); + static ssize_t u2_timeout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -274,13 +293,35 @@ free_desc: } static DEVICE_ATTR_WO(get_dev_desc); +static ssize_t enable_compliance_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *hdev = interface_to_usbdev(intf); + struct lvs_rh *lvs = usb_get_intfdata(intf); + int ret; + + ret = lvs_rh_set_port_feature(hdev, + lvs->portnum | USB_SS_PORT_LS_COMP_MOD << 3, + USB_PORT_FEAT_LINK_STATE); + if (ret < 0) { + dev_err(dev, "can't enable compliance mode %d\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(enable_compliance); + static struct attribute *lvs_attributes[] = { &dev_attr_get_dev_desc.attr, &dev_attr_u1_timeout.attr, &dev_attr_u2_timeout.attr, &dev_attr_hot_reset.attr, + &dev_attr_warm_reset.attr, &dev_attr_u3_entry.attr, &dev_attr_u3_exit.attr, + &dev_attr_enable_compliance.attr, NULL }; diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index b106ce76997b..ddfebb144aaa 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -43,10 +43,6 @@ #include "rio500_usb.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" #define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>" #define DRIVER_DESC "USB Rio 500 driver" diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 440d7fef58cc..30774e0aeadd 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -610,13 +610,11 @@ static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type, u32 addr, u8 data) { struct sisusb_packet packet; - int ret; packet.header = (1 << (addr & 3)) | (type << 6); packet.address = addr & ~3; packet.data = data << ((addr & 3) << 3); - ret = sisusb_send_packet(sisusb, 10, &packet); - return ret; + return sisusb_send_packet(sisusb, 10, &packet); } static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type, @@ -1333,13 +1331,11 @@ static int sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data) { struct sisusb_packet packet; - int ret; packet.header = 0x008f; packet.address = regnum | 0x10000; packet.data = data; - ret = sisusb_send_packet(sisusb, 10, &packet); - return ret; + return sisusb_send_packet(sisusb, 10, &packet); } static int sisusb_read_pci_config(struct sisusb_usb_data *sisusb, @@ -2982,14 +2978,11 @@ err_out: static long sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { - long retval; - switch (cmd) { case SISUSB_GET_CONFIG_SIZE: case SISUSB_GET_CONFIG: case SISUSB_COMMAND: - retval = sisusb_ioctl(f, cmd, arg); - return retval; + return sisusb_ioctl(f, cmd, arg); default: return -ENOIOCTLCMD; diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 9795457723d8..1862ed15ce28 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -25,8 +25,6 @@ #include <linux/module.h> #include <linux/usb.h> -/* Version Information */ -#define DRIVER_VERSION "v1.1" #define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org" #define DRIVER_DESC "PlayStation 2 Trance Vibrator driver" diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 91f66d68bcb7..135c91c434bf 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -114,7 +114,6 @@ #define DRIVER_NAME "usb251xb" #define DRIVER_DESC "Microchip USB 2.0 Hi-Speed Hub Controller" -#define DRIVER_VERSION "1.0" struct usb251xb { struct device *dev; diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index 388fae6373db..3f6a28045b53 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -330,7 +330,7 @@ static struct attribute *dev_attrs[] = { NULL }; -static struct attribute_group dev_attr_grp = { +static const struct attribute_group dev_attr_grp = { .attrs = dev_attrs, }; diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 5947373700a1..8a13b2fcf3e1 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -52,10 +52,6 @@ #include <linux/slab.h> #include <linux/sched/signal.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.6" #define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch" #define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip" @@ -816,8 +812,7 @@ static int __init uss720_init(void) if (retval) goto out; - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose " "driver to allow nonstandard\n"); printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over " diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 7b6dc23d77e9..b26fffc58446 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -288,6 +288,7 @@ static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev) * MTU3_U3_IP_SLOT_DEFAULT for U3 IP * @may_wakeup: means device's remote wakeup is enabled * @is_self_powered: is reported in device status and the config descriptor + * @delayed_status: true when function drivers ask for delayed status * @ep0_req: dummy request used while handling standard USB requests * for GET_STATUS and SET_SEL * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests @@ -327,6 +328,7 @@ struct mtu3 { unsigned u1_enable:1; unsigned u2_enable:1; unsigned is_u3_ip:1; + unsigned delayed_status:1; u8 address; u8 test_mode_nr; diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 11a0d3b84c5e..560256115b23 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c @@ -322,23 +322,65 @@ static const struct file_operations ssusb_mode_fops = { .release = single_release, }; +static int ssusb_vbus_show(struct seq_file *sf, void *unused) +{ + struct ssusb_mtk *ssusb = sf->private; + struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; + + seq_printf(sf, "vbus state: %s\n(echo on/off)\n", + regulator_is_enabled(otg_sx->vbus) ? "on" : "off"); + + return 0; +} + +static int ssusb_vbus_open(struct inode *inode, struct file *file) +{ + return single_open(file, ssusb_vbus_show, inode->i_private); +} + +static ssize_t ssusb_vbus_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *sf = file->private_data; + struct ssusb_mtk *ssusb = sf->private; + struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; + char buf[16]; + bool enable; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (kstrtobool(buf, &enable)) { + dev_err(ssusb->dev, "wrong setting\n"); + return -EINVAL; + } + + ssusb_set_vbus(otg_sx, enable); + + return count; +} + +static const struct file_operations ssusb_vbus_fops = { + .open = ssusb_vbus_open, + .write = ssusb_vbus_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void ssusb_debugfs_init(struct ssusb_mtk *ssusb) { struct dentry *root; - struct dentry *file; root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); - if (IS_ERR_OR_NULL(root)) { - if (!root) - dev_err(ssusb->dev, "create debugfs root failed\n"); + if (!root) { + dev_err(ssusb->dev, "create debugfs root failed\n"); return; } ssusb->dbgfs_root = root; - file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, - ssusb, &ssusb_mode_fops); - if (!file) - dev_dbg(ssusb->dev, "create debugfs mode failed\n"); + debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); + debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops); } static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 9dd2441b4fa1..434fca58143c 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -663,6 +663,7 @@ int mtu3_gadget_setup(struct mtu3 *mtu) mtu->g.sg_supported = 0; mtu->g.name = MTU3_DRIVER_NAME; mtu->is_active = 0; + mtu->delayed_status = false; mtu3_gadget_init_eps(mtu); @@ -727,4 +728,7 @@ void mtu3_gadget_reset(struct mtu3 *mtu) mtu->address = 0; mtu->ep0_state = MU3D_EP0_STATE_SETUP; mtu->may_wakeup = 0; + mtu->u1_enable = 0; + mtu->u2_enable = 0; + mtu->delayed_status = false; } diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 2d7427b48775..958d74dd2b78 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -16,6 +16,8 @@ * */ +#include <linux/usb/composite.h> + #include "mtu3.h" /* ep0 is always mtu3->in_eps[0] */ @@ -150,6 +152,7 @@ static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy) csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL; mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); + mtu->delayed_status = false; mtu->ep0_state = MU3D_EP0_STATE_SETUP; dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", @@ -656,6 +659,9 @@ stall: finish: if (mtu->test_mode) { ; /* nothing to do */ + } else if (handled == USB_GADGET_DELAYED_STATUS) { + /* handle the delay STATUS phase till receive ep_queue on ep0 */ + mtu->delayed_status = true; } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */ mtu3_writel(mbase, U3D_EP0CSR, @@ -775,9 +781,6 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__, mep->name, decode_ep0_state(mtu), mreq->request.length); - if (!list_empty(&mep->req_list)) - return -EBUSY; - switch (mtu->ep0_state) { case MU3D_EP0_STATE_SETUP: case MU3D_EP0_STATE_RX: /* control-OUT data */ @@ -789,6 +792,20 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) return -EINVAL; } + if (mtu->delayed_status) { + u32 csr; + + mtu->delayed_status = false; + csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; + csr |= EP0_SETUPPKTRDY | EP0_DATAEND; + mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); + /* needn't giveback the request for handling delay STATUS */ + return 0; + } + + if (!list_empty(&mep->req_list)) + return -EBUSY; + list_add_tail(&mreq->list, &mep->req_list); /* sequence #1, IN ... start writing the data */ diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c index cd4d01087855..e42d308b8dc2 100644 --- a/drivers/usb/mtu3/mtu3_host.c +++ b/drivers/usb/mtu3/mtu3_host.c @@ -258,8 +258,8 @@ int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn) ret = of_platform_populate(parent_dn, NULL, NULL, parent_dev); if (ret) { - dev_dbg(parent_dev, "failed to create child devices at %s\n", - parent_dn->full_name); + dev_dbg(parent_dev, "failed to create child devices at %pOF\n", + parent_dn); return ret; } diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 212367295276..06b29664470f 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -462,10 +462,12 @@ #define SSUSB_U3_PORT_DIS BIT(0) /* U3D_SSUSB_U2_CTRL_0P */ +#define SSUSB_U2_PORT_VBUSVALID BIT(9) #define SSUSB_U2_PORT_OTG_SEL BIT(7) -#define SSUSB_U2_PORT_HOST_SEL BIT(2) +#define SSUSB_U2_PORT_HOST BIT(2) #define SSUSB_U2_PORT_PDN BIT(1) #define SSUSB_U2_PORT_DIS BIT(0) +#define SSUSB_U2_PORT_HOST_SEL (SSUSB_U2_PORT_VBUSVALID | SSUSB_U2_PORT_HOST) /* U3D_SSUSB_DEV_RST_CTRL */ #define SSUSB_DEV_SW_RST BIT(0) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 0d3ebb353e08..088e3e685c4f 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -500,6 +500,7 @@ static const struct dev_pm_ops mtu3_pm_ops = { static const struct of_device_id mtu3_of_match[] = { {.compatible = "mediatek,mt8173-mtu3",}, + {.compatible = "mediatek,mtu3",}, {}, }; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 87cbd56cc761..029692053dd3 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1156,8 +1156,8 @@ static struct musb_fifo_cfg mode_2_cfg[] = { { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 960, }, +{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 1024, }, }; /* mode 3 - fits in 4KB */ @@ -2671,6 +2671,13 @@ static int musb_suspend(struct device *dev) { struct musb *musb = dev_to_musb(dev); unsigned long flags; + int ret; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } musb_platform_disable(musb); musb_disable_interrupts(musb); @@ -2721,14 +2728,6 @@ static int musb_resume(struct device *dev) if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; - /* - * The USB HUB code expects the device to be in RPM_ACTIVE once it came - * out of suspend - */ - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - musb_start(musb); spin_lock_irqsave(&musb->lock, flags); @@ -2738,6 +2737,9 @@ static int musb_resume(struct device *dev) error); spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; } diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 9f22c5b8ce37..c748f4ac1154 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -465,6 +465,30 @@ static inline struct musb *gadget_to_musb(struct usb_gadget *g) return container_of(g, struct musb, g); } +static inline char *musb_ep_xfertype_string(u8 type) +{ + char *s; + + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + s = "ctrl"; + break; + case USB_ENDPOINT_XFER_ISOC: + s = "iso"; + break; + case USB_ENDPOINT_XFER_BULK: + s = "bulk"; + break; + case USB_ENDPOINT_XFER_INT: + s = "int"; + break; + default: + s = ""; + break; + } + return s; +} + #ifdef CONFIG_BLACKFIN static inline int musb_read_fifosize(struct musb *musb, struct musb_hw_ep *hw_ep, u8 epnum) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index bc6a9be2ccc5..f6b526606ad1 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -1015,13 +1015,20 @@ static int dsps_suspend(struct device *dev) const struct dsps_musb_wrapper *wrp = glue->wrp; struct musb *musb = platform_get_drvdata(glue->musb); void __iomem *mbase; - - del_timer_sync(&glue->timer); + int ret; if (!musb) /* This can happen if the musb device is in -EPROBE_DEFER */ return 0; + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } + + del_timer_sync(&glue->timer); + mbase = musb->ctrl_base; glue->context.control = musb_readl(mbase, wrp->control); glue->context.epintr = musb_readl(mbase, wrp->epintr_set); @@ -1060,6 +1067,8 @@ static int dsps_resume(struct device *dev) musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) dsps_mod_timer(glue, -1); + pm_runtime_put(dev); + return 0; } #endif diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 1acc4864f9f6..bc6d1717c9ec 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1105,11 +1105,7 @@ static int musb_gadget_enable(struct usb_ep *ep, pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n", musb_driver_name, musb_ep->end_point.name, - ({ char *s; switch (musb_ep->type) { - case USB_ENDPOINT_XFER_BULK: s = "bulk"; break; - case USB_ENDPOINT_XFER_INT: s = "int"; break; - default: s = "iso"; break; - } s; }), + musb_ep_xfertype_string(musb_ep->type), musb_ep->is_in ? "IN" : "OUT", musb_ep->dma ? "dma, " : "", musb_ep->packet_sz); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 76decb8011eb..b17450a59882 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -139,6 +139,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) "Could not flush host TX%d fifo: csr: %04x\n", ep->epnum, csr)) return; + mdelay(1); } } @@ -2151,6 +2152,10 @@ static int musb_schedule( (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4; goto success; } else if (best_end < 0) { + dev_err(musb->controller, + "%s hwep alloc failed for %dx%d\n", + musb_ep_xfertype_string(qh->type), + qh->hb_mult, qh->maxpacket); return -ENOSPC; } @@ -2243,6 +2248,10 @@ static int musb_urb_enqueue( ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx) || (usb_pipeout(urb->pipe) && musb->hb_iso_tx); if (!ok) { + dev_err(musb->controller, + "high bandwidth %s (%dx%d) not supported\n", + musb_ep_xfertype_string(qh->type), + qh->hb_mult, qh->maxpacket & 0x7ff); ret = -EMSGSIZE; goto done; } diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8fb86a5f458e..3d0dd2f97415 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -197,6 +197,7 @@ struct msm_otg { struct regulator *v3p3; struct regulator *v1p8; struct regulator *vddcx; + struct regulator_bulk_data supplies[3]; struct reset_control *phy_rst; struct reset_control *link_rst; @@ -1731,7 +1732,6 @@ static int msm_otg_reboot_notify(struct notifier_block *this, static int msm_otg_probe(struct platform_device *pdev) { - struct regulator_bulk_data regs[3]; int ret = 0; struct device_node *np = pdev->dev.of_node; struct msm_otg_platform_data *pdata; @@ -1817,17 +1817,18 @@ static int msm_otg_probe(struct platform_device *pdev) return motg->irq; } - regs[0].supply = "vddcx"; - regs[1].supply = "v3p3"; - regs[2].supply = "v1p8"; + motg->supplies[0].supply = "vddcx"; + motg->supplies[1].supply = "v3p3"; + motg->supplies[2].supply = "v1p8"; - ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); + ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(motg->supplies), + motg->supplies); if (ret) return ret; - motg->vddcx = regs[0].consumer; - motg->v3p3 = regs[1].consumer; - motg->v1p8 = regs[2].consumer; + motg->vddcx = motg->supplies[0].consumer; + motg->v3p3 = motg->supplies[1].consumer; + motg->v1p8 = motg->supplies[2].consumer; clk_set_rate(motg->clk, 60000000); diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 697a741a0cb1..0e315694adc9 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -29,10 +29,8 @@ #include "phy-mv-usb.h" #define DRIVER_DESC "Marvell USB OTG transceiver driver" -#define DRIVER_VERSION "Jan 20, 2010" MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); static const char driver_name[] = "mv-otg"; @@ -650,7 +648,7 @@ static struct attribute *inputs_attrs[] = { NULL, }; -static struct attribute_group inputs_attr_group = { +static const struct attribute_group inputs_attr_group = { .name = "inputs", .attrs = inputs_attrs, }; diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index b6a83a5cbad3..679afeaaa9a8 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -270,12 +270,9 @@ static int phy_8x16_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qphy); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!qphy->regs) - return -ENOMEM; + qphy->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(qphy->regs)) + return PTR_ERR(qphy->regs); phy = &qphy->phy; phy->dev = &pdev->dev; diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index a31c8682e998..8babd318c0ed 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -326,7 +326,7 @@ static struct attribute *tahvo_attributes[] = { NULL }; -static struct attribute_group tahvo_attr_group = { +static const struct attribute_group tahvo_attr_group = { .attrs = tahvo_attributes, }; diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 032f5afaad4b..89f4ac4cd93e 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -18,6 +18,18 @@ #include <linux/usb/phy.h> +/* Default current range by charger type. */ +#define DEFAULT_SDP_CUR_MIN 2 +#define DEFAULT_SDP_CUR_MAX 500 +#define DEFAULT_SDP_CUR_MIN_SS 150 +#define DEFAULT_SDP_CUR_MAX_SS 900 +#define DEFAULT_DCP_CUR_MIN 500 +#define DEFAULT_DCP_CUR_MAX 5000 +#define DEFAULT_CDP_CUR_MIN 1500 +#define DEFAULT_CDP_CUR_MAX 5000 +#define DEFAULT_ACA_CUR_MIN 1500 +#define DEFAULT_ACA_CUR_MAX 5000 + static LIST_HEAD(phy_list); static LIST_HEAD(phy_bind_list); static DEFINE_SPINLOCK(phy_lock); @@ -77,6 +89,221 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node) return ERR_PTR(-EPROBE_DEFER); } +static void usb_phy_set_default_current(struct usb_phy *usb_phy) +{ + usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN; + usb_phy->chg_cur.sdp_max = DEFAULT_SDP_CUR_MAX; + usb_phy->chg_cur.dcp_min = DEFAULT_DCP_CUR_MIN; + usb_phy->chg_cur.dcp_max = DEFAULT_DCP_CUR_MAX; + usb_phy->chg_cur.cdp_min = DEFAULT_CDP_CUR_MIN; + usb_phy->chg_cur.cdp_max = DEFAULT_CDP_CUR_MAX; + usb_phy->chg_cur.aca_min = DEFAULT_ACA_CUR_MIN; + usb_phy->chg_cur.aca_max = DEFAULT_ACA_CUR_MAX; +} + +/** + * usb_phy_notify_charger_work - notify the USB charger state + * @work - the charger work to notify the USB charger state + * + * This work can be issued when USB charger state has been changed or + * USB charger current has been changed, then we can notify the current + * what can be drawn to power user and the charger state to userspace. + * + * If we get the charger type from extcon subsystem, we can notify the + * charger state to power user automatically by usb_phy_get_charger_type() + * issuing from extcon subsystem. + * + * If we get the charger type from ->charger_detect() instead of extcon + * subsystem, the usb phy driver should issue usb_phy_set_charger_state() + * to set charger state when the charger state has been changed. + */ +static void usb_phy_notify_charger_work(struct work_struct *work) +{ + struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work); + char uchger_state[50] = { 0 }; + char *envp[] = { uchger_state, NULL }; + unsigned int min, max; + + switch (usb_phy->chg_state) { + case USB_CHARGER_PRESENT: + usb_phy_get_charger_current(usb_phy, &min, &max); + + atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); + snprintf(uchger_state, ARRAY_SIZE(uchger_state), + "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT"); + break; + case USB_CHARGER_ABSENT: + usb_phy_set_default_current(usb_phy); + + atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); + snprintf(uchger_state, ARRAY_SIZE(uchger_state), + "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT"); + break; + default: + dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", + usb_phy->chg_state); + return; + } + + kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp); +} + +static void __usb_phy_get_charger_type(struct usb_phy *usb_phy) +{ + if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_SDP) > 0) { + usb_phy->chg_type = SDP_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_CDP) > 0) { + usb_phy->chg_type = CDP_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_DCP) > 0) { + usb_phy->chg_type = DCP_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_ACA) > 0) { + usb_phy->chg_type = ACA_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else { + usb_phy->chg_type = UNKNOWN_TYPE; + usb_phy->chg_state = USB_CHARGER_ABSENT; + } + + schedule_work(&usb_phy->chg_work); +} + +/** + * usb_phy_get_charger_type - get charger type from extcon subsystem + * @nb -the notifier block to determine charger type + * @state - the cable state + * @data - private data + * + * Determin the charger type from extcon subsystem which also means the + * charger state has been chaned, then we should notify this event. + */ +static int usb_phy_get_charger_type(struct notifier_block *nb, + unsigned long state, void *data) +{ + struct usb_phy *usb_phy = container_of(nb, struct usb_phy, type_nb); + + __usb_phy_get_charger_type(usb_phy); + return NOTIFY_OK; +} + +/** + * usb_phy_set_charger_current - set the USB charger current + * @usb_phy - the USB phy to be used + * @mA - the current need to be set + * + * Usually we only change the charger default current when USB finished the + * enumeration as one SDP charger. As one SDP charger, usb_phy_set_power() + * will issue this function to change charger current when after setting USB + * configuration, or suspend/resume USB. For other type charger, we should + * use the default charger current and we do not suggest to issue this function + * to change the charger current. + * + * When USB charger current has been changed, we need to notify the power users. + */ +void usb_phy_set_charger_current(struct usb_phy *usb_phy, unsigned int mA) +{ + switch (usb_phy->chg_type) { + case SDP_TYPE: + if (usb_phy->chg_cur.sdp_max == mA) + return; + + usb_phy->chg_cur.sdp_max = (mA > DEFAULT_SDP_CUR_MAX_SS) ? + DEFAULT_SDP_CUR_MAX_SS : mA; + break; + case DCP_TYPE: + if (usb_phy->chg_cur.dcp_max == mA) + return; + + usb_phy->chg_cur.dcp_max = (mA > DEFAULT_DCP_CUR_MAX) ? + DEFAULT_DCP_CUR_MAX : mA; + break; + case CDP_TYPE: + if (usb_phy->chg_cur.cdp_max == mA) + return; + + usb_phy->chg_cur.cdp_max = (mA > DEFAULT_CDP_CUR_MAX) ? + DEFAULT_CDP_CUR_MAX : mA; + break; + case ACA_TYPE: + if (usb_phy->chg_cur.aca_max == mA) + return; + + usb_phy->chg_cur.aca_max = (mA > DEFAULT_ACA_CUR_MAX) ? + DEFAULT_ACA_CUR_MAX : mA; + break; + default: + return; + } + + schedule_work(&usb_phy->chg_work); +} +EXPORT_SYMBOL_GPL(usb_phy_set_charger_current); + +/** + * usb_phy_get_charger_current - get the USB charger current + * @usb_phy - the USB phy to be used + * @min - the minimum current + * @max - the maximum current + * + * Usually we will notify the maximum current to power user, but for some + * special case, power user also need the minimum current value. Then the + * power user can issue this function to get the suitable current. + */ +void usb_phy_get_charger_current(struct usb_phy *usb_phy, + unsigned int *min, unsigned int *max) +{ + switch (usb_phy->chg_type) { + case SDP_TYPE: + *min = usb_phy->chg_cur.sdp_min; + *max = usb_phy->chg_cur.sdp_max; + break; + case DCP_TYPE: + *min = usb_phy->chg_cur.dcp_min; + *max = usb_phy->chg_cur.dcp_max; + break; + case CDP_TYPE: + *min = usb_phy->chg_cur.cdp_min; + *max = usb_phy->chg_cur.cdp_max; + break; + case ACA_TYPE: + *min = usb_phy->chg_cur.aca_min; + *max = usb_phy->chg_cur.aca_max; + break; + default: + *min = 0; + *max = 0; + break; + } +} +EXPORT_SYMBOL_GPL(usb_phy_get_charger_current); + +/** + * usb_phy_set_charger_state - set the USB charger state + * @usb_phy - the USB phy to be used + * @state - the new state need to be set for charger + * + * The usb phy driver can issue this function when the usb phy driver + * detected the charger state has been changed, in this case the charger + * type should be get from ->charger_detect(). + */ +void usb_phy_set_charger_state(struct usb_phy *usb_phy, + enum usb_charger_state state) +{ + if (usb_phy->chg_state == state || !usb_phy->charger_detect) + return; + + usb_phy->chg_state = state; + if (usb_phy->chg_state == USB_CHARGER_PRESENT) + usb_phy->chg_type = usb_phy->charger_detect(usb_phy); + else + usb_phy->chg_type = UNKNOWN_TYPE; + + schedule_work(&usb_phy->chg_work); +} +EXPORT_SYMBOL_GPL(usb_phy_set_charger_state); + static void devm_usb_phy_release(struct device *dev, void *res) { struct usb_phy *phy = *(struct usb_phy **)res; @@ -124,6 +351,44 @@ static int usb_add_extcon(struct usb_phy *x) "register VBUS notifier failed\n"); return ret; } + } else { + x->type_nb.notifier_call = usb_phy_get_charger_type; + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_SDP, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB SDP failed.\n"); + return ret; + } + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_CDP, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB CDP failed.\n"); + return ret; + } + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_DCP, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB DCP failed.\n"); + return ret; + } + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_ACA, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB ACA failed.\n"); + return ret; + } } if (x->id_nb.notifier_call) { @@ -145,6 +410,13 @@ static int usb_add_extcon(struct usb_phy *x) } } + usb_phy_set_default_current(x); + INIT_WORK(&x->chg_work, usb_phy_notify_charger_work); + x->chg_type = UNKNOWN_TYPE; + x->chg_state = USB_CHARGER_DEFAULT; + if (x->type_nb.notifier_call) + __usb_phy_get_charger_type(x); + return 0; } @@ -302,8 +574,8 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, node = of_parse_phandle(dev->of_node, phandle, index); if (!node) { - dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, - dev->of_node->full_name); + dev_dbg(dev, "failed to get %s phandle in %pOF node\n", phandle, + dev->of_node); return ERR_PTR(-ENODEV); } phy = devm_usb_get_phy_by_node(dev, node, NULL); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 93fba9033b00..c068b673420b 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -639,14 +639,11 @@ static int usbhsg_ep_disable(struct usb_ep *ep) struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhs_pipe *pipe; unsigned long flags; - int ret = 0; spin_lock_irqsave(&uep->lock, flags); pipe = usbhsg_uep_to_pipe(uep); - if (!pipe) { - ret = -EINVAL; + if (!pipe) goto out; - } usbhsg_pipe_disable(uep); usbhs_pipe_free(pipe); @@ -767,7 +764,7 @@ static int usbhsg_ep_set_wedge(struct usb_ep *ep) return __usbhsg_ep_set_halt_wedge(ep, 1, 1); } -static struct usb_ep_ops usbhsg_ep_ops = { +static const struct usb_ep_ops usbhsg_ep_ops = { .enable = usbhsg_ep_enable, .disable = usbhsg_ep_disable, @@ -1085,7 +1082,6 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; } - spin_lock_init(&uep->lock); gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); dev_info(dev, "%stransceiver found\n", @@ -1135,6 +1131,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) uep->ep.name = uep->ep_name; uep->ep.ops = &usbhsg_ep_ops; INIT_LIST_HEAD(&uep->ep.ep_list); + spin_lock_init(&uep->lock); /* init DCP */ if (usbhsg_is_dcp(uep)) { diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index dfb346e9bd0c..e256351cb72d 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1285,7 +1285,7 @@ static int usbhsh_bus_nop(struct usb_hcd *hcd) return 0; } -static struct hc_driver usbhsh_driver = { +static const struct hc_driver usbhsh_driver = { .description = usbhsh_hcd_name, .hcd_priv_size = sizeof(struct usbhsh_hpriv), diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 9396a8c14af8..d811f0550c04 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -401,7 +401,7 @@ static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host, u16 dir = 0; u16 epnum = 0; u16 shtnak = 0; - u16 type_array[] = { + static const u16 type_array[] = { [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, [USB_ENDPOINT_XFER_INT] = TYPE_INT, [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index d544b331c9f2..02b67abfc2a1 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -20,9 +20,13 @@ /* Low Power Status register (LPSTS) */ #define LPSTS_SUSPM 0x4000 -/* USB General control register 2 (UGCTRL2), bit[31:6] should be 0 */ +/* + * USB General control register 2 (UGCTRL2) + * Remarks: bit[31:11] and bit[9:6] should be 0 + */ #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ #define UGCTRL2_USB0SEL_OTG 0x00000030 +#define UGCTRL2_VBUSSEL 0x00000400 static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data) { @@ -34,7 +38,8 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG); + usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG | + UGCTRL2_VBUSSEL); if (enable) { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index f64e914a8985..2d945c9f975c 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -142,6 +142,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */ { USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */ + { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ebe51f11105d..54bfef13966a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2016,15 +2016,15 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000), /* TP-Link MA260 */ .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, + { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d01, 0xff) }, /* D-Link DWM-156 (variant) */ + { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d02, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d03, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */ + { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) }, /* D-Link DWM-157 C1 */ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */ .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index c9ebefd8f35f..a585b477415d 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -52,6 +52,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485), + .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 09d9be88209e..3b5a15d1dc0d 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -27,6 +27,7 @@ #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 +#define ATEN_PRODUCT_UC485 0x2021 #define ATEN_PRODUCT_ID2 0x2118 #define IODATA_VENDOR_ID 0x04bb diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 4176d1af9bf2..ec83b3b5efa9 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -47,7 +47,6 @@ MODULE_DESCRIPTION("Driver for Realtek USB Card Reader"); MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>"); MODULE_LICENSE("GPL"); -MODULE_VERSION("1.03"); static int auto_delink_en = 1; module_param(auto_delink_en, int, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index cbea9f329e71..cde115359793 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -124,9 +124,9 @@ UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999, /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */ UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, "Initio Corporation", - "", + "INIC-3069", USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), + US_FL_NO_ATA_1X | US_FL_IGNORE_RESIDUE), /* Reported-by: Tom Arild Naess <tanaess@gmail.com> */ UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 06615934fed1..0dceb9fa3a06 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -315,6 +315,7 @@ static int usb_stor_control_thread(void * __us) { struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); + struct scsi_cmnd *srb; for (;;) { usb_stor_dbg(us, "*** thread sleeping\n"); @@ -330,6 +331,7 @@ static int usb_stor_control_thread(void * __us) scsi_lock(host); /* When we are called with no command pending, we're done */ + srb = us->srb; if (us->srb == NULL) { scsi_unlock(host); mutex_unlock(&us->dev_mutex); @@ -398,14 +400,11 @@ static int usb_stor_control_thread(void * __us) /* lock access to the state */ scsi_lock(host); - /* indicate that the command is done */ - if (us->srb->result != DID_ABORT << 16) { - usb_stor_dbg(us, "scsi cmd done, result=0x%x\n", - us->srb->result); - us->srb->scsi_done(us->srb); - } else { + /* was the command aborted? */ + if (us->srb->result == DID_ABORT << 16) { SkipForAbort: usb_stor_dbg(us, "scsi command aborted\n"); + srb = NULL; /* Don't call srb->scsi_done() */ } /* @@ -429,6 +428,13 @@ SkipForAbort: /* unlock the device pointers */ mutex_unlock(&us->dev_mutex); + + /* now that the locks are released, notify the SCSI core */ + if (srb) { + usb_stor_dbg(us, "scsi cmd done, result=0x%x\n", + srb->result); + srb->scsi_done(srb); + } } /* for (;;) */ /* Wait until we are told to stop */ diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 660180a5d5c4..7170404e8979 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -302,7 +302,6 @@ static int __init usbip_host_init(void) goto err_create_file; } - pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); return ret; err_create_file: @@ -335,4 +334,3 @@ module_exit(usbip_host_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(USBIP_VERSION); diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index cab2b71a80d0..2281f3562870 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -763,7 +763,6 @@ static int __init usbip_core_init(void) { int ret; - pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); ret = usbip_init_eh(); if (ret) return ret; @@ -783,4 +782,3 @@ module_exit(usbip_core_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(USBIP_VERSION); diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index f8573a52e41a..3050fc99a417 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -34,8 +34,6 @@ #include <linux/sched/task.h> #include <uapi/linux/usbip.h> -#define USBIP_VERSION "1.0.0" - #undef pr_fmt #ifdef DEBUG diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 2c4b2fd40406..11b9a22799cc 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1274,7 +1274,7 @@ static int vhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, return 0; } -static struct hc_driver vhci_hc_driver = { +static const struct hc_driver vhci_hc_driver = { .description = driver_name, .product_desc = driver_desc, .hcd_priv_size = sizeof(struct vhci_hcd), @@ -1516,7 +1516,6 @@ static int __init vhci_hcd_init(void) } } - pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); return ret; err_add_hcd: @@ -1542,4 +1541,3 @@ module_exit(vhci_hcd_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(USBIP_VERSION); diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 5778b640ba9c..1b9f60a22e0b 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -366,7 +366,11 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, sockfd_put(socket); dev_err(dev, "port %d already used\n", rhport); - return -EINVAL; + /* + * Will be retried from userspace + * if there's another free port. + */ + return -EBUSY; } dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n", diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index fb70cbef0671..aa4e440e9975 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -586,7 +586,7 @@ static struct attribute *cbaf_dev_attrs[] = { NULL, }; -static struct attribute_group cbaf_dev_attr_group = { +static const struct attribute_group cbaf_dev_attr_group = { .name = NULL, /* we want them in the same directory */ .attrs = cbaf_dev_attrs, }; diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c index d4de56b93d68..78212f8180ce 100644 --- a/drivers/usb/wusbcore/dev-sysfs.c +++ b/drivers/usb/wusbcore/dev-sysfs.c @@ -114,7 +114,7 @@ static struct attribute *wusb_dev_attrs[] = { NULL, }; -static struct attribute_group wusb_dev_attr_group = { +static const struct attribute_group wusb_dev_attr_group = { .name = NULL, /* we want them in the same directory */ .attrs = wusb_dev_attrs, }; diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index a273a91cf667..5338e42533c8 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -244,7 +244,7 @@ static struct attribute *wusbhc_attrs[] = { NULL, }; -static struct attribute_group wusbhc_attr_group = { +static const struct attribute_group wusbhc_attr_group = { .name = NULL, /* we want them in the same directory */ .attrs = wusbhc_attrs, }; |