aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/atm/cxacru.c9
-rw-r--r--drivers/usb/atm/usbatm.c4
-rw-r--r--drivers/usb/atm/xusbatm.c2
-rw-r--r--drivers/usb/cdns3/cdns3-imx.c2
-rw-r--r--drivers/usb/cdns3/core.c44
-rw-r--r--drivers/usb/cdns3/core.h4
-rw-r--r--drivers/usb/cdns3/ep0.c65
-rw-r--r--drivers/usb/cdns3/gadget-export.h3
-rw-r--r--drivers/usb/cdns3/gadget.c144
-rw-r--r--drivers/usb/cdns3/gadget.h5
-rw-r--r--drivers/usb/cdns3/host-export.h6
-rw-r--r--drivers/usb/cdns3/host.c60
-rw-r--r--drivers/usb/chipidea/Makefile5
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c10
-rw-r--r--drivers/usb/chipidea/trace.c23
-rw-r--r--drivers/usb/chipidea/trace.h92
-rw-r--r--drivers/usb/chipidea/udc.c10
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c7
-rw-r--r--drivers/usb/class/cdc-acm.c21
-rw-r--r--drivers/usb/class/cdc-acm.h3
-rw-r--r--drivers/usb/common/ulpi.c2
-rw-r--r--drivers/usb/core/buffer.c6
-rw-r--r--drivers/usb/core/config.c1
-rw-r--r--drivers/usb/core/devio.c14
-rw-r--r--drivers/usb/core/driver.c30
-rw-r--r--drivers/usb/core/endpoint.c2
-rw-r--r--drivers/usb/core/generic.c4
-rw-r--r--drivers/usb/core/hcd-pci.c6
-rw-r--r--drivers/usb/core/hcd.c37
-rw-r--r--drivers/usb/core/hub.c3
-rw-r--r--drivers/usb/core/message.c47
-rw-r--r--drivers/usb/core/port.c4
-rw-r--r--drivers/usb/core/quirks.c16
-rw-r--r--drivers/usb/core/sysfs.c14
-rw-r--r--drivers/usb/core/usb.c4
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/dwc2/platform.c3
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c4
-rw-r--r--drivers/usb/dwc3/ep0.c3
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/function/f_acm.c2
-rw-r--r--drivers/usb/gadget/function/f_fs.c190
-rw-r--r--drivers/usb/gadget/function/f_loopback.c2
-rw-r--r--drivers/usb/gadget/function/f_midi.c16
-rw-r--r--drivers/usb/gadget/function/f_rndis.c4
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c1
-rw-r--r--drivers/usb/gadget/function/storage_common.c8
-rw-r--r--drivers/usb/gadget/legacy/inode.c3
-rw-r--r--drivers/usb/gadget/legacy/raw_gadget.c5
-rw-r--r--drivers/usb/gadget/udc/core.c2
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c10
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/goku_udc.c2
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c19
-rw-r--r--drivers/usb/host/Kconfig17
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-fsl.c9
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-mxc.c213
-rw-r--r--drivers/usb/host/ehci-omap.c1
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c15
-rw-r--r--drivers/usb/host/ehci-ps3.c4
-rw-r--r--drivers/usb/host/ehci-sched.c12
-rw-r--r--drivers/usb/host/ehci-tegra.c4
-rw-r--r--drivers/usb/host/fotg210-hcd.c4
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c9
-rw-r--r--drivers/usb/host/imx21-dbg.c439
-rw-r--r--drivers/usb/host/imx21-hcd.c1933
-rw-r--r--drivers/usb/host/imx21-hcd.h431
-rw-r--r--drivers/usb/host/isp116x-hcd.c1
-rw-r--r--drivers/usb/host/isp1362.h54
-rw-r--r--drivers/usb/host/max3421-hcd.c4
-rw-r--r--drivers/usb/host/ohci-at91.c11
-rw-r--r--drivers/usb/host/ohci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-hub.c1
-rw-r--r--drivers/usb/host/ohci-omap.c13
-rw-r--r--drivers/usb/host/ohci-ps3.c4
-rw-r--r--drivers/usb/host/ohci-pxa27x.c11
-rw-r--r--drivers/usb/host/ohci-s3c2410.c12
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c5
-rw-r--r--drivers/usb/host/sl811-hcd.c20
-rw-r--r--drivers/usb/host/u132-hcd.c6
-rw-r--r--drivers/usb/host/xhci-histb.c2
-rw-r--r--drivers/usb/host/xhci-hub.c4
-rw-r--r--drivers/usb/host/xhci-mem.c7
-rw-r--r--drivers/usb/host/xhci-pci.c23
-rw-r--r--drivers/usb/host/xhci-plat.c3
-rw-r--r--drivers/usb/host/xhci-ring.c4
-rw-r--r--drivers/usb/host/xhci.c140
-rw-r--r--drivers/usb/host/xhci.h6
-rw-r--r--drivers/usb/misc/Kconfig9
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/apple-mfi-fastcharge.c34
-rw-r--r--drivers/usb/misc/brcmstb-usb-pinmap.c351
-rw-r--r--drivers/usb/misc/iowarrior.c3
-rw-r--r--drivers/usb/misc/legousbtower.c2
-rw-r--r--drivers/usb/misc/sisusbvga/Kconfig2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c21
-rw-r--r--drivers/usb/misc/yurex.c1
-rw-r--r--drivers/usb/mtu3/mtu3_debug.h1
-rw-r--r--drivers/usb/mtu3/mtu3_debugfs.c2
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c1
-rw-r--r--drivers/usb/musb/musb_dsps.c4
-rw-r--r--drivers/usb/musb/tusb6010.c1
-rw-r--r--drivers/usb/phy/Kconfig2
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c31
-rw-r--r--drivers/usb/phy/phy-jz4770.c2
-rw-r--r--drivers/usb/serial/Kconfig19
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ch341.c5
-rw-r--r--drivers/usb/serial/cp210x.c499
-rw-r--r--drivers/usb/serial/cyberjack.c7
-rw-r--r--drivers/usb/serial/digi_acceleport.c62
-rw-r--r--drivers/usb/serial/ftdi_sio.c23
-rw-r--r--drivers/usb/serial/iuu_phoenix.c2
-rw-r--r--drivers/usb/serial/keyspan_pda.c548
-rw-r--r--drivers/usb/serial/kl5kusb105.c10
-rw-r--r--drivers/usb/serial/mos7720.c236
-rw-r--r--drivers/usb/serial/option.c43
-rw-r--r--drivers/usb/storage/ene_ub6250.c1
-rw-r--r--drivers/usb/storage/freecom.c1
-rw-r--r--drivers/usb/storage/scsiglue.c2
-rw-r--r--drivers/usb/storage/transport.c9
-rw-r--r--drivers/usb/storage/uas.c23
-rw-r--r--drivers/usb/storage/unusual_uas.h7
-rw-r--r--drivers/usb/storage/usb.c8
-rw-r--r--drivers/usb/typec/Kconfig6
-rw-r--r--drivers/usb/typec/class.c298
-rw-r--r--drivers/usb/typec/mux.c2
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c17
-rw-r--r--drivers/usb/typec/stusb160x.c26
-rw-r--r--drivers/usb/typec/tcpm/fusb302.c16
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c123
-rw-r--r--drivers/usb/typec/tcpm/tcpci.h25
-rw-r--r--drivers/usb/typec/tcpm/tcpci_maxim.c51
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c233
-rw-r--r--drivers/usb/typec/tcpm/wcove.c3
-rw-r--r--drivers/usb/typec/tps6598x.c103
-rw-r--r--drivers/usb/typec/ucsi/psy.c15
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c130
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h4
-rw-r--r--drivers/usb/typec/ucsi/ucsi_acpi.c5
-rw-r--r--drivers/usb/usbip/usbip_common.c5
146 files changed, 2735 insertions, 4723 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 1c1c1d659394..ba5706ccc188 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
-obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_USB2) += host/
obj-$(CONFIG_USB_FOTG210_HCD) += host/
obj-$(CONFIG_USB_MAX3421_HCD) += host/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index e62a770a5d3b..4d3947476f0e 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -810,9 +810,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
mutex_unlock(&instance->poll_state_serialize);
mutex_unlock(&instance->adsl_state_serialize);
- printk(KERN_INFO "%s%d: %s %pM\n", atm_dev->type, atm_dev->number,
- usbatm_instance->description, atm_dev->esi);
-
if (start_polling)
cxacru_poll_status(&instance->poll_work.work);
return 0;
@@ -852,15 +849,15 @@ static void cxacru_poll_status(struct work_struct *work)
switch (instance->adsl_status) {
case 0:
- atm_printk(KERN_INFO, usbatm, "ADSL state: running\n");
+ atm_info(usbatm, "ADSL state: running\n");
break;
case 1:
- atm_printk(KERN_INFO, usbatm, "ADSL state: stopped\n");
+ atm_info(usbatm, "ADSL state: stopped\n");
break;
default:
- atm_printk(KERN_INFO, usbatm, "Unknown adsl status %02x\n", instance->adsl_status);
+ atm_info(usbatm, "Unknown adsl status %02x\n", instance->adsl_status);
break;
}
}
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 56fe30d247da..33ae03ac13a6 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -249,7 +249,7 @@ static void usbatm_complete(struct urb *urb)
/* vdbg("%s: urb 0x%p, status %d, actual_length %d",
__func__, urb, status, urb->actual_length); */
- /* usually in_interrupt(), but not always */
+ /* Can be invoked from task context, protect against interrupts */
spin_lock_irqsave(&channel->lock, flags);
/* must add to the back when receiving; doesn't matter when sending */
@@ -1278,7 +1278,7 @@ EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);
static int __init usbatm_usb_init(void)
{
if (sizeof(struct usbatm_control) > sizeof_field(struct sk_buff, cb)) {
- printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
+ pr_err("%s unusable with this kernel!\n", usbatm_driver_name);
return -EIO;
}
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index ffc9810070a3..0befbf63d1cc 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -179,7 +179,7 @@ static int __init xusbatm_init(void)
num_vendor != num_product ||
num_vendor != num_rx_endpoint ||
num_vendor != num_tx_endpoint) {
- printk(KERN_WARNING "xusbatm: malformed module parameters\n");
+ pr_warn("xusbatm: malformed module parameters\n");
return -EINVAL;
}
diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c
index 54a2d70a9c73..22a56c4dce67 100644
--- a/drivers/usb/cdns3/cdns3-imx.c
+++ b/drivers/usb/cdns3/cdns3-imx.c
@@ -151,6 +151,7 @@ static int cdns_imx_platform_suspend(struct device *dev,
bool suspend, bool wakeup);
static struct cdns3_platform_data cdns_imx_pdata = {
.platform_suspend = cdns_imx_platform_suspend,
+ .quirks = CDNS3_DEFAULT_PM_RUNTIME_ALLOW,
};
static const struct of_dev_auxdata cdns_imx_auxdata[] = {
@@ -206,7 +207,6 @@ static int cdns_imx_probe(struct platform_device *pdev)
device_set_wakeup_capable(dev, true);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- pm_runtime_forbid(dev);
return ret;
err:
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index a0f73d4711ae..1991cb5cf6bf 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -427,7 +427,6 @@ static irqreturn_t cdns3_wakeup_irq(int irq, void *data)
*/
static int cdns3_probe(struct platform_device *pdev)
{
- struct usb_role_switch_desc sw_desc = { };
struct device *dev = &pdev->dev;
struct resource *res;
struct cdns3 *cdns;
@@ -466,11 +465,8 @@ static int cdns3_probe(struct platform_device *pdev)
cdns->xhci_res[1] = *res;
cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral");
- if (cdns->dev_irq == -EPROBE_DEFER)
- return cdns->dev_irq;
-
if (cdns->dev_irq < 0)
- dev_err(dev, "couldn't get peripheral irq\n");
+ return cdns->dev_irq;
regs = devm_platform_ioremap_resource_byname(pdev, "dev");
if (IS_ERR(regs))
@@ -478,14 +474,9 @@ static int cdns3_probe(struct platform_device *pdev)
cdns->dev_regs = regs;
cdns->otg_irq = platform_get_irq_byname(pdev, "otg");
- if (cdns->otg_irq == -EPROBE_DEFER)
+ if (cdns->otg_irq < 0)
return cdns->otg_irq;
- if (cdns->otg_irq < 0) {
- dev_err(dev, "couldn't get otg irq\n");
- return cdns->otg_irq;
- }
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg");
if (!res) {
dev_err(dev, "couldn't get otg resource\n");
@@ -529,18 +520,21 @@ static int cdns3_probe(struct platform_device *pdev)
if (ret)
goto err2;
- sw_desc.set = cdns3_role_set;
- sw_desc.get = cdns3_role_get;
- sw_desc.allow_userspace_control = true;
- sw_desc.driver_data = cdns;
- if (device_property_read_bool(dev, "usb-role-switch"))
+ if (device_property_read_bool(dev, "usb-role-switch")) {
+ struct usb_role_switch_desc sw_desc = { };
+
+ sw_desc.set = cdns3_role_set;
+ sw_desc.get = cdns3_role_get;
+ sw_desc.allow_userspace_control = true;
+ sw_desc.driver_data = cdns;
sw_desc.fwnode = dev->fwnode;
- cdns->role_sw = usb_role_switch_register(dev, &sw_desc);
- if (IS_ERR(cdns->role_sw)) {
- ret = PTR_ERR(cdns->role_sw);
- dev_warn(dev, "Unable to register Role Switch\n");
- goto err3;
+ cdns->role_sw = usb_role_switch_register(dev, &sw_desc);
+ if (IS_ERR(cdns->role_sw)) {
+ ret = PTR_ERR(cdns->role_sw);
+ dev_warn(dev, "Unable to register Role Switch\n");
+ goto err3;
+ }
}
if (cdns->wakeup_irq) {
@@ -551,7 +545,7 @@ static int cdns3_probe(struct platform_device *pdev)
if (ret) {
dev_err(cdns->dev, "couldn't register wakeup irq handler\n");
- goto err3;
+ goto err4;
}
}
@@ -567,7 +561,8 @@ static int cdns3_probe(struct platform_device *pdev)
device_set_wakeup_capable(dev, true);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- pm_runtime_forbid(dev);
+ if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)))
+ pm_runtime_forbid(dev);
/*
* The controller needs less time between bus and controller suspend,
@@ -582,7 +577,8 @@ static int cdns3_probe(struct platform_device *pdev)
return 0;
err4:
cdns3_drd_exit(cdns);
- usb_role_switch_unregister(cdns->role_sw);
+ if (cdns->role_sw)
+ usb_role_switch_unregister(cdns->role_sw);
err3:
set_phy_power_off(cdns);
err2:
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
index 8a40d53d5ede..3176f924293a 100644
--- a/drivers/usb/cdns3/core.h
+++ b/drivers/usb/cdns3/core.h
@@ -42,6 +42,8 @@ struct cdns3_role_driver {
struct cdns3_platform_data {
int (*platform_suspend)(struct device *dev,
bool suspend, bool wakeup);
+ unsigned long quirks;
+#define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0)
};
/**
@@ -73,6 +75,7 @@ struct cdns3_platform_data {
* @wakeup_pending: wakeup interrupt pending
* @pdata: platform data from glue layer
* @lock: spinlock structure
+ * @xhci_plat_data: xhci private data structure pointer
*/
struct cdns3 {
struct device *dev;
@@ -106,6 +109,7 @@ struct cdns3 {
bool wakeup_pending;
struct cdns3_platform_data *pdata;
spinlock_t lock;
+ struct xhci_plat_priv *xhci_plat_data;
};
int cdns3_hw_role_switch(struct cdns3 *cdns);
diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c
index 4761c852d9c4..d3121a32cc68 100644
--- a/drivers/usb/cdns3/ep0.c
+++ b/drivers/usb/cdns3/ep0.c
@@ -137,48 +137,36 @@ static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev,
struct usb_ctrlrequest *ctrl_req)
{
enum usb_device_state device_state = priv_dev->gadget.state;
- struct cdns3_endpoint *priv_ep;
u32 config = le16_to_cpu(ctrl_req->wValue);
int result = 0;
- int i;
switch (device_state) {
case USB_STATE_ADDRESS:
- /* Configure non-control EPs */
- for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) {
- priv_ep = priv_dev->eps[i];
- if (!priv_ep)
- continue;
-
- if (priv_ep->flags & EP_CLAIMED)
- cdns3_ep_config(priv_ep);
- }
-
result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
- if (result)
- return result;
-
- if (!config) {
- cdns3_hw_reset_eps_config(priv_dev);
- usb_gadget_set_state(&priv_dev->gadget,
- USB_STATE_ADDRESS);
- }
+ if (result || !config)
+ goto reset_config;
break;
case USB_STATE_CONFIGURED:
result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
+ if (!config && !result)
+ goto reset_config;
- if (!config && !result) {
- cdns3_hw_reset_eps_config(priv_dev);
- usb_gadget_set_state(&priv_dev->gadget,
- USB_STATE_ADDRESS);
- }
break;
default:
- result = -EINVAL;
+ return -EINVAL;
}
+ return 0;
+
+reset_config:
+ if (result != USB_GADGET_DELAYED_STATUS)
+ cdns3_hw_reset_eps_config(priv_dev);
+
+ usb_gadget_set_state(&priv_dev->gadget,
+ USB_STATE_ADDRESS);
+
return result;
}
@@ -705,6 +693,7 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
unsigned long flags;
int ret = 0;
u8 zlp = 0;
+ int i;
spin_lock_irqsave(&priv_dev->lock, flags);
trace_cdns3_ep0_queue(priv_dev, request);
@@ -720,6 +709,17 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
u32 val;
cdns3_select_ep(priv_dev, 0x00);
+
+ /*
+ * Configure all non-control EPs which are not enabled by class driver
+ */
+ for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) {
+ priv_ep = priv_dev->eps[i];
+ if (priv_ep && priv_ep->flags & EP_CLAIMED &&
+ !(priv_ep->flags & EP_ENABLED))
+ cdns3_ep_config(priv_ep, 0);
+ }
+
cdns3_set_hw_configuration(priv_dev);
cdns3_ep0_complete_setup(priv_dev, 0, 1);
/* wait until configuration set */
@@ -811,6 +811,7 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev)
struct cdns3_usb_regs __iomem *regs;
struct cdns3_endpoint *priv_ep;
u32 max_packet_size = 64;
+ u32 ep_cfg;
regs = priv_dev->regs;
@@ -842,8 +843,10 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev)
BIT(0) | BIT(16));
}
- writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size),
- &regs->ep_cfg);
+ ep_cfg = EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size);
+
+ if (!(priv_ep->flags & EP_CONFIGURED))
+ writel(ep_cfg, &regs->ep_cfg);
writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN,
&regs->ep_sts_en);
@@ -851,8 +854,10 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev)
/* init ep in */
cdns3_select_ep(priv_dev, USB_DIR_IN);
- writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size),
- &regs->ep_cfg);
+ if (!(priv_ep->flags & EP_CONFIGURED))
+ writel(ep_cfg, &regs->ep_cfg);
+
+ priv_ep->flags |= EP_CONFIGURED;
writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, &regs->ep_sts_en);
diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h
index 577469eee961..702c5a267a92 100644
--- a/drivers/usb/cdns3/gadget-export.h
+++ b/drivers/usb/cdns3/gadget-export.h
@@ -13,7 +13,6 @@
#ifdef CONFIG_USB_CDNS3_GADGET
int cdns3_gadget_init(struct cdns3 *cdns);
-void cdns3_gadget_exit(struct cdns3 *cdns);
#else
static inline int cdns3_gadget_init(struct cdns3 *cdns)
@@ -21,8 +20,6 @@ static inline int cdns3_gadget_init(struct cdns3 *cdns)
return -ENXIO;
}
-static inline void cdns3_gadget_exit(struct cdns3 *cdns) { }
-
#endif
#endif /* __LINUX_CDNS3_GADGET_EXPORT */
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index 6e7b70a2e352..08a4e693c470 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -296,6 +296,8 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep)
*/
void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev)
{
+ int i;
+
writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf);
cdns3_allow_enable_l1(priv_dev, 0);
@@ -304,6 +306,10 @@ void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev)
priv_dev->out_mem_is_allocated = 0;
priv_dev->wait_for_setup = 0;
priv_dev->using_streams = 0;
+
+ for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++)
+ if (priv_dev->eps[i])
+ priv_dev->eps[i]->flags &= ~EP_CONFIGURED;
}
/**
@@ -506,7 +512,6 @@ static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep,
while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
int chunk_end;
- int length;
descmiss_priv_req =
cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
@@ -517,7 +522,6 @@ static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep,
break;
chunk_end = descmiss_priv_req->flags & REQUEST_INTERNAL_CH;
- length = request->actual + descmiss_req->actual;
request->status = descmiss_req->status;
__cdns3_descmiss_copy_data(request, descmiss_req);
list_del_init(&descmiss_priv_req->list);
@@ -1110,7 +1114,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
struct cdns3_request *priv_req;
struct cdns3_trb *trb;
- struct cdns3_trb *link_trb;
+ struct cdns3_trb *link_trb = NULL;
dma_addr_t trb_dma;
u32 togle_pcs = 1;
int sg_iter = 0;
@@ -1189,10 +1193,20 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
/* set incorrect Cycle Bit for first trb*/
control = priv_ep->pcs ? 0 : TRB_CYCLE;
+ trb->length = 0;
+ if (priv_dev->dev_ver >= DEV_VER_V2) {
+ u16 td_size;
+
+ td_size = DIV_ROUND_UP(request->length,
+ priv_ep->endpoint.maxpacket);
+ if (priv_dev->gadget.speed == USB_SPEED_SUPER)
+ trb->length = TRB_TDL_SS_SIZE(td_size);
+ else
+ control |= TRB_TDL_HS_SIZE(td_size);
+ }
do {
u32 length;
- u16 td_size = 0;
/* fill TRB */
control |= TRB_TYPE(TRB_NORMAL);
@@ -1204,20 +1218,12 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
length = request->length;
}
- if (likely(priv_dev->dev_ver >= DEV_VER_V2))
- td_size = DIV_ROUND_UP(length,
- priv_ep->endpoint.maxpacket);
- else if (priv_ep->flags & EP_TDLCHK_EN)
+ if (priv_ep->flags & EP_TDLCHK_EN)
total_tdl += DIV_ROUND_UP(length,
priv_ep->endpoint.maxpacket);
- trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) |
+ trb->length |= cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) |
TRB_LEN(length));
- if (priv_dev->gadget.speed == USB_SPEED_SUPER)
- trb->length |= cpu_to_le32(TRB_TDL_SS_SIZE(td_size));
- else
- control |= TRB_TDL_HS_SIZE(td_size);
-
pcs = priv_ep->pcs ? TRB_CYCLE : 0;
/*
@@ -1254,6 +1260,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
priv_req->end_trb = priv_ep->enqueue;
cdns3_ep_inc_enq(priv_ep);
trb = priv_ep->trb_pool + priv_ep->enqueue;
+ trb->length = 0;
} while (sg_iter < num_trb);
trb = priv_req->trb;
@@ -1746,11 +1753,8 @@ static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep)
static void cdns3_disconnect_gadget(struct cdns3_device *priv_dev)
{
- if (priv_dev->gadget_driver && priv_dev->gadget_driver->disconnect) {
- spin_unlock(&priv_dev->lock);
+ if (priv_dev->gadget_driver && priv_dev->gadget_driver->disconnect)
priv_dev->gadget_driver->disconnect(&priv_dev->gadget);
- spin_lock(&priv_dev->lock);
- }
}
/**
@@ -1761,6 +1765,7 @@ static void cdns3_disconnect_gadget(struct cdns3_device *priv_dev)
*/
static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
u32 usb_ists)
+__must_hold(&priv_dev->lock)
{
int speed = 0;
@@ -1785,7 +1790,9 @@ static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
/* Disconnection detected */
if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) {
+ spin_unlock(&priv_dev->lock);
cdns3_disconnect_gadget(priv_dev);
+ spin_lock(&priv_dev->lock);
priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
cdns3_hw_reset_eps_config(priv_dev);
@@ -1979,27 +1986,6 @@ static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev,
return 0;
}
-static void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev,
- struct cdns3_endpoint *priv_ep)
-{
- if (!priv_ep->use_streams || priv_dev->gadget.speed < USB_SPEED_SUPER)
- return;
-
- if (priv_dev->dev_ver >= DEV_VER_V3) {
- u32 mask = BIT(priv_ep->num + (priv_ep->dir ? 16 : 0));
-
- /*
- * Stream capable endpoints are handled by using ep_tdl
- * register. Other endpoints use TDL from TRB feature.
- */
- cdns3_clear_register_bit(&priv_dev->regs->tdl_from_trb, mask);
- }
-
- /* Enable Stream Bit TDL chk and SID chk */
- cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_STREAM_EN |
- EP_CFG_TDL_CHK | EP_CFG_SID_CHK);
-}
-
static void cdns3_configure_dmult(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep)
{
@@ -2037,8 +2023,9 @@ static void cdns3_configure_dmult(struct cdns3_device *priv_dev,
/**
* cdns3_ep_config Configure hardware endpoint
* @priv_ep: extended endpoint object
+ * @enable: set EP_CFG_ENABLE bit in ep_cfg register.
*/
-void cdns3_ep_config(struct cdns3_endpoint *priv_ep)
+int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
{
bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC);
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
@@ -2099,7 +2086,7 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep)
break;
default:
/* all other speed are not supported */
- return;
+ return -EINVAL;
}
if (max_packet_size == 1024)
@@ -2109,11 +2096,33 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep)
else
priv_ep->trb_burst_size = 16;
- ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1,
- !!priv_ep->dir);
- if (ret) {
- dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n");
- return;
+ /* onchip buffer is only allocated before configuration */
+ if (!priv_dev->hw_configured_flag) {
+ ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1,
+ !!priv_ep->dir);
+ if (ret) {
+ dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n");
+ return ret;
+ }
+ }
+
+ if (enable)
+ ep_cfg |= EP_CFG_ENABLE;
+
+ if (priv_ep->use_streams && priv_dev->gadget.speed >= USB_SPEED_SUPER) {
+ if (priv_dev->dev_ver >= DEV_VER_V3) {
+ u32 mask = BIT(priv_ep->num + (priv_ep->dir ? 16 : 0));
+
+ /*
+ * Stream capable endpoints are handled by using ep_tdl
+ * register. Other endpoints use TDL from TRB feature.
+ */
+ cdns3_clear_register_bit(&priv_dev->regs->tdl_from_trb,
+ mask);
+ }
+
+ /* Enable Stream Bit TDL chk and SID chk */
+ ep_cfg |= EP_CFG_STREAM_EN | EP_CFG_TDL_CHK | EP_CFG_SID_CHK;
}
ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) |
@@ -2123,9 +2132,12 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep)
cdns3_select_ep(priv_dev, bEndpointAddress);
writel(ep_cfg, &priv_dev->regs->ep_cfg);
+ priv_ep->flags |= EP_CONFIGURED;
dev_dbg(priv_dev->dev, "Configure %s: with val %08x\n",
priv_ep->name, ep_cfg);
+
+ return 0;
}
/* Find correct direction for HW endpoint according to description */
@@ -2266,7 +2278,7 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep,
u32 bEndpointAddress;
unsigned long flags;
int enable = 1;
- int ret;
+ int ret = 0;
int val;
priv_ep = ep_to_cdns3_ep(ep);
@@ -2305,6 +2317,17 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep,
bEndpointAddress = priv_ep->num | priv_ep->dir;
cdns3_select_ep(priv_dev, bEndpointAddress);
+ /*
+ * For some versions of controller at some point during ISO OUT traffic
+ * DMA reads Transfer Ring for the EP which has never got doorbell.
+ * This issue was detected only on simulation, but to avoid this issue
+ * driver add protection against it. To fix it driver enable ISO OUT
+ * endpoint before setting DRBL. This special treatment of ISO OUT
+ * endpoints are recommended by controller specification.
+ */
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir)
+ enable = 0;
+
if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
/*
* Enable stream support (SS mode) related interrupts
@@ -2315,13 +2338,17 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep,
EP_STS_EN_SIDERREN | EP_STS_EN_MD_EXITEN |
EP_STS_EN_STREAMREN;
priv_ep->use_streams = true;
- cdns3_stream_ep_reconfig(priv_dev, priv_ep);
+ ret = cdns3_ep_config(priv_ep, enable);
priv_dev->using_streams |= true;
}
+ } else {
+ ret = cdns3_ep_config(priv_ep, enable);
}
- ret = cdns3_allocate_trb_pool(priv_ep);
+ if (ret)
+ goto exit;
+ ret = cdns3_allocate_trb_pool(priv_ep);
if (ret)
goto exit;
@@ -2351,20 +2378,6 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep,
writel(reg, &priv_dev->regs->ep_sts_en);
- /*
- * For some versions of controller at some point during ISO OUT traffic
- * DMA reads Transfer Ring for the EP which has never got doorbell.
- * This issue was detected only on simulation, but to avoid this issue
- * driver add protection against it. To fix it driver enable ISO OUT
- * endpoint before setting DRBL. This special treatment of ISO OUT
- * endpoints are recommended by controller specification.
- */
- if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir)
- enable = 0;
-
- if (enable)
- cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE);
-
ep->desc = desc;
priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALLED | EP_STALL_PENDING |
EP_QUIRK_ISO_OUT_EN | EP_QUIRK_EXTRA_BUF_EN);
@@ -3071,7 +3084,7 @@ static void cdns3_gadget_release(struct device *dev)
kfree(priv_dev);
}
-void cdns3_gadget_exit(struct cdns3 *cdns)
+static void cdns3_gadget_exit(struct cdns3 *cdns)
{
struct cdns3_device *priv_dev;
@@ -3265,10 +3278,13 @@ err0:
}
static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup)
+__must_hold(&cdns->lock)
{
struct cdns3_device *priv_dev = cdns->gadget_dev;
+ spin_unlock(&cdns->lock);
cdns3_disconnect_gadget(priv_dev);
+ spin_lock(&cdns->lock);
priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
index 1ccecd237530..21fa461c518e 100644
--- a/drivers/usb/cdns3/gadget.h
+++ b/drivers/usb/cdns3/gadget.h
@@ -1072,7 +1072,7 @@ struct cdns3_trb {
#define TRB_TDL_SS_SIZE_GET(p) (((p) & GENMASK(23, 17)) >> 17)
/* transfer_len bitmasks - bits 31:24 */
-#define TRB_BURST_LEN(p) (((p) << 24) & GENMASK(31, 24))
+#define TRB_BURST_LEN(p) ((unsigned int)((p) << 24) & GENMASK(31, 24))
#define TRB_BURST_LEN_GET(p) (((p) & GENMASK(31, 24)) >> 24)
/* Data buffer pointer bitmasks*/
@@ -1159,6 +1159,7 @@ struct cdns3_endpoint {
#define EP_QUIRK_EXTRA_BUF_DET BIT(12)
#define EP_QUIRK_EXTRA_BUF_EN BIT(13)
#define EP_TDLCHK_EN BIT(15)
+#define EP_CONFIGURED BIT(16)
u32 flags;
struct cdns3_request *descmis_req;
@@ -1360,7 +1361,7 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
int cdns3_init_ep0(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep);
void cdns3_ep0_config(struct cdns3_device *priv_dev);
-void cdns3_ep_config(struct cdns3_endpoint *priv_ep);
+int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable);
void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir);
int __cdns3_gadget_wakeup(struct cdns3_device *priv_dev);
diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h
index ae11810f8826..26041718a086 100644
--- a/drivers/usb/cdns3/host-export.h
+++ b/drivers/usb/cdns3/host-export.h
@@ -9,9 +9,11 @@
#ifndef __LINUX_CDNS3_HOST_EXPORT
#define __LINUX_CDNS3_HOST_EXPORT
+struct usb_hcd;
#ifdef CONFIG_USB_CDNS3_HOST
int cdns3_host_init(struct cdns3 *cdns);
+int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd);
#else
@@ -21,6 +23,10 @@ static inline int cdns3_host_init(struct cdns3 *cdns)
}
static inline void cdns3_host_exit(struct cdns3 *cdns) { }
+static inline int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd)
+{
+ return 0;
+}
#endif /* CONFIG_USB_CDNS3_HOST */
diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
index b3e2cb69762c..ec89f2e5430f 100644
--- a/drivers/usb/cdns3/host.c
+++ b/drivers/usb/cdns3/host.c
@@ -14,6 +14,19 @@
#include "drd.h"
#include "host-export.h"
#include <linux/usb/hcd.h>
+#include "../host/xhci.h"
+#include "../host/xhci-plat.h"
+
+#define XECP_PORT_CAP_REG 0x8000
+#define XECP_AUX_CTRL_REG1 0x8120
+
+#define CFG_RXDET_P3_EN BIT(15)
+#define LPM_2_STB_SWITCH_EN BIT(25)
+
+static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
+ .quirks = XHCI_SKIP_PHY_INIT | XHCI_AVOID_BEI,
+ .suspend_quirk = xhci_cdns3_suspend_quirk,
+};
static int __cdns3_host_init(struct cdns3 *cdns)
{
@@ -39,10 +52,25 @@ static int __cdns3_host_init(struct cdns3 *cdns)
goto err1;
}
+ cdns->xhci_plat_data = kmemdup(&xhci_plat_cdns3_xhci,
+ sizeof(struct xhci_plat_priv), GFP_KERNEL);
+ if (!cdns->xhci_plat_data) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))
+ cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+
+ ret = platform_device_add_data(xhci, cdns->xhci_plat_data,
+ sizeof(struct xhci_plat_priv));
+ if (ret)
+ goto free_memory;
+
ret = platform_device_add(xhci);
if (ret) {
dev_err(cdns->dev, "failed to register xHCI device\n");
- goto err1;
+ goto free_memory;
}
/* Glue needs to access xHCI region register for Power management */
@@ -51,13 +79,43 @@ static int __cdns3_host_init(struct cdns3 *cdns)
cdns->xhci_regs = hcd->regs;
return 0;
+
+free_memory:
+ kfree(cdns->xhci_plat_data);
err1:
platform_device_put(xhci);
return ret;
}
+int xhci_cdns3_suspend_quirk(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ u32 value;
+
+ if (pm_runtime_status_suspended(hcd->self.controller))
+ return 0;
+
+ /* set usbcmd.EU3S */
+ value = readl(&xhci->op_regs->command);
+ value |= CMD_PM_INDEX;
+ writel(value, &xhci->op_regs->command);
+
+ if (hcd->regs) {
+ value = readl(hcd->regs + XECP_AUX_CTRL_REG1);
+ value |= CFG_RXDET_P3_EN;
+ writel(value, hcd->regs + XECP_AUX_CTRL_REG1);
+
+ value = readl(hcd->regs + XECP_PORT_CAP_REG);
+ value |= LPM_2_STB_SWITCH_EN;
+ writel(value, hcd->regs + XECP_PORT_CAP_REG);
+ }
+
+ return 0;
+}
+
static void cdns3_host_exit(struct cdns3 *cdns)
{
+ kfree(cdns->xhci_plat_data);
platform_device_unregister(cdns->host_dev);
cdns->host_dev = NULL;
cdns3_drd_host_off(cdns);
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index fae779a23866..6f4a3deced35 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -1,8 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
+
+# define_trace.h needs to know how to find our header
+CFLAGS_trace.o := -I$(src)
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
ci_hdrc-y := core.o otg.o debug.o ulpi.o
-ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o trace.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 25c65accf089..9e12152ea46b 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -57,7 +57,8 @@ static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
- CI_HDRC_TURN_VBUS_EARLY_ON,
+ CI_HDRC_TURN_VBUS_EARLY_ON |
+ CI_HDRC_DISABLE_DEVICE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
@@ -319,16 +320,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
.notify_event = ci_hdrc_imx_notify_event,
};
int ret;
- const struct of_device_id *of_id;
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
- of_id = of_match_device(ci_hdrc_imx_dt_ids, dev);
- if (!of_id)
- return -ENODEV;
-
- imx_platform_flag = of_id->data;
+ imx_platform_flag = of_device_get_match_data(&pdev->dev);
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
diff --git a/drivers/usb/chipidea/trace.c b/drivers/usb/chipidea/trace.c
new file mode 100644
index 000000000000..f6402630a58e
--- /dev/null
+++ b/drivers/usb/chipidea/trace.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Chipidea Device Mode Trace Support
+ *
+ * Copyright (C) 2020 NXP
+ *
+ * Author: Peter Chen <peter.chen@nxp.com>
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+void ci_log(struct ci_hdrc *ci, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ trace_ci_log(ci, &vaf);
+ va_end(args);
+}
diff --git a/drivers/usb/chipidea/trace.h b/drivers/usb/chipidea/trace.h
new file mode 100644
index 000000000000..1601fd86c4c1
--- /dev/null
+++ b/drivers/usb/chipidea/trace.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Trace support header file for device mode
+ *
+ * Copyright (C) 2020 NXP
+ *
+ * Author: Peter Chen <peter.chen@nxp.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM chipidea
+
+#if !defined(__LINUX_CHIPIDEA_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __LINUX_CHIPIDEA_TRACE
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <linux/usb/chipidea.h>
+#include "ci.h"
+#include "udc.h"
+
+#define CHIPIDEA_MSG_MAX 500
+
+void ci_log(struct ci_hdrc *ci, const char *fmt, ...);
+
+TRACE_EVENT(ci_log,
+ TP_PROTO(struct ci_hdrc *ci, struct va_format *vaf),
+ TP_ARGS(ci, vaf),
+ TP_STRUCT__entry(
+ __string(name, dev_name(ci->dev))
+ __dynamic_array(char, msg, CHIPIDEA_MSG_MAX)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(ci->dev));
+ vsnprintf(__get_str(msg), CHIPIDEA_MSG_MAX, vaf->fmt, *vaf->va);
+ ),
+ TP_printk("%s: %s", __get_str(name), __get_str(msg))
+);
+
+DECLARE_EVENT_CLASS(ci_log_trb,
+ TP_PROTO(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, struct td_node *td),
+ TP_ARGS(hwep, hwreq, td),
+ TP_STRUCT__entry(
+ __string(name, hwep->name)
+ __field(struct td_node *, td)
+ __field(struct usb_request *, req)
+ __field(dma_addr_t, dma)
+ __field(s32, td_remaining_size)
+ __field(u32, next)
+ __field(u32, token)
+ __field(u32, type)
+ ),
+ TP_fast_assign(
+ __assign_str(name, hwep->name);
+ __entry->req = &hwreq->req;
+ __entry->td = td;
+ __entry->dma = td->dma;
+ __entry->td_remaining_size = td->td_remaining_size;
+ __entry->next = le32_to_cpu(td->ptr->next);
+ __entry->token = le32_to_cpu(td->ptr->token);
+ __entry->type = usb_endpoint_type(hwep->ep.desc);
+ ),
+ TP_printk("%s: req: %p, td: %p, td_dma_address: %pad, remaining_size: %d, "
+ "next: %x, total bytes: %d, status: %lx",
+ __get_str(name), __entry->req, __entry->td, &__entry->dma,
+ __entry->td_remaining_size, __entry->next,
+ (int)((__entry->token & TD_TOTAL_BYTES) >> __ffs(TD_TOTAL_BYTES)),
+ __entry->token & TD_STATUS
+ )
+);
+
+DEFINE_EVENT(ci_log_trb, ci_prepare_td,
+ TP_PROTO(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, struct td_node *td),
+ TP_ARGS(hwep, hwreq, td)
+);
+
+DEFINE_EVENT(ci_log_trb, ci_complete_td,
+ TP_PROTO(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, struct td_node *td),
+ TP_ARGS(hwep, hwreq, td)
+);
+
+#endif /* __LINUX_CHIPIDEA_TRACE */
+
+/* this part must be outside header guard */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 60ea932afe2b..c16d900cdaee 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -26,6 +26,7 @@
#include "bits.h"
#include "otg.h"
#include "otg_fsm.h"
+#include "trace.h"
/* control endpoint description */
static const struct usb_endpoint_descriptor
@@ -569,14 +570,18 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
if (ret)
return ret;
- firstnode = list_first_entry(&hwreq->tds, struct td_node, td);
-
lastnode = list_entry(hwreq->tds.prev,
struct td_node, td);
lastnode->ptr->next = cpu_to_le32(TD_TERMINATE);
if (!hwreq->req.no_interrupt)
lastnode->ptr->token |= cpu_to_le32(TD_IOC);
+
+ list_for_each_entry_safe(firstnode, lastnode, &hwreq->tds, td)
+ trace_ci_prepare_td(hwep, hwreq, firstnode);
+
+ firstnode = list_first_entry(&hwreq->tds, struct td_node, td);
+
wmb();
hwreq->req.actual = 0;
@@ -671,6 +676,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
tmptoken = le32_to_cpu(node->ptr->token);
+ trace_ci_complete_td(hwep, hwreq, node);
if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
int n = hw_ep_bit(hwep->num, hwep->dir);
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 6d8331e7da99..4545b23bda3f 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -1134,11 +1134,6 @@ MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct imx_usbmisc *data;
- const struct of_device_id *of_id;
-
- of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
- if (!of_id)
- return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -1150,7 +1145,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
- data->ops = (const struct usbmisc_ops *)of_id->data;
+ data->ops = of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, data);
return 0;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 30ef946a8e1a..f52f1bc0559f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -508,6 +508,7 @@ static void acm_read_bulk_callback(struct urb *urb)
"%s - cooling babbling device\n", __func__);
usb_mark_last_busy(acm->dev);
set_bit(rb->index, &acm->urbs_in_error_delay);
+ set_bit(ACM_ERROR_DELAY, &acm->flags);
cooldown = true;
break;
default:
@@ -533,7 +534,7 @@ static void acm_read_bulk_callback(struct urb *urb)
if (stopped || stalled || cooldown) {
if (stalled)
- schedule_work(&acm->work);
+ schedule_delayed_work(&acm->dwork, 0);
else if (cooldown)
schedule_delayed_work(&acm->dwork, HZ / 2);
return;
@@ -563,13 +564,13 @@ static void acm_write_bulk(struct urb *urb)
acm_write_done(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags);
set_bit(EVENT_TTY_WAKEUP, &acm->flags);
- schedule_work(&acm->work);
+ schedule_delayed_work(&acm->dwork, 0);
}
static void acm_softint(struct work_struct *work)
{
int i;
- struct acm *acm = container_of(work, struct acm, work);
+ struct acm *acm = container_of(work, struct acm, dwork.work);
if (test_bit(EVENT_RX_STALL, &acm->flags)) {
smp_mb(); /* against acm_suspend() */
@@ -585,7 +586,7 @@ static void acm_softint(struct work_struct *work)
if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) {
for (i = 0; i < acm->rx_buflimit; i++)
if (test_and_clear_bit(i, &acm->urbs_in_error_delay))
- acm_submit_read_urb(acm, i, GFP_NOIO);
+ acm_submit_read_urb(acm, i, GFP_KERNEL);
}
if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags))
@@ -1351,7 +1352,6 @@ made_compressed_probe:
acm->ctrlsize = ctrlsize;
acm->readsize = readsize;
acm->rx_buflimit = num_rx_buf;
- INIT_WORK(&acm->work, acm_softint);
INIT_DELAYED_WORK(&acm->dwork, acm_softint);
init_waitqueue_head(&acm->wioctl);
spin_lock_init(&acm->write_lock);
@@ -1561,7 +1561,6 @@ static void acm_disconnect(struct usb_interface *intf)
}
acm_kill_urbs(acm);
- cancel_work_sync(&acm->work);
cancel_delayed_work_sync(&acm->dwork);
tty_unregister_device(acm_tty_driver, acm->minor);
@@ -1604,7 +1603,6 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
acm_kill_urbs(acm);
- cancel_work_sync(&acm->work);
cancel_delayed_work_sync(&acm->dwork);
acm->urbs_in_error_delay = 0;
@@ -1695,6 +1693,15 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
+ { USB_DEVICE(0x045b, 0x023c), /* Renesas USB Download mode */
+ .driver_info = DISABLE_ECHO, /* Don't echo banner */
+ },
+ { USB_DEVICE(0x045b, 0x0248), /* Renesas USB Download mode */
+ .driver_info = DISABLE_ECHO, /* Don't echo banner */
+ },
+ { USB_DEVICE(0x045b, 0x024D), /* Renesas USB Download mode */
+ .driver_info = DISABLE_ECHO, /* Don't echo banner */
+ },
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 9dce179d031b..8aef5eb769a0 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -112,8 +112,7 @@ struct acm {
# define ACM_ERROR_DELAY 3
unsigned long urbs_in_error_delay; /* these need to be restarted after a delay */
struct usb_cdc_line_coding line; /* bits, stop, parity */
- struct work_struct work; /* work queue entry for various purposes*/
- struct delayed_work dwork; /* for cool downs needed in error recovery */
+ struct delayed_work dwork; /* work queue entry for various purposes */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
unsigned int ctrlout; /* output control lines (DTR, RTS) */
struct async_icount iocount; /* counters for control line changes */
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index a18d7c4222dd..ce5e6f6711f7 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -118,7 +118,7 @@ static struct attribute *ulpi_dev_attrs[] = {
NULL
};
-static struct attribute_group ulpi_dev_attr_group = {
+static const struct attribute_group ulpi_dev_attr_group = {
.attrs = ulpi_dev_attrs,
};
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 6cf22c27f2d2..fbb087b728dc 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -51,7 +51,8 @@ void __init usb_init_pool_max(void)
/**
* hcd_buffer_create - initialize buffer pools
* @hcd: the bus whose buffer pools are to be initialized
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
*
* Call this as part of initializing a host controller that uses the dma
* memory allocators. It initializes some pools of dma-coherent memory that
@@ -88,7 +89,8 @@ int hcd_buffer_create(struct usb_hcd *hcd)
/**
* hcd_buffer_destroy - deallocate buffer pools
* @hcd: the bus whose buffer pools are to be destroyed
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
*
* This frees the buffer pools created by hcd_buffer_create().
*/
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 562a730befda..b199eb65f378 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -1076,6 +1076,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
case USB_PTM_CAP_TYPE:
dev->bos->ptm_cap =
(struct usb_ptm_cap_descriptor *)buffer;
+ break;
default:
break;
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index e96a858a1218..533236366a03 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -482,11 +482,11 @@ static void snoop_urb(struct usb_device *udev,
if (userurb) { /* Async */
if (when == SUBMIT)
- dev_info(&udev->dev, "userurb %pK, ep%d %s-%s, "
+ dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
"length %u\n",
userurb, ep, t, d, length);
else
- dev_info(&udev->dev, "userurb %pK, ep%d %s-%s, "
+ dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
"actual_length %u status %d\n",
userurb, ep, t, d, length,
timeout_or_status);
@@ -1997,7 +1997,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
if (as) {
int retval;
- snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
return retval;
@@ -2014,7 +2014,7 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
as = async_getcompleted(ps);
if (as) {
- snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -2142,7 +2142,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
if (as) {
int retval;
- snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
return retval;
@@ -2159,7 +2159,7 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
as = async_getcompleted(ps);
if (as) {
- snoop(&ps->dev->dev, "reap %pK\n", as->userurb);
+ snoop(&ps->dev->dev, "reap %px\n", as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -2624,7 +2624,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
#endif
case USBDEVFS_DISCARDURB:
- snoop(&dev->dev, "%s: DISCARDURB %pK\n", __func__, p);
+ snoop(&dev->dev, "%s: DISCARDURB %px\n", __func__, p);
ret = proc_unlinkurb(ps, p);
break;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 98b7449c11f3..4dfa44d6cc3c 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -839,6 +839,22 @@ const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
return NULL;
}
+bool usb_driver_applicable(struct usb_device *udev,
+ struct usb_device_driver *udrv)
+{
+ if (udrv->id_table && udrv->match)
+ return usb_device_match_id(udev, udrv->id_table) != NULL &&
+ udrv->match(udev);
+
+ if (udrv->id_table)
+ return usb_device_match_id(udev, udrv->id_table) != NULL;
+
+ if (udrv->match)
+ return udrv->match(udev);
+
+ return false;
+}
+
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
@@ -853,17 +869,14 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
udev = to_usb_device(dev);
udrv = to_usb_device_driver(drv);
- if (udrv->id_table)
- return usb_device_match_id(udev, udrv->id_table) != NULL;
-
- if (udrv->match)
- return udrv->match(udev);
-
/* If the device driver under consideration does not have a
* id_table or a match function, then let the driver's probe
* function decide.
*/
- return 1;
+ if (!udrv->id_table && !udrv->match)
+ return 1;
+
+ return usb_driver_applicable(udev, udrv);
} else if (is_usb_interface(dev)) {
struct usb_interface *intf;
@@ -941,8 +954,7 @@ static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
return 0;
udev = to_usb_device(dev);
- if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
- (!new_udriver->match || new_udriver->match(udev) == 0))
+ if (!usb_driver_applicable(udev, new_udriver))
return 0;
ret = device_reprobe(dev);
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 1c2c04079676..903426b6d305 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -153,7 +153,7 @@ static struct attribute *ep_dev_attrs[] = {
&dev_attr_direction.attr,
NULL,
};
-static struct attribute_group ep_dev_attr_grp = {
+static const struct attribute_group ep_dev_attr_grp = {
.attrs = ep_dev_attrs,
};
static const struct attribute_group *ep_dev_groups[] = {
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 22c887f5c497..26f9fb9f67ca 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -205,9 +205,7 @@ static int __check_for_non_generic_match(struct device_driver *drv, void *data)
udrv = to_usb_device_driver(drv);
if (udrv == &usb_generic_driver)
return 0;
- if (usb_device_match_id(udev, udrv->id_table) != NULL)
- return 1;
- return (udrv->match && udrv->match(udev));
+ return usb_driver_applicable(udev, udrv);
}
static bool usb_generic_driver_match(struct usb_device *udev)
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index ec0d6c50610c..d630cccd2e6e 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -160,7 +160,8 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
* @dev: USB Host Controller being probed
* @id: pci hotplug id connecting controller to HCD framework
* @driver: USB HC driver handle
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
*
* Allocates basic PCI resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
@@ -304,7 +305,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
/**
* usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
* @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
*
* Reverses the effect of usb_hcd_pci_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 2c6b9578a7d3..60886a7464c3 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -747,8 +747,7 @@ error:
* driver requests it; otherwise the driver is responsible for
* calling usb_hcd_poll_rh_status() when an event occurs.
*
- * Completions are called in_interrupt(), but they may or may not
- * be in_irq().
+ * Completion handler may not sleep. See usb_hcd_giveback_urb() for details.
*/
void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
{
@@ -904,7 +903,8 @@ static void usb_bus_init (struct usb_bus *bus)
/**
* usb_register_bus - registers the USB host controller with the usb core
* @bus: pointer to the bus to register
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
*
* Assigns a bus number, and links the controller into usbcore data
* structures so that it can be seen by scanning the bus list.
@@ -939,7 +939,8 @@ error_find_busnum:
/**
* usb_deregister_bus - deregisters the USB host controller
* @bus: pointer to the bus to deregister
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
*
* Recycles the bus number, and unlinks the controller from usbcore data
* structures so that it won't be seen by scanning the bus list.
@@ -1646,9 +1647,16 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
/* pass ownership to the completion handler */
urb->status = status;
- kcov_remote_start_usb((u64)urb->dev->bus->busnum);
+ /*
+ * This function can be called in task context inside another remote
+ * coverage collection section, but KCOV doesn't support that kind of
+ * recursion yet. Only collect coverage in softirq context for now.
+ */
+ if (in_serving_softirq())
+ kcov_remote_start_usb((u64)urb->dev->bus->busnum);
urb->complete(urb);
- kcov_remote_stop();
+ if (in_serving_softirq())
+ kcov_remote_stop();
usb_anchor_resume_wakeups(anchor);
atomic_dec(&urb->use_count);
@@ -1691,7 +1699,11 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t)
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
* @status: completion status code for the URB.
- * Context: in_interrupt()
+ *
+ * Context: atomic. The completion callback is invoked in caller's context.
+ * For HCDs with HCD_BH flag set, the completion callback is invoked in tasklet
+ * context (except for URBs submitted to the root hub which always complete in
+ * caller's context).
*
* This hands the URB from HCD to its USB device driver, using its
* completion function. The HCD has freed all per-urb resources
@@ -2268,7 +2280,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
* usb_bus_start_enum - start immediate enumeration (for OTG)
* @bus: the bus (must use hcd framework)
* @port_num: 1-based number of port; usually bus->otg_port
- * Context: in_interrupt()
+ * Context: atomic
*
* Starts enumeration, with an immediate reset followed later by
* hub_wq identifying and possibly configuring the device.
@@ -2474,7 +2486,8 @@ EXPORT_SYMBOL_GPL(__usb_create_hcd);
* @bus_name: value to store in hcd->self.bus_name
* @primary_hcd: a pointer to the usb_hcd structure that is sharing the
* PCI device. Only allocate certain resources for the primary HCD
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
*
* Allocate a struct usb_hcd, with extra space at the end for the
* HC driver's private data. Initialize the generic members of the
@@ -2496,7 +2509,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
* @driver: HC driver that will use this hcd
* @dev: device for this HC, stored in hcd->self.controller
* @bus_name: value to store in hcd->self.bus_name
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
*
* Allocate a struct usb_hcd, with extra space at the end for the
* HC driver's private data. Initialize the generic members of the
@@ -2830,7 +2844,8 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
/**
* usb_remove_hcd - shutdown processing for generic HCDs
* @hcd: the usb_hcd structure to remove
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
*
* Disconnects the root hub, then reverses the effects of usb_add_hcd(),
* invoking the HCD's stop() method.
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 17202b2ee063..7f71218cc1e5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2171,7 +2171,8 @@ static void hub_disconnect_children(struct usb_device *udev)
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep
*
* Something got disconnected. Get rid of it and all of its children.
*
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 19ebb542befc..30e9e680c74c 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -119,7 +119,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
* @timeout: time in msecs to wait for the message to complete before timing
* out (if 0 the wait is forever)
*
- * Context: !in_interrupt ()
+ * Context: task context, might sleep.
*
* This function sends a simple control message to a specified endpoint and
* waits for the message to complete, or timeout.
@@ -204,9 +204,6 @@ int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
int ret;
u8 *data = NULL;
- if (usb_pipe_type_check(dev, pipe))
- return -EINVAL;
-
if (size) {
data = kmemdup(driver_data, size, memflags);
if (!data)
@@ -219,9 +216,8 @@ int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
if (ret < 0)
return ret;
- if (ret == size)
- return 0;
- return -EINVAL;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(usb_control_msg_send);
@@ -273,7 +269,7 @@ int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request,
int ret;
u8 *data;
- if (!size || !driver_data || usb_pipe_type_check(dev, pipe))
+ if (!size || !driver_data)
return -EINVAL;
data = kmalloc(size, memflags);
@@ -290,7 +286,7 @@ int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request,
memcpy(driver_data, data, size);
ret = 0;
} else {
- ret = -EINVAL;
+ ret = -EREMOTEIO;
}
exit:
@@ -310,7 +306,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv);
* @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
*
- * Context: !in_interrupt ()
+ * Context: task context, might sleep.
*
* This function sends a simple interrupt message to a specified endpoint and
* waits for the message to complete, or timeout.
@@ -343,7 +339,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
* @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
*
- * Context: !in_interrupt ()
+ * Context: task context, might sleep.
*
* This function sends a simple bulk message to a specified endpoint
* and waits for the message to complete, or timeout.
@@ -610,7 +606,8 @@ EXPORT_SYMBOL_GPL(usb_sg_init);
* usb_sg_wait - synchronously execute scatter/gather request
* @io: request block handle, as initialized with usb_sg_init().
* some fields become accessible when this call returns.
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* This function blocks until the specified I/O operation completes. It
* leverages the grouping of the related I/O requests to get good transfer
@@ -764,7 +761,8 @@ EXPORT_SYMBOL_GPL(usb_sg_cancel);
* @index: the number of the descriptor
* @buf: where to put the descriptor
* @size: how big is "buf"?
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* Gets a USB descriptor. Convenience functions exist to simplify
* getting some types of descriptors. Use
@@ -812,7 +810,8 @@ EXPORT_SYMBOL_GPL(usb_get_descriptor);
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
* in little-endian byte order).
@@ -947,7 +946,8 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* This converts the UTF-16LE encoded strings returned by devices, from
* usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
@@ -1036,7 +1036,8 @@ char *usb_cache_string(struct usb_device *udev, int index)
* usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
* @dev: the device whose device descriptor is being updated
* @size: how much of the descriptor to read
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* Updates the copy of the device descriptor stored in the device structure,
* which dedicates space for this purpose.
@@ -1071,7 +1072,7 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
/*
* usb_set_isoch_delay - informs the device of the packet transmit delay
* @dev: the device whose delay is to be informed
- * Context: !in_interrupt()
+ * Context: task context, might sleep
*
* Since this is an optional request, we don't bother if it fails.
*/
@@ -1100,7 +1101,8 @@ int usb_set_isoch_delay(struct usb_device *dev)
* @type: USB_STATUS_TYPE_*; for standard or PTM status types
* @target: zero (for device), else interface or endpoint number
* @data: pointer to two bytes of bitmap data
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* Returns device, interface, or endpoint status. Normally only of
* interest to see if the device is self powered, or has enabled the
@@ -1177,7 +1179,8 @@ EXPORT_SYMBOL_GPL(usb_get_status);
* usb_clear_halt - tells device to clear endpoint halt/stall condition
* @dev: device whose endpoint is halted
* @pipe: endpoint "pipe" being cleared
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* This is used to clear halt conditions for bulk and interrupt endpoints,
* as reported by URB completion status. Endpoints that are halted are
@@ -1481,7 +1484,8 @@ void usb_enable_interface(struct usb_device *dev,
* @dev: the device whose interface is being updated
* @interface: the interface being updated
* @alternate: the setting being chosen.
- * Context: !in_interrupt ()
+ *
+ * Context: task context, might sleep.
*
* This is used to enable data transfers on interfaces that may not
* be enabled by default. Not all devices support such configurability.
@@ -1902,7 +1906,8 @@ static void __usb_queue_reset_device(struct work_struct *ws)
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
* @configuration: the configuration being chosen.
- * Context: !in_interrupt(), caller owns the device lock
+ *
+ * Context: task context, might sleep. Caller holds device lock.
*
* This is used to enable non-default device modes. Not all devices
* use this kind of configurability; many devices only have one
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 235a7c645503..dfcca9c876c7 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -155,7 +155,7 @@ static struct attribute *port_dev_attrs[] = {
NULL,
};
-static struct attribute_group port_dev_attr_grp = {
+static const struct attribute_group port_dev_attr_grp = {
.attrs = port_dev_attrs,
};
@@ -169,7 +169,7 @@ static struct attribute *port_dev_usb3_attrs[] = {
NULL,
};
-static struct attribute_group port_dev_usb3_attr_grp = {
+static const struct attribute_group port_dev_usb3_attr_grp = {
.attrs = port_dev_usb3_attrs,
};
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 10574fa3f927..1b4eb7046b07 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -342,12 +342,19 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
+ /* Agfa SNAPSCAN 1212U */
+ { USB_DEVICE(0x06bd, 0x0001), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
/* Guillemot Webcam Hercules Dualpix Exchange*/
{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Guillemot Hercules DJ Console audio card (BZ 208357) */
+ { USB_DEVICE(0x06f8, 0xb000), .driver_info =
+ USB_QUIRK_ENDPOINT_IGNORE },
+
/* Midiman M-Audio Keystation 88es */
{ USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -378,6 +385,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0926, 0x3333), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
+ /* Kingston DataTraveler 3.0 */
+ { USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM },
+
/* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
{ USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
@@ -418,6 +428,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x1532, 0x0116), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+ /* Lenovo ThinkCenter A630Z TI024Gen3 usb-audio */
+ { USB_DEVICE(0x17ef, 0xa012), .driver_info =
+ USB_QUIRK_DISCONNECT_SUSPEND },
+
/* BUILDWIN Photo Frame */
{ USB_DEVICE(0x1908, 0x1315), .driver_info =
USB_QUIRK_HONOR_BNUMINTERFACES },
@@ -518,6 +532,8 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = {
* Matched for devices with USB_QUIRK_ENDPOINT_IGNORE.
*/
static const struct usb_device_id usb_endpoint_ignore[] = {
+ { USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x01 },
+ { USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x81 },
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
{ }
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 8d134193fa0c..d85699bee671 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -641,7 +641,7 @@ static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_lpm_besl.attr,
NULL,
};
-static struct attribute_group usb2_hardware_lpm_attr_group = {
+static const struct attribute_group usb2_hardware_lpm_attr_group = {
.name = power_group_name,
.attrs = usb2_hardware_lpm_attr,
};
@@ -651,7 +651,7 @@ static struct attribute *usb3_hardware_lpm_attr[] = {
&dev_attr_usb3_hardware_lpm_u2.attr,
NULL,
};
-static struct attribute_group usb3_hardware_lpm_attr_group = {
+static const struct attribute_group usb3_hardware_lpm_attr_group = {
.name = power_group_name,
.attrs = usb3_hardware_lpm_attr,
};
@@ -663,7 +663,7 @@ static struct attribute *power_attrs[] = {
&dev_attr_active_duration.attr,
NULL,
};
-static struct attribute_group power_attr_group = {
+static const struct attribute_group power_attr_group = {
.name = power_group_name,
.attrs = power_attrs,
};
@@ -832,7 +832,7 @@ static struct attribute *dev_attrs[] = {
#endif
NULL,
};
-static struct attribute_group dev_attr_grp = {
+static const struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
@@ -865,7 +865,7 @@ static umode_t dev_string_attrs_are_visible(struct kobject *kobj,
return a->mode;
}
-static struct attribute_group dev_string_attr_grp = {
+static const struct attribute_group dev_string_attr_grp = {
.attrs = dev_string_attrs,
.is_visible = dev_string_attrs_are_visible,
};
@@ -1222,7 +1222,7 @@ static struct attribute *intf_attrs[] = {
&dev_attr_interface_authorized.attr,
NULL,
};
-static struct attribute_group intf_attr_grp = {
+static const struct attribute_group intf_attr_grp = {
.attrs = intf_attrs,
};
@@ -1246,7 +1246,7 @@ static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
return a->mode;
}
-static struct attribute_group intf_assoc_attr_grp = {
+static const struct attribute_group intf_assoc_attr_grp = {
.attrs = intf_assoc_attrs,
.is_visible = intf_assoc_attrs_are_visible,
};
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 9b4ac4415f1a..8f07b0516100 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -28,7 +28,6 @@
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/slab.h>
-#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -561,7 +560,8 @@ static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
* @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep.
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index c893f54a3420..82538daac8b8 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -74,6 +74,8 @@ extern int usb_match_device(struct usb_device *dev,
const struct usb_device_id *id);
extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
const struct usb_device_id *id);
+extern bool usb_driver_applicable(struct usb_device *udev,
+ struct usb_device_driver *udrv);
extern void usb_forced_unbind_intf(struct usb_interface *intf);
extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index e2820676beb1..5f18acac7406 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -608,10 +608,13 @@ static int dwc2_driver_probe(struct platform_device *dev)
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
return 0;
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
+ IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
error_debugfs:
dwc2_debugfs_exit(hsotg);
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
+#endif
error_drd:
dwc2_drd_exit(hsotg);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index bdf0925da6b6..841daec70b6e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* core.c - DesignWare USB3 DRD Controller Core file
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 74323b10a64a..2f95f08ca511 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1277,7 +1277,7 @@ struct dwc3_event_type {
#define DWC3_DEPEVT_EPCMDCMPLT 0x07
/**
- * struct dwc3_event_depvt - Device Endpoint Events
+ * struct dwc3_event_depevt - Device Endpoint Events
* @one_bit: indicates this is an endpoint event (not used)
* @endpoint_number: number of the endpoint
* @endpoint_event: The event we have:
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 242b6210380a..bae6a70664c8 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -40,6 +40,7 @@
#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
#define PCI_DEVICE_ID_INTEL_TGPH 0x43ee
#define PCI_DEVICE_ID_INTEL_JSP 0x4dee
+#define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1
#define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
@@ -367,6 +368,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP),
(kernel_ulong_t) &dwc3_pci_intel_properties, },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
(kernel_ulong_t) &dwc3_pci_amd_properties, },
{ } /* Terminating Entry */
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 7be3903cb842..8b668ef46f7f 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -1058,10 +1058,11 @@ void dwc3_ep0_send_delayed_status(struct dwc3 *dwc)
{
unsigned int direction = !dwc->ep0_expect_in;
+ dwc->delayed_status = false;
+
if (dwc->ep0state != EP0_STATUS_PHASE)
return;
- dwc->delayed_status = false;
__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 05b176c82cc5..c6d455f2bb92 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1245,7 +1245,7 @@ int usb_string_id(struct usb_composite_dev *cdev)
EXPORT_SYMBOL_GPL(usb_string_id);
/**
- * usb_string_ids() - allocate unused string IDs in batch
+ * usb_string_ids_tab() - allocate unused string IDs in batch
* @cdev: the device whose string descriptor IDs are being allocated
* @str: an array of usb_string objects to assign numbers to
* Context: single threaded during gadget setup
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 46647bfac2ef..349945e064bb 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -686,7 +686,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
- acm_ss_function, NULL);
+ acm_ss_function, acm_ss_function);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 046f770a76da..801a8b668a35 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -296,11 +296,11 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
reinit_completion(&ffs->ep0req_completion);
ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
- if (unlikely(ret < 0))
+ if (ret < 0)
return ret;
ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
- if (unlikely(ret)) {
+ if (ret) {
usb_ep_dequeue(ffs->gadget->ep0, req);
return -EINTR;
}
@@ -337,7 +337,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
- if (unlikely(ret < 0))
+ if (ret < 0)
return ret;
/* Check state */
@@ -345,7 +345,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
case FFS_READ_DESCRIPTORS:
case FFS_READ_STRINGS:
/* Copy data */
- if (unlikely(len < 16)) {
+ if (len < 16) {
ret = -EINVAL;
break;
}
@@ -360,7 +360,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
if (ffs->state == FFS_READ_DESCRIPTORS) {
pr_info("read descriptors\n");
ret = __ffs_data_got_descs(ffs, data, len);
- if (unlikely(ret < 0))
+ if (ret < 0)
break;
ffs->state = FFS_READ_STRINGS;
@@ -368,11 +368,11 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
} else {
pr_info("read strings\n");
ret = __ffs_data_got_strings(ffs, data, len);
- if (unlikely(ret < 0))
+ if (ret < 0)
break;
ret = ffs_epfiles_create(ffs);
- if (unlikely(ret)) {
+ if (ret) {
ffs->state = FFS_CLOSING;
break;
}
@@ -381,7 +381,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
mutex_unlock(&ffs->mutex);
ret = ffs_ready(ffs);
- if (unlikely(ret < 0)) {
+ if (ret < 0) {
ffs->state = FFS_CLOSING;
return ret;
}
@@ -495,7 +495,7 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
spin_unlock_irq(&ffs->ev.waitq.lock);
mutex_unlock(&ffs->mutex);
- return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size;
+ return copy_to_user(buf, events, size) ? -EFAULT : size;
}
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@@ -514,7 +514,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
- if (unlikely(ret < 0))
+ if (ret < 0)
return ret;
/* Check state */
@@ -536,7 +536,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
case FFS_NO_SETUP:
n = len / sizeof(struct usb_functionfs_event);
- if (unlikely(!n)) {
+ if (!n) {
ret = -EINVAL;
break;
}
@@ -567,9 +567,9 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
spin_unlock_irq(&ffs->ev.waitq.lock);
- if (likely(len)) {
+ if (len) {
data = kmalloc(len, GFP_KERNEL);
- if (unlikely(!data)) {
+ if (!data) {
ret = -ENOMEM;
goto done_mutex;
}
@@ -586,7 +586,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
/* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len);
- if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len)))
+ if ((ret > 0) && (copy_to_user(buf, data, len)))
ret = -EFAULT;
goto done_mutex;
@@ -608,7 +608,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file)
ENTER();
- if (unlikely(ffs->state == FFS_CLOSING))
+ if (ffs->state == FFS_CLOSING)
return -EBUSY;
file->private_data = ffs;
@@ -657,7 +657,7 @@ static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
poll_wait(file, &ffs->ev.waitq, wait);
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
- if (unlikely(ret < 0))
+ if (ret < 0)
return mask;
switch (ffs->state) {
@@ -678,6 +678,8 @@ static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
mask |= (EPOLLIN | EPOLLOUT);
break;
}
+ break;
+
case FFS_CLOSING:
break;
case FFS_DEACTIVATED:
@@ -706,7 +708,7 @@ static const struct file_operations ffs_ep0_operations = {
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
ENTER();
- if (likely(req->context)) {
+ if (req->context) {
struct ffs_ep *ep = _ep->driver_data;
ep->status = req->status ? req->status : req->actual;
complete(req->context);
@@ -716,10 +718,10 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
{
ssize_t ret = copy_to_iter(data, data_len, iter);
- if (likely(ret == data_len))
+ if (ret == data_len)
return ret;
- if (unlikely(iov_iter_count(iter)))
+ if (iov_iter_count(iter))
return -EFAULT;
/*
@@ -885,7 +887,7 @@ static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
return ret;
}
- if (unlikely(iov_iter_count(iter))) {
+ if (iov_iter_count(iter)) {
ret = -EFAULT;
} else {
buf->length -= ret;
@@ -906,10 +908,10 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
struct ffs_buffer *buf;
ssize_t ret = copy_to_iter(data, data_len, iter);
- if (likely(data_len == ret))
+ if (data_len == ret)
return ret;
- if (unlikely(iov_iter_count(iter)))
+ if (iov_iter_count(iter))
return -EFAULT;
/* See ffs_copy_to_iter for more context. */
@@ -930,7 +932,7 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
* in struct ffs_epfile for full read_buffer pointer synchronisation
* story.
*/
- if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf)))
+ if (cmpxchg(&epfile->read_buffer, NULL, buf))
kfree(buf);
return ret;
@@ -968,7 +970,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
/* We will be using request and read_buffer */
ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
- if (unlikely(ret))
+ if (ret)
goto error;
/* Allocate & copy */
@@ -1013,7 +1015,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
spin_unlock_irq(&epfile->ffs->eps_lock);
data = ffs_alloc_buffer(io_data, data_len);
- if (unlikely(!data)) {
+ if (!data) {
ret = -ENOMEM;
goto error_mutex;
}
@@ -1033,7 +1035,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
ret = usb_ep_set_halt(ep->ep);
if (!ret)
ret = -EBADMSG;
- } else if (unlikely(data_len == -EINVAL)) {
+ } else if (data_len == -EINVAL) {
/*
* Sanity Check: even though data_len can't be used
* uninitialized at the time I write this comment, some
@@ -1068,12 +1070,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
req->complete = ffs_epfile_io_complete;
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
- if (unlikely(ret < 0))
+ if (ret < 0)
goto error_lock;
spin_unlock_irq(&epfile->ffs->eps_lock);
- if (unlikely(wait_for_completion_interruptible(&done))) {
+ if (wait_for_completion_interruptible(&done)) {
/*
* To avoid race condition with ffs_epfile_io_complete,
* dequeue the request first then check
@@ -1115,7 +1117,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
req->complete = ffs_epfile_async_io_complete;
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
- if (unlikely(ret)) {
+ if (ret) {
io_data->req = NULL;
usb_ep_free_request(ep->ep, req);
goto error_lock;
@@ -1166,7 +1168,7 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
- if (likely(io_data && io_data->ep && io_data->req))
+ if (io_data && io_data->ep && io_data->req)
value = usb_ep_dequeue(io_data->ep, io_data->req);
else
value = -EINVAL;
@@ -1185,7 +1187,7 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL);
- if (unlikely(!p))
+ if (!p)
return -ENOMEM;
p->aio = true;
} else {
@@ -1222,7 +1224,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
if (!is_sync_kiocb(kiocb)) {
p = kzalloc(sizeof(io_data), GFP_KERNEL);
- if (unlikely(!p))
+ if (!p)
return -ENOMEM;
p->aio = true;
} else {
@@ -1324,10 +1326,11 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
case FUNCTIONFS_ENDPOINT_DESC:
{
int desc_idx;
- struct usb_endpoint_descriptor *desc;
+ struct usb_endpoint_descriptor desc1, *desc;
switch (epfile->ffs->gadget->speed) {
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
desc_idx = 2;
break;
case USB_SPEED_HIGH:
@@ -1336,10 +1339,12 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
default:
desc_idx = 0;
}
+
desc = epfile->ep->descs[desc_idx];
+ memcpy(&desc1, desc, desc->bLength);
spin_unlock_irq(&epfile->ffs->eps_lock);
- ret = copy_to_user((void __user *)value, desc, desc->bLength);
+ ret = copy_to_user((void __user *)value, &desc1, desc1.bLength);
if (ret)
ret = -EFAULT;
return ret;
@@ -1383,7 +1388,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
inode = new_inode(sb);
- if (likely(inode)) {
+ if (inode) {
struct timespec64 ts = current_time(inode);
inode->i_ino = get_next_ino();
@@ -1415,11 +1420,11 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb,
ENTER();
dentry = d_alloc_name(sb->s_root, name);
- if (unlikely(!dentry))
+ if (!dentry)
return NULL;
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
- if (unlikely(!inode)) {
+ if (!inode) {
dput(dentry);
return NULL;
}
@@ -1466,12 +1471,11 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
&simple_dir_inode_operations,
&data->perms);
sb->s_root = d_make_root(inode);
- if (unlikely(!sb->s_root))
+ if (!sb->s_root)
return -ENOMEM;
/* EP0 file */
- if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
- &ffs_ep0_operations)))
+ if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
return -ENOMEM;
return 0;
@@ -1559,13 +1563,13 @@ static int ffs_fs_get_tree(struct fs_context *fc)
return invalf(fc, "No source specified");
ffs = ffs_data_new(fc->source);
- if (unlikely(!ffs))
+ if (!ffs)
return -ENOMEM;
ffs->file_perms = ctx->perms;
ffs->no_disconnect = ctx->no_disconnect;
ffs->dev_name = kstrdup(fc->source, GFP_KERNEL);
- if (unlikely(!ffs->dev_name)) {
+ if (!ffs->dev_name) {
ffs_data_put(ffs);
return -ENOMEM;
}
@@ -1651,7 +1655,7 @@ static int functionfs_init(void)
ENTER();
ret = register_filesystem(&ffs_fs_type);
- if (likely(!ret))
+ if (!ret)
pr_info("file system registered\n");
else
pr_err("failed registering file system (%d)\n", ret);
@@ -1696,7 +1700,7 @@ static void ffs_data_put(struct ffs_data *ffs)
{
ENTER();
- if (unlikely(refcount_dec_and_test(&ffs->ref))) {
+ if (refcount_dec_and_test(&ffs->ref)) {
pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
@@ -1738,7 +1742,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
static struct ffs_data *ffs_data_new(const char *dev_name)
{
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
- if (unlikely(!ffs))
+ if (!ffs)
return NULL;
ENTER();
@@ -1828,11 +1832,11 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
return -EBADFD;
first_id = usb_string_ids_n(cdev, ffs->strings_count);
- if (unlikely(first_id < 0))
+ if (first_id < 0)
return first_id;
ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
- if (unlikely(!ffs->ep0req))
+ if (!ffs->ep0req)
return -ENOMEM;
ffs->ep0req->complete = ffs_ep0_complete;
ffs->ep0req->context = ffs;
@@ -1888,7 +1892,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
epfile,
&ffs_epfile_operations);
- if (unlikely(!epfile->dentry)) {
+ if (!epfile->dentry) {
ffs_epfiles_destroy(epfiles, i - 1);
return -ENOMEM;
}
@@ -1926,7 +1930,7 @@ static void ffs_func_eps_disable(struct ffs_function *func)
spin_lock_irqsave(&func->ffs->eps_lock, flags);
while (count--) {
/* pending requests get nuked */
- if (likely(ep->ep))
+ if (ep->ep)
usb_ep_disable(ep->ep);
++ep;
@@ -1960,7 +1964,7 @@ static int ffs_func_eps_enable(struct ffs_function *func)
}
ret = usb_ep_enable(ep->ep);
- if (likely(!ret)) {
+ if (!ret) {
epfile->ep = ep;
epfile->in = usb_endpoint_dir_in(ep->ep->desc);
epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
@@ -2033,12 +2037,12 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK)
#define __entity(type, val) do { \
pr_vdebug("entity " #type "(%02x)\n", (val)); \
- if (unlikely(!__entity_check_ ##type(val))) { \
+ if (!__entity_check_ ##type(val)) { \
pr_vdebug("invalid entity's value\n"); \
return -EINVAL; \
} \
ret = entity(FFS_ ##type, &val, _ds, priv); \
- if (unlikely(ret < 0)) { \
+ if (ret < 0) { \
pr_debug("entity " #type "(%02x); ret = %d\n", \
(val), ret); \
return ret; \
@@ -2163,7 +2167,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
/* Record "descriptor" entity */
ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
- if (unlikely(ret < 0)) {
+ if (ret < 0) {
pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
num, ret);
return ret;
@@ -2174,7 +2178,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
ret = ffs_do_single_desc(data, len, entity, priv,
&current_class);
- if (unlikely(ret < 0)) {
+ if (ret < 0) {
pr_debug("%s returns %d\n", __func__, ret);
return ret;
}
@@ -2280,7 +2284,7 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
/* loop over all ext compat/ext prop descriptors */
while (feature_count--) {
ret = entity(type, h, data, len, priv);
- if (unlikely(ret < 0)) {
+ if (ret < 0) {
pr_debug("bad OS descriptor, type: %d\n", type);
return ret;
}
@@ -2320,7 +2324,7 @@ static int __must_check ffs_do_os_descs(unsigned count,
return -EINVAL;
ret = __ffs_do_os_desc_header(&type, desc);
- if (unlikely(ret < 0)) {
+ if (ret < 0) {
pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
num, ret);
return ret;
@@ -2341,7 +2345,7 @@ static int __must_check ffs_do_os_descs(unsigned count,
*/
ret = ffs_do_single_os_desc(data, len, type,
feature_count, entity, priv, desc);
- if (unlikely(ret < 0)) {
+ if (ret < 0) {
pr_debug("%s returns %d\n", __func__, ret);
return ret;
}
@@ -2573,20 +2577,20 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
ENTER();
- if (unlikely(len < 16 ||
- get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
- get_unaligned_le32(data + 4) != len))
+ if (len < 16 ||
+ get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+ get_unaligned_le32(data + 4) != len)
goto error;
str_count = get_unaligned_le32(data + 8);
lang_count = get_unaligned_le32(data + 12);
/* if one is zero the other must be zero */
- if (unlikely(!str_count != !lang_count))
+ if (!str_count != !lang_count)
goto error;
/* Do we have at least as many strings as descriptors need? */
needed_count = ffs->strings_count;
- if (unlikely(str_count < needed_count))
+ if (str_count < needed_count)
goto error;
/*
@@ -2610,7 +2614,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
- if (unlikely(!vlabuf)) {
+ if (!vlabuf) {
kfree(_data);
return -ENOMEM;
}
@@ -2637,7 +2641,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
do { /* lang_count > 0 so we can use do-while */
unsigned needed = needed_count;
- if (unlikely(len < 3))
+ if (len < 3)
goto error_free;
t->language = get_unaligned_le16(data);
t->strings = s;
@@ -2650,7 +2654,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
do { /* str_count > 0 so we can use do-while */
size_t length = strnlen(data, len);
- if (unlikely(length == len))
+ if (length == len)
goto error_free;
/*
@@ -2658,7 +2662,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
* if that's the case we simply ignore the
* rest
*/
- if (likely(needed)) {
+ if (needed) {
/*
* s->id will be set while adding
* function to configuration so for
@@ -2680,7 +2684,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
} while (--lang_count);
/* Some garbage left? */
- if (unlikely(len))
+ if (len)
goto error_free;
/* Done! */
@@ -2827,7 +2831,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
ffs_ep = func->eps + idx;
- if (unlikely(ffs_ep->descs[ep_desc_id])) {
+ if (ffs_ep->descs[ep_desc_id]) {
pr_err("two %sspeed descriptors for EP %d\n",
speed_names[ep_desc_id],
ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
@@ -2858,12 +2862,12 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
wMaxPacketSize = ds->wMaxPacketSize;
pr_vdebug("autoconfig\n");
ep = usb_ep_autoconfig(func->gadget, ds);
- if (unlikely(!ep))
+ if (!ep)
return -ENOTSUPP;
ep->driver_data = func->eps + idx;
req = usb_ep_alloc_request(ep, GFP_KERNEL);
- if (unlikely(!req))
+ if (!req)
return -ENOMEM;
ffs_ep->ep = ep;
@@ -2905,7 +2909,7 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
idx = *valuep;
if (func->interfaces_nums[idx] < 0) {
int id = usb_interface_id(func->conf, &func->function);
- if (unlikely(id < 0))
+ if (id < 0)
return id;
func->interfaces_nums[idx] = id;
}
@@ -2926,7 +2930,7 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
return 0;
idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
- if (unlikely(!func->eps[idx].ep))
+ if (!func->eps[idx].ep)
return -EINVAL;
{
@@ -3109,12 +3113,12 @@ static int _ffs_func_bind(struct usb_configuration *c,
ENTER();
/* Has descriptors only for speeds gadget does not support */
- if (unlikely(!(full | high | super)))
+ if (!(full | high | super))
return -ENOTSUPP;
/* Allocate a single chunk, less management later on */
vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
- if (unlikely(!vlabuf))
+ if (!vlabuf)
return -ENOMEM;
ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
@@ -3143,13 +3147,13 @@ static int _ffs_func_bind(struct usb_configuration *c,
* endpoints first, so that later we can rewrite the endpoint
* numbers without worrying that it may be described later on.
*/
- if (likely(full)) {
+ if (full) {
func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
fs_len = ffs_do_descs(ffs->fs_descs_count,
vla_ptr(vlabuf, d, raw_descs),
d_raw_descs__sz,
__ffs_func_bind_do_descs, func);
- if (unlikely(fs_len < 0)) {
+ if (fs_len < 0) {
ret = fs_len;
goto error;
}
@@ -3157,13 +3161,13 @@ static int _ffs_func_bind(struct usb_configuration *c,
fs_len = 0;
}
- if (likely(high)) {
+ if (high) {
func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
hs_len = ffs_do_descs(ffs->hs_descs_count,
vla_ptr(vlabuf, d, raw_descs) + fs_len,
d_raw_descs__sz - fs_len,
__ffs_func_bind_do_descs, func);
- if (unlikely(hs_len < 0)) {
+ if (hs_len < 0) {
ret = hs_len;
goto error;
}
@@ -3171,13 +3175,14 @@ static int _ffs_func_bind(struct usb_configuration *c,
hs_len = 0;
}
- if (likely(super)) {
- func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
+ if (super) {
+ func->function.ss_descriptors = func->function.ssp_descriptors =
+ vla_ptr(vlabuf, d, ss_descs);
ss_len = ffs_do_descs(ffs->ss_descs_count,
vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
d_raw_descs__sz - fs_len - hs_len,
__ffs_func_bind_do_descs, func);
- if (unlikely(ss_len < 0)) {
+ if (ss_len < 0) {
ret = ss_len;
goto error;
}
@@ -3195,7 +3200,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
(super ? ffs->ss_descs_count : 0),
vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
__ffs_func_bind_do_nums, func);
- if (unlikely(ret < 0))
+ if (ret < 0)
goto error;
func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
@@ -3216,7 +3221,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
d_raw_descs__sz - fs_len - hs_len -
ss_len,
__ffs_func_bind_do_os_desc, func);
- if (unlikely(ret < 0))
+ if (ret < 0)
goto error;
}
func->function.os_desc_n =
@@ -3267,7 +3272,7 @@ static int ffs_func_set_alt(struct usb_function *f,
if (alt != (unsigned)-1) {
intf = ffs_func_revmap_intf(func, interface);
- if (unlikely(intf < 0))
+ if (intf < 0)
return intf;
}
@@ -3292,7 +3297,7 @@ static int ffs_func_set_alt(struct usb_function *f,
ffs->func = func;
ret = ffs_func_eps_enable(func);
- if (likely(ret >= 0))
+ if (ret >= 0)
ffs_event_add(ffs, FUNCTIONFS_ENABLE);
return ret;
}
@@ -3334,13 +3339,13 @@ static int ffs_func_setup(struct usb_function *f,
switch (creq->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
- if (unlikely(ret < 0))
+ if (ret < 0)
return ret;
break;
case USB_RECIP_ENDPOINT:
ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
- if (unlikely(ret < 0))
+ if (ret < 0)
return ret;
if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
ret = func->ffs->eps_addrmap[ret];
@@ -3582,6 +3587,7 @@ static void ffs_func_unbind(struct usb_configuration *c,
func->function.fs_descriptors = NULL;
func->function.hs_descriptors = NULL;
func->function.ss_descriptors = NULL;
+ func->function.ssp_descriptors = NULL;
func->interfaces_nums = NULL;
ffs_event_add(ffs, FUNCTIONFS_UNBIND);
@@ -3594,7 +3600,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
ENTER();
func = kzalloc(sizeof(*func), GFP_KERNEL);
- if (unlikely(!func))
+ if (!func)
return ERR_PTR(-ENOMEM);
func->function.name = "Function FS Gadget";
@@ -3809,7 +3815,7 @@ done:
static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
{
return nonblock
- ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
+ ? mutex_trylock(mutex) ? 0 : -EAGAIN
: mutex_lock_interruptible(mutex);
}
@@ -3817,14 +3823,14 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)
{
char *data;
- if (unlikely(!len))
+ if (!len)
return NULL;
data = kmalloc(len, GFP_KERNEL);
- if (unlikely(!data))
+ if (!data)
return ERR_PTR(-ENOMEM);
- if (unlikely(copy_from_user(data, buf, len))) {
+ if (copy_from_user(data, buf, len)) {
kfree(data);
return ERR_PTR(-EFAULT);
}
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index 1803646b3678..b56ad7c3838b 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -274,7 +274,7 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
default:
ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
- /* FALLTHROUGH */
+ fallthrough;
/* NOTE: since this driver doesn't maintain an explicit record
* of requests it submitted (just maintains qlen count), we
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 85cb15734aa8..8fff995b8dd5 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1048,6 +1048,12 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
f->ss_descriptors = usb_copy_descriptors(midi_function);
if (!f->ss_descriptors)
goto fail_f_midi;
+
+ if (gadget_is_superspeed_plus(c->cdev->gadget)) {
+ f->ssp_descriptors = usb_copy_descriptors(midi_function);
+ if (!f->ssp_descriptors)
+ goto fail_f_midi;
+ }
}
kfree(midi_function);
@@ -1315,7 +1321,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
midi->id = kstrdup(opts->id, GFP_KERNEL);
if (opts->id && !midi->id) {
status = -ENOMEM;
- goto setup_fail;
+ goto midi_free;
}
midi->in_ports = opts->in_ports;
midi->out_ports = opts->out_ports;
@@ -1327,7 +1333,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL);
if (status)
- goto setup_fail;
+ goto midi_free;
spin_lock_init(&midi->transmit_lock);
@@ -1343,9 +1349,13 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
return &midi->func;
+midi_free:
+ if (midi)
+ kfree(midi->id);
+ kfree(midi);
setup_fail:
mutex_unlock(&opts->lock);
- kfree(midi);
+
return ERR_PTR(status);
}
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 9534c8ab62a8..0739b05a0ef7 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -87,8 +87,10 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)
/* peak (theoretical) bulk transfer rate in bits-per-second */
static unsigned int bitrate(struct usb_gadget *g)
{
+ if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
+ return 4250000000U;
if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
- return 13 * 1024 * 8 * 1000 * 8;
+ return 3750000000U;
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return 13 * 512 * 8 * 1000 * 8;
else
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index ed68a4860b7d..5a201ba7b155 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -559,6 +559,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
#if 1
DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
+ break;
#endif
case -EREMOTEIO: /* short read */
break;
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index f7e6c42558eb..b859a158a414 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -204,7 +204,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
if (!(filp->f_mode & FMODE_WRITE))
ro = 1;
- inode = file_inode(filp);
+ inode = filp->f_mapping->host;
if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
LINFO(curlun, "invalid file type: %s\n", filename);
goto out;
@@ -221,7 +221,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
if (!(filp->f_mode & FMODE_CAN_WRITE))
ro = 1;
- size = i_size_read(inode->i_mapping->host);
+ size = i_size_read(inode);
if (size < 0) {
LINFO(curlun, "unable to find file size: %s\n", filename);
rc = (int) size;
@@ -231,8 +231,8 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
if (curlun->cdrom) {
blksize = 2048;
blkbits = 11;
- } else if (inode->i_bdev) {
- blksize = bdev_logical_block_size(inode->i_bdev);
+ } else if (S_ISBLK(inode->i_mode)) {
+ blksize = bdev_logical_block_size(I_BDEV(inode));
blkbits = blksize_bits(blksize);
} else {
blksize = 512;
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 1b430b36d0a6..71e7d10dd76b 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -2039,6 +2039,9 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
return 0;
Enomem:
+ kfree(CHIP);
+ CHIP = NULL;
+
return -ENOMEM;
}
diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index e01e366d89cd..062dfac30399 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -564,9 +564,12 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
return -ENODEV;
}
length = min(arg.length, event->length);
- if (copy_to_user((void __user *)value, event, sizeof(*event) + length))
+ if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
+ kfree(event);
return -EFAULT;
+ }
+ kfree(event);
return 0;
}
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index debf54205d22..5b5cfeb6c14a 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -897,8 +897,6 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
* @ep: the endpoint to be used with with the request
* @req: the request being given back
*
- * Context: in_interrupt()
- *
* This is called by device controller drivers in order to return the
* completed request back to the gadget layer.
*/
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 53a227217f1c..ab5e978b5052 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -553,6 +553,7 @@ static int dummy_enable(struct usb_ep *_ep,
/* we'll fake any legal size */
break;
/* save a return statement */
+ fallthrough;
default:
goto done;
}
@@ -595,6 +596,7 @@ static int dummy_enable(struct usb_ep *_ep,
if (max <= 1023)
break;
/* save a return statement */
+ fallthrough;
default:
goto done;
}
@@ -1754,8 +1756,10 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
return ret_val;
}
-/* drive both sides of the transfers; looks like irq handlers to
- * both drivers except the callbacks aren't in_irq().
+/*
+ * Drive both sides of the transfers; looks like irq handlers to both
+ * drivers except that the callbacks are invoked from soft interrupt
+ * context.
*/
static void dummy_timer(struct timer_list *t)
{
@@ -2734,7 +2738,7 @@ static int __init init(void)
{
int retval = -ENOMEM;
int i;
- struct dummy *dum[MAX_NUM_UDC];
+ struct dummy *dum[MAX_NUM_UDC] = {};
if (usb_disabled())
return -ENODEV;
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index de528e3b0662..ad6ff9c4188e 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1051,7 +1051,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
u32 bitmask;
struct ep_queue_head *qh;
- if (!_ep || _ep->desc || !(_ep->desc->bEndpointAddress&0xF))
+ if (!_ep || !_ep->desc || !(_ep->desc->bEndpointAddress&0xF))
return -ENODEV;
ep = container_of(_ep, struct fsl_ep, ep);
diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c
index 25c1d6ab5adb..3e1267d38774 100644
--- a/drivers/usb/gadget/udc/goku_udc.c
+++ b/drivers/usb/gadget/udc/goku_udc.c
@@ -1760,6 +1760,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err;
}
+ pci_set_drvdata(pdev, dev);
spin_lock_init(&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &goku_ops;
@@ -1793,7 +1794,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
dev->regs = (struct goku_udc_regs __iomem *) base;
- pci_set_drvdata(pdev, dev);
INFO(dev, "%s\n", driver_desc);
INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr());
INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base);
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index cfaeca457fa7..ce57961dfd2d 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -304,7 +304,7 @@ static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
* update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
* @udc: pxa udc
*
- * Context: in_interrupt()
+ * Context: interrupt handler
*
* Updates all pxa_ep fields in udc_usb_ep structures, if this field was
* previously set up (and is not NULL). The update is necessary is a
@@ -859,7 +859,7 @@ static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
* @ep: pxa physical endpoint
* @req: usb request
*
- * Context: callable when in_interrupt()
+ * Context: interrupt handler
*
* Unload as many packets as possible from the fifo we use for usb OUT
* transfers and put them into the request. Caller should have made sure
@@ -997,7 +997,7 @@ static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
* @ep: control endpoint
* @req: request
*
- * Context: callable when in_interrupt()
+ * Context: interrupt handler
*
* Sends a request (or a part of the request) to the control endpoint (ep0 in).
* If the request doesn't fit, the remaining part will be sent from irq.
@@ -1036,8 +1036,8 @@ static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
* @_req: usb request
* @gfp_flags: flags
*
- * Context: normally called when !in_interrupt, but callable when in_interrupt()
- * in the special case of ep0 setup :
+ * Context: thread context or from the interrupt handler in the
+ * special case of ep0 setup :
* (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
*
* Returns 0 if succedeed, error otherwise
@@ -1512,7 +1512,8 @@ static int should_disable_udc(struct pxa_udc *udc)
* pxa_udc_pullup - Offer manual D+ pullup control
* @_gadget: usb gadget using the control
* @is_active: 0 if disconnect, else connect D+ pullup resistor
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
*
* Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup
*/
@@ -1560,7 +1561,7 @@ static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
* @_gadget: usb gadget
* @mA: current drawn
*
- * Context: !in_interrupt()
+ * Context: task context, might sleep
*
* Called after a configuration was chosen by a USB host, to inform how much
* current can be drawn by the device from VBus line.
@@ -1886,7 +1887,7 @@ stall:
* @fifo_irq: 1 if triggered by fifo service type irq
* @opc_irq: 1 if triggered by output packet complete type irq
*
- * Context : when in_interrupt() or with ep->lock held
+ * Context : interrupt handler
*
* Tries to transfer all pending request data into the endpoint and/or
* transfer all pending data in the endpoint into usb requests.
@@ -2011,7 +2012,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
* Tries to transfer all pending request data into the endpoint and/or
* transfer all pending data in the endpoint into usb requests.
*
- * Is always called when in_interrupt() and with ep->lock released.
+ * Is always called from the interrupt handler. ep->lock must not be held.
*/
static void handle_ep(struct pxa_ep *ep)
{
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ab12c4bf0ef1..31e59309da1f 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -213,13 +213,6 @@ config USB_EHCI_FSL
help
Variation of ARC USB block used in some Freescale chips.
-config USB_EHCI_MXC
- tristate "Support for Freescale i.MX on-chip EHCI USB controller"
- depends on ARCH_MXC || COMPILE_TEST
- select USB_EHCI_ROOT_HUB_TT
- help
- Variation of ARC USB block used in some Freescale chips.
-
config USB_EHCI_HCD_NPCM7XX
tristate "Support for Nuvoton NPCM7XX on-chip EHCI USB controller"
depends on (USB_EHCI_HCD && ARCH_NPCM7XX) || COMPILE_TEST
@@ -741,16 +734,6 @@ config USB_RENESAS_USBHS_HCD
To compile this driver as a module, choose M here: the
module will be called renesas-usbhs.
-config USB_IMX21_HCD
- tristate "i.MX21 HCD support"
- depends on ARM && ARCH_MXC
- help
- This driver enables support for the on-chip USB host in the
- i.MX21 processor.
-
- To compile this driver as a module, choose M here: the
- module will be called "imx21-hcd".
-
config USB_HCD_BCMA
tristate "BCMA usb host driver"
depends on BCMA
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index bc731332fed9..c1b08703af10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -40,7 +40,6 @@ obj-$(CONFIG_USB_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
-obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
obj-$(CONFIG_USB_EHCI_HCD_NPCM7XX) += ehci-npcm7xx.o
obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
@@ -81,7 +80,6 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 1e8b59ab2272..6f7bd6641694 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -39,10 +39,10 @@ static struct hc_driver __read_mostly fsl_ehci_hc_driver;
/*
* fsl_ehci_drv_probe - initialize FSL-based HCDs
* @pdev: USB Host Controller being probed
- * Context: !in_interrupt()
*
- * Allocates basic resources for this USB host controller.
+ * Context: task context, might sleep
*
+ * Allocates basic resources for this USB host controller.
*/
static int fsl_ehci_drv_probe(struct platform_device *pdev)
{
@@ -684,12 +684,11 @@ static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = {
/**
* fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs
* @pdev: USB Host Controller being removed
- * Context: !in_interrupt()
*
- * Reverses the effect of usb_hcd_fsl_probe().
+ * Context: task context, might sleep
*
+ * Reverses the effect of usb_hcd_fsl_probe().
*/
-
static int fsl_ehci_drv_remove(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 3575b7201881..e358ae17d51e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -867,7 +867,7 @@ static int ehci_urb_enqueue (
*/
if (urb->transfer_buffer_length > (16 * 1024))
return -EMSGSIZE;
- /* FALLTHROUGH */
+ fallthrough;
/* case PIPE_BULK: */
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
deleted file mode 100644
index dc2676320527..000000000000
--- a/drivers/usb/host/ehci-mxc.c
+++ /dev/null
@@ -1,213 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/platform_data/usb-ehci-mxc.h>
-#include "ehci.h"
-
-#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
-
-static const char hcd_name[] = "ehci-mxc";
-
-#define ULPI_VIEWPORT_OFFSET 0x170
-
-struct ehci_mxc_priv {
- struct clk *usbclk, *ahbclk, *phyclk;
-};
-
-static struct hc_driver __read_mostly ehci_mxc_hc_driver;
-
-static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = {
- .extra_priv_size = sizeof(struct ehci_mxc_priv),
-};
-
-static int ehci_mxc_drv_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev);
- struct usb_hcd *hcd;
- struct resource *res;
- int irq, ret;
- struct ehci_mxc_priv *priv;
- struct ehci_hcd *ehci;
-
- if (!pdata) {
- dev_err(dev, "No platform data given, bailing out.\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
- if (!hcd)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(hcd->regs)) {
- ret = PTR_ERR(hcd->regs);
- goto err_alloc;
- }
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
- hcd->has_tt = 1;
- ehci = hcd_to_ehci(hcd);
- priv = (struct ehci_mxc_priv *) ehci->priv;
-
- /* enable clocks */
- priv->usbclk = devm_clk_get(dev, "ipg");
- if (IS_ERR(priv->usbclk)) {
- ret = PTR_ERR(priv->usbclk);
- goto err_alloc;
- }
- clk_prepare_enable(priv->usbclk);
-
- priv->ahbclk = devm_clk_get(dev, "ahb");
- if (IS_ERR(priv->ahbclk)) {
- ret = PTR_ERR(priv->ahbclk);
- goto err_clk_ahb;
- }
- clk_prepare_enable(priv->ahbclk);
-
- /* "dr" device has its own clock on i.MX51 */
- priv->phyclk = devm_clk_get(dev, "phy");
- if (IS_ERR(priv->phyclk))
- priv->phyclk = NULL;
- if (priv->phyclk)
- clk_prepare_enable(priv->phyclk);
-
- /* call platform specific init function */
- if (pdata->init) {
- ret = pdata->init(pdev);
- if (ret) {
- dev_err(dev, "platform init failed\n");
- goto err_init;
- }
- /* platforms need some time to settle changed IO settings */
- mdelay(10);
- }
-
- /* EHCI registers start at offset 0x100 */
- ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- /* set up the PORTSCx register */
- ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
-
- /* is this really needed? */
- msleep(10);
-
- /* Initialize the transceiver */
- if (pdata->otg) {
- pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
- ret = usb_phy_init(pdata->otg);
- if (ret) {
- dev_err(dev, "unable to init transceiver, probably missing\n");
- ret = -ENODEV;
- goto err_add;
- }
- ret = otg_set_vbus(pdata->otg->otg, 1);
- if (ret) {
- dev_err(dev, "unable to enable vbus on transceiver\n");
- goto err_add;
- }
- }
-
- platform_set_drvdata(pdev, hcd);
-
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret)
- goto err_add;
-
- device_wakeup_enable(hcd->self.controller);
- return 0;
-
-err_add:
- if (pdata && pdata->exit)
- pdata->exit(pdev);
-err_init:
- if (priv->phyclk)
- clk_disable_unprepare(priv->phyclk);
-
- clk_disable_unprepare(priv->ahbclk);
-err_clk_ahb:
- clk_disable_unprepare(priv->usbclk);
-err_alloc:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int ehci_mxc_drv_remove(struct platform_device *pdev)
-{
- struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
-
- usb_remove_hcd(hcd);
-
- if (pdata && pdata->exit)
- pdata->exit(pdev);
-
- if (pdata && pdata->otg)
- usb_phy_shutdown(pdata->otg);
-
- clk_disable_unprepare(priv->usbclk);
- clk_disable_unprepare(priv->ahbclk);
-
- if (priv->phyclk)
- clk_disable_unprepare(priv->phyclk);
-
- usb_put_hcd(hcd);
- return 0;
-}
-
-MODULE_ALIAS("platform:mxc-ehci");
-
-static struct platform_driver ehci_mxc_driver = {
- .probe = ehci_mxc_drv_probe,
- .remove = ehci_mxc_drv_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "mxc-ehci",
- },
-};
-
-static int __init ehci_mxc_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
- ehci_init_driver(&ehci_mxc_hc_driver, &ehci_mxc_overrides);
- return platform_driver_register(&ehci_mxc_driver);
-}
-module_init(ehci_mxc_init);
-
-static void __exit ehci_mxc_cleanup(void)
-{
- platform_driver_unregister(&ehci_mxc_driver);
-}
-module_exit(ehci_mxc_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Sascha Hauer");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 8771a2ed6926..7f4a03e8647a 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -220,6 +220,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
err_pm_runtime:
pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
err_phy:
for (i = 0; i < omap->nports; i++) {
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index 2d462fbbe0a6..5fb92b956cc7 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -147,12 +147,14 @@ err1:
/**
* usb_hcd_msp_probe - initialize PMC MSP-based HCDs
- * Context: !in_interrupt()
+ * @driver: Pointer to hc driver instance
+ * @dev: USB controller to probe
+ *
+ * Context: task context, might sleep
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
- *
*/
int usb_hcd_msp_probe(const struct hc_driver *driver,
struct platform_device *dev)
@@ -223,8 +225,9 @@ err1:
/**
* usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ * @hcd: USB Host Controller being removed
+ *
+ * Context: task context, might sleep
*
* Reverses the effect of usb_hcd_msp_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
@@ -233,7 +236,7 @@ err1:
* may be called without controller electrically present
* may be called with controller, bus, and devices active
*/
-void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)
+static void usb_hcd_msp_remove(struct usb_hcd *hcd)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
@@ -306,7 +309,7 @@ static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- usb_hcd_msp_remove(hcd, pdev);
+ usb_hcd_msp_remove(hcd);
/* free TWI GPIO USB_HOST_DEV pin */
gpio_free(MSP_PIN_USB0_HOST_DEV);
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index fb52133c3557..98568b046a1a 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -200,7 +200,7 @@ fail_start:
return result;
}
-static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
+static void ps3_ehci_remove(struct ps3_system_bus_device *dev)
{
unsigned int tmp;
struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
@@ -227,8 +227,6 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
ps3_dma_region_free(dev->d_region);
ps3_close_hv_device(dev);
-
- return 0;
}
static int __init ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 6dfb242f9a4b..0f85aa9b2fb1 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -244,6 +244,12 @@ static void reserve_release_intr_bandwidth(struct ehci_hcd *ehci,
/* FS/LS bus bandwidth */
if (tt_usecs) {
+ /*
+ * find_tt() will not return any error here as we have
+ * already called find_tt() before calling this function
+ * and checked for any error return. The previous call
+ * would have created the data structure.
+ */
tt = find_tt(qh->ps.udev);
if (sign > 0)
list_add_tail(&qh->ps.ps_list, &tt->ps_list);
@@ -1337,6 +1343,12 @@ static void reserve_release_iso_bandwidth(struct ehci_hcd *ehci,
}
}
+ /*
+ * find_tt() will not return any error here as we have
+ * already called find_tt() before calling this function
+ * and checked for any error return. The previous call
+ * would have created the data structure.
+ */
tt = find_tt(stream->ps.udev);
if (sign > 0)
list_add_tail(&stream->ps.ps_list, &tt->ps_list);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index e077b2ca53c5..869d9c4de5fc 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -479,8 +479,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
u_phy->otg->host = hcd_to_bus(hcd);
irq = platform_get_irq(pdev, 0);
- if (!irq) {
- err = -ENODEV;
+ if (irq < 0) {
+ err = irq;
goto cleanup_phy;
}
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 1d94fcfac2c2..5617ef30530a 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -1951,7 +1951,7 @@ static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
goto fail;
/* Hardware periodic table */
- fotg210->periodic = (__le32 *)
+ fotg210->periodic =
dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
fotg210->periodic_size * sizeof(__le32),
&fotg210->periodic_dma, 0);
@@ -5276,7 +5276,7 @@ static int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
*/
if (urb->transfer_buffer_length > (16 * 1024))
return -EMSGSIZE;
- /* FALLTHROUGH */
+ fallthrough;
/* case PIPE_BULK: */
default:
if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index ae8f60f6e6a5..44a7e58a26e3 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -94,10 +94,13 @@ static struct platform_device *fsl_usb2_device_register(
pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
- if (!pdev->dev.dma_mask)
+ if (!pdev->dev.dma_mask) {
pdev->dev.dma_mask = &ofdev->dev.coherent_dma_mask;
- else
- dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ } else {
+ retval = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (retval)
+ goto error;
+ }
retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
if (retval)
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
deleted file mode 100644
index 02a1344fbd6a..000000000000
--- a/drivers/usb/host/imx21-dbg.c
+++ /dev/null
@@ -1,439 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2009 by Martin Fuzzey
- */
-
-/* this file is part of imx21-hcd.c */
-
-#ifdef CONFIG_DYNAMIC_DEBUG
-#define DEBUG
-#endif
-
-#ifndef DEBUG
-
-static inline void create_debug_files(struct imx21 *imx21) { }
-static inline void remove_debug_files(struct imx21 *imx21) { }
-static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {}
-static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb,
- int status) {}
-static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {}
-static inline void debug_urb_queued_for_etd(struct imx21 *imx21,
- struct urb *urb) {}
-static inline void debug_urb_queued_for_dmem(struct imx21 *imx21,
- struct urb *urb) {}
-static inline void debug_etd_allocated(struct imx21 *imx21) {}
-static inline void debug_etd_freed(struct imx21 *imx21) {}
-static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {}
-static inline void debug_dmem_freed(struct imx21 *imx21, int size) {}
-static inline void debug_isoc_submitted(struct imx21 *imx21,
- int frame, struct td *td) {}
-static inline void debug_isoc_completed(struct imx21 *imx21,
- int frame, struct td *td, int cc, int len) {}
-
-#else
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static const char *dir_labels[] = {
- "TD 0",
- "OUT",
- "IN",
- "TD 1"
-};
-
-static const char *speed_labels[] = {
- "Full",
- "Low"
-};
-
-static const char *format_labels[] = {
- "Control",
- "ISO",
- "Bulk",
- "Interrupt"
-};
-
-static inline struct debug_stats *stats_for_urb(struct imx21 *imx21,
- struct urb *urb)
-{
- return usb_pipeisoc(urb->pipe) ?
- &imx21->isoc_stats : &imx21->nonisoc_stats;
-}
-
-static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb)
-{
- stats_for_urb(imx21, urb)->submitted++;
-}
-
-static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st)
-{
- if (st)
- stats_for_urb(imx21, urb)->completed_failed++;
- else
- stats_for_urb(imx21, urb)->completed_ok++;
-}
-
-static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb)
-{
- stats_for_urb(imx21, urb)->unlinked++;
-}
-
-static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb)
-{
- stats_for_urb(imx21, urb)->queue_etd++;
-}
-
-static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb)
-{
- stats_for_urb(imx21, urb)->queue_dmem++;
-}
-
-static inline void debug_etd_allocated(struct imx21 *imx21)
-{
- imx21->etd_usage.maximum = max(
- ++(imx21->etd_usage.value),
- imx21->etd_usage.maximum);
-}
-
-static inline void debug_etd_freed(struct imx21 *imx21)
-{
- imx21->etd_usage.value--;
-}
-
-static inline void debug_dmem_allocated(struct imx21 *imx21, int size)
-{
- imx21->dmem_usage.value += size;
- imx21->dmem_usage.maximum = max(
- imx21->dmem_usage.value,
- imx21->dmem_usage.maximum);
-}
-
-static inline void debug_dmem_freed(struct imx21 *imx21, int size)
-{
- imx21->dmem_usage.value -= size;
-}
-
-
-static void debug_isoc_submitted(struct imx21 *imx21,
- int frame, struct td *td)
-{
- struct debug_isoc_trace *trace = &imx21->isoc_trace[
- imx21->isoc_trace_index++];
-
- imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace);
- trace->schedule_frame = td->frame;
- trace->submit_frame = frame;
- trace->request_len = td->len;
- trace->td = td;
-}
-
-static inline void debug_isoc_completed(struct imx21 *imx21,
- int frame, struct td *td, int cc, int len)
-{
- struct debug_isoc_trace *trace, *trace_failed;
- int i;
- int found = 0;
-
- trace = imx21->isoc_trace;
- for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) {
- if (trace->td == td) {
- trace->done_frame = frame;
- trace->done_len = len;
- trace->cc = cc;
- trace->td = NULL;
- found = 1;
- break;
- }
- }
-
- if (found && cc) {
- trace_failed = &imx21->isoc_trace_failed[
- imx21->isoc_trace_index_failed++];
-
- imx21->isoc_trace_index_failed %= ARRAY_SIZE(
- imx21->isoc_trace_failed);
- *trace_failed = *trace;
- }
-}
-
-
-static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize)
-{
- if (ep)
- snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)",
- ep->desc.bEndpointAddress,
- usb_endpoint_type(&ep->desc),
- ep);
- else
- snprintf(buf, bufsize, "none");
- return buf;
-}
-
-static char *format_etd_dword0(u32 value, char *buf, int bufsize)
-{
- snprintf(buf, bufsize,
- "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
- value & 0x7F,
- (value >> DW0_ENDPNT) & 0x0F,
- dir_labels[(value >> DW0_DIRECT) & 0x03],
- speed_labels[(value >> DW0_SPEED) & 0x01],
- format_labels[(value >> DW0_FORMAT) & 0x03],
- (value >> DW0_HALTED) & 0x01);
- return buf;
-}
-
-static int debug_status_show(struct seq_file *s, void *v)
-{
- struct imx21 *imx21 = s->private;
- int etds_allocated = 0;
- int etds_sw_busy = 0;
- int etds_hw_busy = 0;
- int dmem_blocks = 0;
- int queued_for_etd = 0;
- int queued_for_dmem = 0;
- unsigned int dmem_bytes = 0;
- int i;
- struct etd_priv *etd;
- u32 etd_enable_mask;
- unsigned long flags;
- struct imx21_dmem_area *dmem;
- struct ep_priv *ep_priv;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- etd_enable_mask = readl(imx21->regs + USBH_ETDENSET);
- for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
- if (etd->alloc)
- etds_allocated++;
- if (etd->urb)
- etds_sw_busy++;
- if (etd_enable_mask & (1<<i))
- etds_hw_busy++;
- }
-
- list_for_each_entry(dmem, &imx21->dmem_list, list) {
- dmem_bytes += dmem->size;
- dmem_blocks++;
- }
-
- list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue)
- queued_for_etd++;
-
- list_for_each_entry(etd, &imx21->queue_for_dmem, queue)
- queued_for_dmem++;
-
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- seq_printf(s,
- "Frame: %d\n"
- "ETDs allocated: %d/%d (max=%d)\n"
- "ETDs in use sw: %d\n"
- "ETDs in use hw: %d\n"
- "DMEM allocated: %d/%d (max=%d)\n"
- "DMEM blocks: %d\n"
- "Queued waiting for ETD: %d\n"
- "Queued waiting for DMEM: %d\n",
- readl(imx21->regs + USBH_FRMNUB) & 0xFFFF,
- etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum,
- etds_sw_busy,
- etds_hw_busy,
- dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum,
- dmem_blocks,
- queued_for_etd,
- queued_for_dmem);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_status);
-
-static int debug_dmem_show(struct seq_file *s, void *v)
-{
- struct imx21 *imx21 = s->private;
- struct imx21_dmem_area *dmem;
- unsigned long flags;
- char ep_text[40];
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- list_for_each_entry(dmem, &imx21->dmem_list, list)
- seq_printf(s,
- "%04X: size=0x%X "
- "ep=%s\n",
- dmem->offset, dmem->size,
- format_ep(dmem->ep, ep_text, sizeof(ep_text)));
-
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_dmem);
-
-static int debug_etd_show(struct seq_file *s, void *v)
-{
- struct imx21 *imx21 = s->private;
- struct etd_priv *etd;
- char buf[60];
- u32 dword;
- int i, j;
- unsigned long flags;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
- int state = -1;
- struct urb_priv *urb_priv;
- if (etd->urb) {
- urb_priv = etd->urb->hcpriv;
- if (urb_priv)
- state = urb_priv->state;
- }
-
- seq_printf(s,
- "etd_num: %d\n"
- "ep: %s\n"
- "alloc: %d\n"
- "len: %d\n"
- "busy sw: %d\n"
- "busy hw: %d\n"
- "urb state: %d\n"
- "current urb: %p\n",
-
- i,
- format_ep(etd->ep, buf, sizeof(buf)),
- etd->alloc,
- etd->len,
- etd->urb != NULL,
- (readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0,
- state,
- etd->urb);
-
- for (j = 0; j < 4; j++) {
- dword = etd_readl(imx21, i, j);
- switch (j) {
- case 0:
- format_etd_dword0(dword, buf, sizeof(buf));
- break;
- case 2:
- snprintf(buf, sizeof(buf),
- "cc=0X%02X", dword >> DW2_COMPCODE);
- break;
- default:
- *buf = 0;
- break;
- }
- seq_printf(s,
- "dword %d: submitted=%08X cur=%08X [%s]\n",
- j,
- etd->submitted_dwords[j],
- dword,
- buf);
- }
- seq_printf(s, "\n");
- }
-
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_etd);
-
-static void debug_statistics_show_one(struct seq_file *s,
- const char *name, struct debug_stats *stats)
-{
- seq_printf(s, "%s:\n"
- "submitted URBs: %lu\n"
- "completed OK: %lu\n"
- "completed failed: %lu\n"
- "unlinked: %lu\n"
- "queued for ETD: %lu\n"
- "queued for DMEM: %lu\n\n",
- name,
- stats->submitted,
- stats->completed_ok,
- stats->completed_failed,
- stats->unlinked,
- stats->queue_etd,
- stats->queue_dmem);
-}
-
-static int debug_statistics_show(struct seq_file *s, void *v)
-{
- struct imx21 *imx21 = s->private;
- unsigned long flags;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats);
- debug_statistics_show_one(s, "isoc", &imx21->isoc_stats);
- seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks);
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_statistics);
-
-static void debug_isoc_show_one(struct seq_file *s,
- const char *name, int index, struct debug_isoc_trace *trace)
-{
- seq_printf(s, "%s %d:\n"
- "cc=0X%02X\n"
- "scheduled frame %d (%d)\n"
- "submitted frame %d (%d)\n"
- "completed frame %d (%d)\n"
- "requested length=%d\n"
- "completed length=%d\n\n",
- name, index,
- trace->cc,
- trace->schedule_frame, trace->schedule_frame & 0xFFFF,
- trace->submit_frame, trace->submit_frame & 0xFFFF,
- trace->done_frame, trace->done_frame & 0xFFFF,
- trace->request_len,
- trace->done_len);
-}
-
-static int debug_isoc_show(struct seq_file *s, void *v)
-{
- struct imx21 *imx21 = s->private;
- struct debug_isoc_trace *trace;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- trace = imx21->isoc_trace_failed;
- for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++)
- debug_isoc_show_one(s, "isoc failed", i, trace);
-
- trace = imx21->isoc_trace;
- for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++)
- debug_isoc_show_one(s, "isoc", i, trace);
-
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(debug_isoc);
-
-static void create_debug_files(struct imx21 *imx21)
-{
- struct dentry *root;
-
- root = debugfs_create_dir(dev_name(imx21->dev), usb_debug_root);
- imx21->debug_root = root;
-
- debugfs_create_file("status", S_IRUGO, root, imx21, &debug_status_fops);
- debugfs_create_file("dmem", S_IRUGO, root, imx21, &debug_dmem_fops);
- debugfs_create_file("etd", S_IRUGO, root, imx21, &debug_etd_fops);
- debugfs_create_file("statistics", S_IRUGO, root, imx21,
- &debug_statistics_fops);
- debugfs_create_file("isoc", S_IRUGO, root, imx21, &debug_isoc_fops);
-}
-
-static void remove_debug_files(struct imx21 *imx21)
-{
- debugfs_remove_recursive(imx21->debug_root);
-}
-
-#endif
-
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
deleted file mode 100644
index b2716cb72471..000000000000
--- a/drivers/usb/host/imx21-hcd.c
+++ /dev/null
@@ -1,1933 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * USB Host Controller Driver for IMX21
- *
- * Copyright (C) 2006 Loping Dog Embedded Systems
- * Copyright (C) 2009 Martin Fuzzey
- * Originally written by Jay Monkman <jtm@lopingdog.com>
- * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
- */
-
-
- /*
- * The i.MX21 USB hardware contains
- * * 32 transfer descriptors (called ETDs)
- * * 4Kb of Data memory
- *
- * The data memory is shared between the host and function controllers
- * (but this driver only supports the host controller)
- *
- * So setting up a transfer involves:
- * * Allocating a ETD
- * * Fill in ETD with appropriate information
- * * Allocating data memory (and putting the offset in the ETD)
- * * Activate the ETD
- * * Get interrupt when done.
- *
- * An ETD is assigned to each active endpoint.
- *
- * Low resource (ETD and Data memory) situations are handled differently for
- * isochronous and non insosynchronous transactions :
- *
- * Non ISOC transfers are queued if either ETDs or Data memory are unavailable
- *
- * ISOC transfers use 2 ETDs per endpoint to achieve double buffering.
- * They allocate both ETDs and Data memory during URB submission
- * (and fail if unavailable).
- */
-
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-
-#include "imx21-hcd.h"
-
-#ifdef CONFIG_DYNAMIC_DEBUG
-#define DEBUG
-#endif
-
-#ifdef DEBUG
-#define DEBUG_LOG_FRAME(imx21, etd, event) \
- (etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB)
-#else
-#define DEBUG_LOG_FRAME(imx21, etd, event) do { } while (0)
-#endif
-
-static const char hcd_name[] = "imx21-hcd";
-
-static inline struct imx21 *hcd_to_imx21(struct usb_hcd *hcd)
-{
- return (struct imx21 *)hcd->hcd_priv;
-}
-
-
-/* =========================================== */
-/* Hardware access helpers */
-/* =========================================== */
-
-static inline void set_register_bits(struct imx21 *imx21, u32 offset, u32 mask)
-{
- void __iomem *reg = imx21->regs + offset;
- writel(readl(reg) | mask, reg);
-}
-
-static inline void clear_register_bits(struct imx21 *imx21,
- u32 offset, u32 mask)
-{
- void __iomem *reg = imx21->regs + offset;
- writel(readl(reg) & ~mask, reg);
-}
-
-static inline void clear_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
-{
- void __iomem *reg = imx21->regs + offset;
-
- if (readl(reg) & mask)
- writel(mask, reg);
-}
-
-static inline void set_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
-{
- void __iomem *reg = imx21->regs + offset;
-
- if (!(readl(reg) & mask))
- writel(mask, reg);
-}
-
-static void etd_writel(struct imx21 *imx21, int etd_num, int dword, u32 value)
-{
- writel(value, imx21->regs + USB_ETD_DWORD(etd_num, dword));
-}
-
-static u32 etd_readl(struct imx21 *imx21, int etd_num, int dword)
-{
- return readl(imx21->regs + USB_ETD_DWORD(etd_num, dword));
-}
-
-static inline int wrap_frame(int counter)
-{
- return counter & 0xFFFF;
-}
-
-static inline int frame_after(int frame, int after)
-{
- /* handle wrapping like jiffies time_afer */
- return (s16)((s16)after - (s16)frame) < 0;
-}
-
-static int imx21_hc_get_frame(struct usb_hcd *hcd)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
-
- return wrap_frame(readl(imx21->regs + USBH_FRMNUB));
-}
-
-static inline bool unsuitable_for_dma(dma_addr_t addr)
-{
- return (addr & 3) != 0;
-}
-
-#include "imx21-dbg.c"
-
-static void nonisoc_urb_completed_for_etd(
- struct imx21 *imx21, struct etd_priv *etd, int status);
-static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb);
-static void free_dmem(struct imx21 *imx21, struct etd_priv *etd);
-
-/* =========================================== */
-/* ETD management */
-/* =========================================== */
-
-static int alloc_etd(struct imx21 *imx21)
-{
- int i;
- struct etd_priv *etd = imx21->etd;
-
- for (i = 0; i < USB_NUM_ETD; i++, etd++) {
- if (etd->alloc == 0) {
- memset(etd, 0, sizeof(imx21->etd[0]));
- etd->alloc = 1;
- debug_etd_allocated(imx21);
- return i;
- }
- }
- return -1;
-}
-
-static void disactivate_etd(struct imx21 *imx21, int num)
-{
- int etd_mask = (1 << num);
- struct etd_priv *etd = &imx21->etd[num];
-
- writel(etd_mask, imx21->regs + USBH_ETDENCLR);
- clear_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
- writel(etd_mask, imx21->regs + USB_ETDDMACHANLCLR);
- clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
-
- etd->active_count = 0;
-
- DEBUG_LOG_FRAME(imx21, etd, disactivated);
-}
-
-static void reset_etd(struct imx21 *imx21, int num)
-{
- struct etd_priv *etd = imx21->etd + num;
- int i;
-
- disactivate_etd(imx21, num);
-
- for (i = 0; i < 4; i++)
- etd_writel(imx21, num, i, 0);
- etd->urb = NULL;
- etd->ep = NULL;
- etd->td = NULL;
- etd->bounce_buffer = NULL;
-}
-
-static void free_etd(struct imx21 *imx21, int num)
-{
- if (num < 0)
- return;
-
- if (num >= USB_NUM_ETD) {
- dev_err(imx21->dev, "BAD etd=%d!\n", num);
- return;
- }
- if (imx21->etd[num].alloc == 0) {
- dev_err(imx21->dev, "ETD %d already free!\n", num);
- return;
- }
-
- debug_etd_freed(imx21);
- reset_etd(imx21, num);
- memset(&imx21->etd[num], 0, sizeof(imx21->etd[0]));
-}
-
-
-static void setup_etd_dword0(struct imx21 *imx21,
- int etd_num, struct urb *urb, u8 dir, u16 maxpacket)
-{
- etd_writel(imx21, etd_num, 0,
- ((u32) usb_pipedevice(urb->pipe)) << DW0_ADDRESS |
- ((u32) usb_pipeendpoint(urb->pipe) << DW0_ENDPNT) |
- ((u32) dir << DW0_DIRECT) |
- ((u32) ((urb->dev->speed == USB_SPEED_LOW) ?
- 1 : 0) << DW0_SPEED) |
- ((u32) fmt_urb_to_etd[usb_pipetype(urb->pipe)] << DW0_FORMAT) |
- ((u32) maxpacket << DW0_MAXPKTSIZ));
-}
-
-/*
- * Copy buffer to data controller data memory.
- * We cannot use memcpy_toio() because the hardware requires 32bit writes
- */
-static void copy_to_dmem(
- struct imx21 *imx21, int dmem_offset, void *src, int count)
-{
- void __iomem *dmem = imx21->regs + USBOTG_DMEM + dmem_offset;
- u32 word = 0;
- u8 *p = src;
- int byte = 0;
- int i;
-
- for (i = 0; i < count; i++) {
- byte = i % 4;
- word += (*p++ << (byte * 8));
- if (byte == 3) {
- writel(word, dmem);
- dmem += 4;
- word = 0;
- }
- }
-
- if (count && byte != 3)
- writel(word, dmem);
-}
-
-static void activate_etd(struct imx21 *imx21, int etd_num, u8 dir)
-{
- u32 etd_mask = 1 << etd_num;
- struct etd_priv *etd = &imx21->etd[etd_num];
-
- if (etd->dma_handle && unsuitable_for_dma(etd->dma_handle)) {
- /* For non aligned isoc the condition below is always true */
- if (etd->len <= etd->dmem_size) {
- /* Fits into data memory, use PIO */
- if (dir != TD_DIR_IN) {
- copy_to_dmem(imx21,
- etd->dmem_offset,
- etd->cpu_buffer, etd->len);
- }
- etd->dma_handle = 0;
-
- } else {
- /* Too big for data memory, use bounce buffer */
- enum dma_data_direction dmadir;
-
- if (dir == TD_DIR_IN) {
- dmadir = DMA_FROM_DEVICE;
- etd->bounce_buffer = kmalloc(etd->len,
- GFP_ATOMIC);
- } else {
- dmadir = DMA_TO_DEVICE;
- etd->bounce_buffer = kmemdup(etd->cpu_buffer,
- etd->len,
- GFP_ATOMIC);
- }
- if (!etd->bounce_buffer) {
- dev_err(imx21->dev, "failed bounce alloc\n");
- goto err_bounce_alloc;
- }
-
- etd->dma_handle =
- dma_map_single(imx21->dev,
- etd->bounce_buffer,
- etd->len,
- dmadir);
- if (dma_mapping_error(imx21->dev, etd->dma_handle)) {
- dev_err(imx21->dev, "failed bounce map\n");
- goto err_bounce_map;
- }
- }
- }
-
- clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
- set_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
- clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
- clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
-
- if (etd->dma_handle) {
- set_register_bits(imx21, USB_ETDDMACHANLCLR, etd_mask);
- clear_toggle_bit(imx21, USBH_XBUFSTAT, etd_mask);
- clear_toggle_bit(imx21, USBH_YBUFSTAT, etd_mask);
- writel(etd->dma_handle, imx21->regs + USB_ETDSMSA(etd_num));
- set_register_bits(imx21, USB_ETDDMAEN, etd_mask);
- } else {
- if (dir != TD_DIR_IN) {
- /* need to set for ZLP and PIO */
- set_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
- set_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
- }
- }
-
- DEBUG_LOG_FRAME(imx21, etd, activated);
-
-#ifdef DEBUG
- if (!etd->active_count) {
- int i;
- etd->activated_frame = readl(imx21->regs + USBH_FRMNUB);
- etd->disactivated_frame = -1;
- etd->last_int_frame = -1;
- etd->last_req_frame = -1;
-
- for (i = 0; i < 4; i++)
- etd->submitted_dwords[i] = etd_readl(imx21, etd_num, i);
- }
-#endif
-
- etd->active_count = 1;
- writel(etd_mask, imx21->regs + USBH_ETDENSET);
- return;
-
-err_bounce_map:
- kfree(etd->bounce_buffer);
-
-err_bounce_alloc:
- free_dmem(imx21, etd);
- nonisoc_urb_completed_for_etd(imx21, etd, -ENOMEM);
-}
-
-/* =========================================== */
-/* Data memory management */
-/* =========================================== */
-
-static int alloc_dmem(struct imx21 *imx21, unsigned int size,
- struct usb_host_endpoint *ep)
-{
- unsigned int offset = 0;
- struct imx21_dmem_area *area;
- struct imx21_dmem_area *tmp;
-
- size += (~size + 1) & 0x3; /* Round to 4 byte multiple */
-
- if (size > DMEM_SIZE) {
- dev_err(imx21->dev, "size=%d > DMEM_SIZE(%d)\n",
- size, DMEM_SIZE);
- return -EINVAL;
- }
-
- list_for_each_entry(tmp, &imx21->dmem_list, list) {
- if ((size + offset) < offset)
- goto fail;
- if ((size + offset) <= tmp->offset)
- break;
- offset = tmp->size + tmp->offset;
- if ((offset + size) > DMEM_SIZE)
- goto fail;
- }
-
- area = kmalloc(sizeof(struct imx21_dmem_area), GFP_ATOMIC);
- if (area == NULL)
- return -ENOMEM;
-
- area->ep = ep;
- area->offset = offset;
- area->size = size;
- list_add_tail(&area->list, &tmp->list);
- debug_dmem_allocated(imx21, size);
- return offset;
-
-fail:
- return -ENOMEM;
-}
-
-/* Memory now available for a queued ETD - activate it */
-static void activate_queued_etd(struct imx21 *imx21,
- struct etd_priv *etd, u32 dmem_offset)
-{
- struct urb_priv *urb_priv = etd->urb->hcpriv;
- int etd_num = etd - &imx21->etd[0];
- u32 maxpacket = etd_readl(imx21, etd_num, 1) >> DW1_YBUFSRTAD;
- u8 dir = (etd_readl(imx21, etd_num, 2) >> DW2_DIRPID) & 0x03;
-
- dev_dbg(imx21->dev, "activating queued ETD %d now DMEM available\n",
- etd_num);
- etd_writel(imx21, etd_num, 1,
- ((dmem_offset + maxpacket) << DW1_YBUFSRTAD) | dmem_offset);
-
- etd->dmem_offset = dmem_offset;
- urb_priv->active = 1;
- activate_etd(imx21, etd_num, dir);
-}
-
-static void free_dmem(struct imx21 *imx21, struct etd_priv *etd)
-{
- struct imx21_dmem_area *area;
- struct etd_priv *tmp;
- int found = 0;
- int offset;
-
- if (!etd->dmem_size)
- return;
- etd->dmem_size = 0;
-
- offset = etd->dmem_offset;
- list_for_each_entry(area, &imx21->dmem_list, list) {
- if (area->offset == offset) {
- debug_dmem_freed(imx21, area->size);
- list_del(&area->list);
- kfree(area);
- found = 1;
- break;
- }
- }
-
- if (!found) {
- dev_err(imx21->dev,
- "Trying to free unallocated DMEM %d\n", offset);
- return;
- }
-
- /* Try again to allocate memory for anything we've queued */
- list_for_each_entry_safe(etd, tmp, &imx21->queue_for_dmem, queue) {
- offset = alloc_dmem(imx21, etd->dmem_size, etd->ep);
- if (offset >= 0) {
- list_del(&etd->queue);
- activate_queued_etd(imx21, etd, (u32)offset);
- }
- }
-}
-
-static void free_epdmem(struct imx21 *imx21, struct usb_host_endpoint *ep)
-{
- struct imx21_dmem_area *area, *tmp;
-
- list_for_each_entry_safe(area, tmp, &imx21->dmem_list, list) {
- if (area->ep == ep) {
- dev_err(imx21->dev,
- "Active DMEM %d for disabled ep=%p\n",
- area->offset, ep);
- list_del(&area->list);
- kfree(area);
- }
- }
-}
-
-
-/* =========================================== */
-/* End handling */
-/* =========================================== */
-
-/* Endpoint now idle - release its ETD(s) or assign to queued request */
-static void ep_idle(struct imx21 *imx21, struct ep_priv *ep_priv)
-{
- int i;
-
- for (i = 0; i < NUM_ISO_ETDS; i++) {
- int etd_num = ep_priv->etd[i];
- struct etd_priv *etd;
- if (etd_num < 0)
- continue;
-
- etd = &imx21->etd[etd_num];
- ep_priv->etd[i] = -1;
-
- free_dmem(imx21, etd); /* for isoc */
-
- if (list_empty(&imx21->queue_for_etd)) {
- free_etd(imx21, etd_num);
- continue;
- }
-
- dev_dbg(imx21->dev,
- "assigning idle etd %d for queued request\n", etd_num);
- ep_priv = list_first_entry(&imx21->queue_for_etd,
- struct ep_priv, queue);
- list_del(&ep_priv->queue);
- reset_etd(imx21, etd_num);
- ep_priv->waiting_etd = 0;
- ep_priv->etd[i] = etd_num;
-
- if (list_empty(&ep_priv->ep->urb_list)) {
- dev_err(imx21->dev, "No urb for queued ep!\n");
- continue;
- }
- schedule_nonisoc_etd(imx21, list_first_entry(
- &ep_priv->ep->urb_list, struct urb, urb_list));
- }
-}
-
-static void urb_done(struct usb_hcd *hcd, struct urb *urb, int status)
-__releases(imx21->lock)
-__acquires(imx21->lock)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- struct ep_priv *ep_priv = urb->ep->hcpriv;
- struct urb_priv *urb_priv = urb->hcpriv;
-
- debug_urb_completed(imx21, urb, status);
- dev_vdbg(imx21->dev, "urb %p done %d\n", urb, status);
-
- kfree(urb_priv->isoc_td);
- kfree(urb->hcpriv);
- urb->hcpriv = NULL;
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&imx21->lock);
- usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&imx21->lock);
- if (list_empty(&ep_priv->ep->urb_list))
- ep_idle(imx21, ep_priv);
-}
-
-static void nonisoc_urb_completed_for_etd(
- struct imx21 *imx21, struct etd_priv *etd, int status)
-{
- struct usb_host_endpoint *ep = etd->ep;
-
- urb_done(imx21->hcd, etd->urb, status);
- etd->urb = NULL;
-
- if (!list_empty(&ep->urb_list)) {
- struct urb *urb = list_first_entry(
- &ep->urb_list, struct urb, urb_list);
-
- dev_vdbg(imx21->dev, "next URB %p\n", urb);
- schedule_nonisoc_etd(imx21, urb);
- }
-}
-
-
-/* =========================================== */
-/* ISOC Handling ... */
-/* =========================================== */
-
-static void schedule_isoc_etds(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- struct ep_priv *ep_priv = ep->hcpriv;
- struct etd_priv *etd;
- struct urb_priv *urb_priv;
- struct td *td;
- int etd_num;
- int i;
- int cur_frame;
- u8 dir;
-
- for (i = 0; i < NUM_ISO_ETDS; i++) {
-too_late:
- if (list_empty(&ep_priv->td_list))
- break;
-
- etd_num = ep_priv->etd[i];
- if (etd_num < 0)
- break;
-
- etd = &imx21->etd[etd_num];
- if (etd->urb)
- continue;
-
- td = list_entry(ep_priv->td_list.next, struct td, list);
- list_del(&td->list);
- urb_priv = td->urb->hcpriv;
-
- cur_frame = imx21_hc_get_frame(hcd);
- if (frame_after(cur_frame, td->frame)) {
- dev_dbg(imx21->dev, "isoc too late frame %d > %d\n",
- cur_frame, td->frame);
- urb_priv->isoc_status = -EXDEV;
- td->urb->iso_frame_desc[
- td->isoc_index].actual_length = 0;
- td->urb->iso_frame_desc[td->isoc_index].status = -EXDEV;
- if (--urb_priv->isoc_remaining == 0)
- urb_done(hcd, td->urb, urb_priv->isoc_status);
- goto too_late;
- }
-
- urb_priv->active = 1;
- etd->td = td;
- etd->ep = td->ep;
- etd->urb = td->urb;
- etd->len = td->len;
- etd->dma_handle = td->dma_handle;
- etd->cpu_buffer = td->cpu_buffer;
-
- debug_isoc_submitted(imx21, cur_frame, td);
-
- dir = usb_pipeout(td->urb->pipe) ? TD_DIR_OUT : TD_DIR_IN;
- setup_etd_dword0(imx21, etd_num, td->urb, dir, etd->dmem_size);
- etd_writel(imx21, etd_num, 1, etd->dmem_offset);
- etd_writel(imx21, etd_num, 2,
- (TD_NOTACCESSED << DW2_COMPCODE) |
- ((td->frame & 0xFFFF) << DW2_STARTFRM));
- etd_writel(imx21, etd_num, 3,
- (TD_NOTACCESSED << DW3_COMPCODE0) |
- (td->len << DW3_PKTLEN0));
-
- activate_etd(imx21, etd_num, dir);
- }
-}
-
-static void isoc_etd_done(struct usb_hcd *hcd, int etd_num)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- int etd_mask = 1 << etd_num;
- struct etd_priv *etd = imx21->etd + etd_num;
- struct urb *urb = etd->urb;
- struct urb_priv *urb_priv = urb->hcpriv;
- struct td *td = etd->td;
- struct usb_host_endpoint *ep = etd->ep;
- int isoc_index = td->isoc_index;
- unsigned int pipe = urb->pipe;
- int dir_in = usb_pipein(pipe);
- int cc;
- int bytes_xfrd;
-
- disactivate_etd(imx21, etd_num);
-
- cc = (etd_readl(imx21, etd_num, 3) >> DW3_COMPCODE0) & 0xf;
- bytes_xfrd = etd_readl(imx21, etd_num, 3) & 0x3ff;
-
- /* Input doesn't always fill the buffer, don't generate an error
- * when this happens.
- */
- if (dir_in && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- if (cc == TD_NOTACCESSED)
- bytes_xfrd = 0;
-
- debug_isoc_completed(imx21,
- imx21_hc_get_frame(hcd), td, cc, bytes_xfrd);
- if (cc) {
- urb_priv->isoc_status = -EXDEV;
- dev_dbg(imx21->dev,
- "bad iso cc=0x%X frame=%d sched frame=%d "
- "cnt=%d len=%d urb=%p etd=%d index=%d\n",
- cc, imx21_hc_get_frame(hcd), td->frame,
- bytes_xfrd, td->len, urb, etd_num, isoc_index);
- }
-
- if (dir_in) {
- clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
- if (!etd->dma_handle)
- memcpy_fromio(etd->cpu_buffer,
- imx21->regs + USBOTG_DMEM + etd->dmem_offset,
- bytes_xfrd);
- }
-
- urb->actual_length += bytes_xfrd;
- urb->iso_frame_desc[isoc_index].actual_length = bytes_xfrd;
- urb->iso_frame_desc[isoc_index].status = cc_to_error[cc];
-
- etd->td = NULL;
- etd->urb = NULL;
- etd->ep = NULL;
-
- if (--urb_priv->isoc_remaining == 0)
- urb_done(hcd, urb, urb_priv->isoc_status);
-
- schedule_isoc_etds(hcd, ep);
-}
-
-static struct ep_priv *alloc_isoc_ep(
- struct imx21 *imx21, struct usb_host_endpoint *ep)
-{
- struct ep_priv *ep_priv;
- int i;
-
- ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
- if (!ep_priv)
- return NULL;
-
- for (i = 0; i < NUM_ISO_ETDS; i++)
- ep_priv->etd[i] = -1;
-
- INIT_LIST_HEAD(&ep_priv->td_list);
- ep_priv->ep = ep;
- ep->hcpriv = ep_priv;
- return ep_priv;
-}
-
-static int alloc_isoc_etds(struct imx21 *imx21, struct ep_priv *ep_priv)
-{
- int i, j;
- int etd_num;
-
- /* Allocate the ETDs if required */
- for (i = 0; i < NUM_ISO_ETDS; i++) {
- if (ep_priv->etd[i] < 0) {
- etd_num = alloc_etd(imx21);
- if (etd_num < 0)
- goto alloc_etd_failed;
-
- ep_priv->etd[i] = etd_num;
- imx21->etd[etd_num].ep = ep_priv->ep;
- }
- }
- return 0;
-
-alloc_etd_failed:
- dev_err(imx21->dev, "isoc: Couldn't allocate etd\n");
- for (j = 0; j < i; j++) {
- free_etd(imx21, ep_priv->etd[j]);
- ep_priv->etd[j] = -1;
- }
- return -ENOMEM;
-}
-
-static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
- struct urb *urb, gfp_t mem_flags)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- struct urb_priv *urb_priv;
- unsigned long flags;
- struct ep_priv *ep_priv;
- struct td *td = NULL;
- int i;
- int ret;
- int cur_frame;
- u16 maxpacket;
-
- urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
- if (urb_priv == NULL)
- return -ENOMEM;
-
- urb_priv->isoc_td = kcalloc(urb->number_of_packets, sizeof(struct td),
- mem_flags);
- if (urb_priv->isoc_td == NULL) {
- ret = -ENOMEM;
- goto alloc_td_failed;
- }
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- if (ep->hcpriv == NULL) {
- ep_priv = alloc_isoc_ep(imx21, ep);
- if (ep_priv == NULL) {
- ret = -ENOMEM;
- goto alloc_ep_failed;
- }
- } else {
- ep_priv = ep->hcpriv;
- }
-
- ret = alloc_isoc_etds(imx21, ep_priv);
- if (ret)
- goto alloc_etd_failed;
-
- ret = usb_hcd_link_urb_to_ep(hcd, urb);
- if (ret)
- goto link_failed;
-
- urb->status = -EINPROGRESS;
- urb->actual_length = 0;
- urb->error_count = 0;
- urb->hcpriv = urb_priv;
- urb_priv->ep = ep;
-
- /* allocate data memory for largest packets if not already done */
- maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
- for (i = 0; i < NUM_ISO_ETDS; i++) {
- struct etd_priv *etd = &imx21->etd[ep_priv->etd[i]];
-
- if (etd->dmem_size > 0 && etd->dmem_size < maxpacket) {
- /* not sure if this can really occur.... */
- dev_err(imx21->dev, "increasing isoc buffer %d->%d\n",
- etd->dmem_size, maxpacket);
- ret = -EMSGSIZE;
- goto alloc_dmem_failed;
- }
-
- if (etd->dmem_size == 0) {
- etd->dmem_offset = alloc_dmem(imx21, maxpacket, ep);
- if (etd->dmem_offset < 0) {
- dev_dbg(imx21->dev, "failed alloc isoc dmem\n");
- ret = -EAGAIN;
- goto alloc_dmem_failed;
- }
- etd->dmem_size = maxpacket;
- }
- }
-
- /* calculate frame */
- cur_frame = imx21_hc_get_frame(hcd);
- i = 0;
- if (list_empty(&ep_priv->td_list)) {
- urb->start_frame = wrap_frame(cur_frame + 5);
- } else {
- urb->start_frame = wrap_frame(list_entry(ep_priv->td_list.prev,
- struct td, list)->frame + urb->interval);
-
- if (frame_after(cur_frame, urb->start_frame)) {
- dev_dbg(imx21->dev,
- "enqueue: adjusting iso start %d (cur=%d) asap=%d\n",
- urb->start_frame, cur_frame,
- (urb->transfer_flags & URB_ISO_ASAP) != 0);
- i = DIV_ROUND_UP(wrap_frame(
- cur_frame - urb->start_frame),
- urb->interval);
-
- /* Treat underruns as if URB_ISO_ASAP was set */
- if ((urb->transfer_flags & URB_ISO_ASAP) ||
- i >= urb->number_of_packets) {
- urb->start_frame = wrap_frame(urb->start_frame
- + i * urb->interval);
- i = 0;
- }
- }
- }
-
- /* set up transfers */
- urb_priv->isoc_remaining = urb->number_of_packets - i;
- td = urb_priv->isoc_td;
- for (; i < urb->number_of_packets; i++, td++) {
- unsigned int offset = urb->iso_frame_desc[i].offset;
- td->ep = ep;
- td->urb = urb;
- td->len = urb->iso_frame_desc[i].length;
- td->isoc_index = i;
- td->frame = wrap_frame(urb->start_frame + urb->interval * i);
- td->dma_handle = urb->transfer_dma + offset;
- td->cpu_buffer = urb->transfer_buffer + offset;
- list_add_tail(&td->list, &ep_priv->td_list);
- }
-
- dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n",
- urb->number_of_packets, urb->start_frame, td->frame);
-
- debug_urb_submitted(imx21, urb);
- schedule_isoc_etds(hcd, ep);
-
- spin_unlock_irqrestore(&imx21->lock, flags);
- return 0;
-
-alloc_dmem_failed:
- usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-link_failed:
-alloc_etd_failed:
-alloc_ep_failed:
- spin_unlock_irqrestore(&imx21->lock, flags);
- kfree(urb_priv->isoc_td);
-
-alloc_td_failed:
- kfree(urb_priv);
- return ret;
-}
-
-static void dequeue_isoc_urb(struct imx21 *imx21,
- struct urb *urb, struct ep_priv *ep_priv)
-{
- struct urb_priv *urb_priv = urb->hcpriv;
- struct td *td, *tmp;
- int i;
-
- if (urb_priv->active) {
- for (i = 0; i < NUM_ISO_ETDS; i++) {
- int etd_num = ep_priv->etd[i];
- if (etd_num != -1 && imx21->etd[etd_num].urb == urb) {
- struct etd_priv *etd = imx21->etd + etd_num;
-
- reset_etd(imx21, etd_num);
- free_dmem(imx21, etd);
- }
- }
- }
-
- list_for_each_entry_safe(td, tmp, &ep_priv->td_list, list) {
- if (td->urb == urb) {
- dev_vdbg(imx21->dev, "removing td %p\n", td);
- list_del(&td->list);
- }
- }
-}
-
-/* =========================================== */
-/* NON ISOC Handling ... */
-/* =========================================== */
-
-static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
-{
- unsigned int pipe = urb->pipe;
- struct urb_priv *urb_priv = urb->hcpriv;
- struct ep_priv *ep_priv = urb_priv->ep->hcpriv;
- int state = urb_priv->state;
- int etd_num = ep_priv->etd[0];
- struct etd_priv *etd;
- u32 count;
- u16 etd_buf_size;
- u16 maxpacket;
- u8 dir;
- u8 bufround;
- u8 datatoggle;
- u8 interval = 0;
- u8 relpolpos = 0;
-
- if (etd_num < 0) {
- dev_err(imx21->dev, "No valid ETD\n");
- return;
- }
- if (readl(imx21->regs + USBH_ETDENSET) & (1 << etd_num))
- dev_err(imx21->dev, "submitting to active ETD %d\n", etd_num);
-
- etd = &imx21->etd[etd_num];
- maxpacket = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
- if (!maxpacket)
- maxpacket = 8;
-
- if (usb_pipecontrol(pipe) && (state != US_CTRL_DATA)) {
- if (state == US_CTRL_SETUP) {
- dir = TD_DIR_SETUP;
- if (unsuitable_for_dma(urb->setup_dma))
- usb_hcd_unmap_urb_setup_for_dma(imx21->hcd,
- urb);
- etd->dma_handle = urb->setup_dma;
- etd->cpu_buffer = urb->setup_packet;
- bufround = 0;
- count = 8;
- datatoggle = TD_TOGGLE_DATA0;
- } else { /* US_CTRL_ACK */
- dir = usb_pipeout(pipe) ? TD_DIR_IN : TD_DIR_OUT;
- bufround = 0;
- count = 0;
- datatoggle = TD_TOGGLE_DATA1;
- }
- } else {
- dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN;
- bufround = (dir == TD_DIR_IN) ? 1 : 0;
- if (unsuitable_for_dma(urb->transfer_dma))
- usb_hcd_unmap_urb_for_dma(imx21->hcd, urb);
-
- etd->dma_handle = urb->transfer_dma;
- etd->cpu_buffer = urb->transfer_buffer;
- if (usb_pipebulk(pipe) && (state == US_BULK0))
- count = 0;
- else
- count = urb->transfer_buffer_length;
-
- if (usb_pipecontrol(pipe)) {
- datatoggle = TD_TOGGLE_DATA1;
- } else {
- if (usb_gettoggle(
- urb->dev,
- usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe)))
- datatoggle = TD_TOGGLE_DATA1;
- else
- datatoggle = TD_TOGGLE_DATA0;
- }
- }
-
- etd->urb = urb;
- etd->ep = urb_priv->ep;
- etd->len = count;
-
- if (usb_pipeint(pipe)) {
- interval = urb->interval;
- relpolpos = (readl(imx21->regs + USBH_FRMNUB) + 1) & 0xff;
- }
-
- /* Write ETD to device memory */
- setup_etd_dword0(imx21, etd_num, urb, dir, maxpacket);
-
- etd_writel(imx21, etd_num, 2,
- (u32) interval << DW2_POLINTERV |
- ((u32) relpolpos << DW2_RELPOLPOS) |
- ((u32) dir << DW2_DIRPID) |
- ((u32) bufround << DW2_BUFROUND) |
- ((u32) datatoggle << DW2_DATATOG) |
- ((u32) TD_NOTACCESSED << DW2_COMPCODE));
-
- /* DMA will always transfer buffer size even if TOBYCNT in DWORD3
- is smaller. Make sure we don't overrun the buffer!
- */
- if (count && count < maxpacket)
- etd_buf_size = count;
- else
- etd_buf_size = maxpacket;
-
- etd_writel(imx21, etd_num, 3,
- ((u32) (etd_buf_size - 1) << DW3_BUFSIZE) | (u32) count);
-
- if (!count)
- etd->dma_handle = 0;
-
- /* allocate x and y buffer space at once */
- etd->dmem_size = (count > maxpacket) ? maxpacket * 2 : maxpacket;
- etd->dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep);
- if (etd->dmem_offset < 0) {
- /* Setup everything we can in HW and update when we get DMEM */
- etd_writel(imx21, etd_num, 1, (u32)maxpacket << 16);
-
- dev_dbg(imx21->dev, "Queuing etd %d for DMEM\n", etd_num);
- debug_urb_queued_for_dmem(imx21, urb);
- list_add_tail(&etd->queue, &imx21->queue_for_dmem);
- return;
- }
-
- etd_writel(imx21, etd_num, 1,
- (((u32) etd->dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) |
- (u32) etd->dmem_offset);
-
- urb_priv->active = 1;
-
- /* enable the ETD to kick off transfer */
- dev_vdbg(imx21->dev, "Activating etd %d for %d bytes %s\n",
- etd_num, count, dir != TD_DIR_IN ? "out" : "in");
- activate_etd(imx21, etd_num, dir);
-
-}
-
-static void nonisoc_etd_done(struct usb_hcd *hcd, int etd_num)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- struct etd_priv *etd = &imx21->etd[etd_num];
- struct urb *urb = etd->urb;
- u32 etd_mask = 1 << etd_num;
- struct urb_priv *urb_priv = urb->hcpriv;
- int dir;
- int cc;
- u32 bytes_xfrd;
- int etd_done;
-
- disactivate_etd(imx21, etd_num);
-
- dir = (etd_readl(imx21, etd_num, 0) >> DW0_DIRECT) & 0x3;
- cc = (etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE) & 0xf;
- bytes_xfrd = etd->len - (etd_readl(imx21, etd_num, 3) & 0x1fffff);
-
- /* save toggle carry */
- usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe),
- (etd_readl(imx21, etd_num, 0) >> DW0_TOGCRY) & 0x1);
-
- if (dir == TD_DIR_IN) {
- clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
- clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
-
- if (etd->bounce_buffer) {
- memcpy(etd->cpu_buffer, etd->bounce_buffer, bytes_xfrd);
- dma_unmap_single(imx21->dev,
- etd->dma_handle, etd->len, DMA_FROM_DEVICE);
- } else if (!etd->dma_handle && bytes_xfrd) {/* PIO */
- memcpy_fromio(etd->cpu_buffer,
- imx21->regs + USBOTG_DMEM + etd->dmem_offset,
- bytes_xfrd);
- }
- }
-
- kfree(etd->bounce_buffer);
- etd->bounce_buffer = NULL;
- free_dmem(imx21, etd);
-
- urb->error_count = 0;
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK)
- && (cc == TD_DATAUNDERRUN))
- cc = TD_CC_NOERROR;
-
- if (cc != 0)
- dev_vdbg(imx21->dev, "cc is 0x%x\n", cc);
-
- etd_done = (cc_to_error[cc] != 0); /* stop if error */
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- switch (urb_priv->state) {
- case US_CTRL_SETUP:
- if (urb->transfer_buffer_length > 0)
- urb_priv->state = US_CTRL_DATA;
- else
- urb_priv->state = US_CTRL_ACK;
- break;
- case US_CTRL_DATA:
- urb->actual_length += bytes_xfrd;
- urb_priv->state = US_CTRL_ACK;
- break;
- case US_CTRL_ACK:
- etd_done = 1;
- break;
- default:
- dev_err(imx21->dev,
- "Invalid pipe state %d\n", urb_priv->state);
- etd_done = 1;
- break;
- }
- break;
-
- case PIPE_BULK:
- urb->actual_length += bytes_xfrd;
- if ((urb_priv->state == US_BULK)
- && (urb->transfer_flags & URB_ZERO_PACKET)
- && urb->transfer_buffer_length > 0
- && ((urb->transfer_buffer_length %
- usb_maxpacket(urb->dev, urb->pipe,
- usb_pipeout(urb->pipe))) == 0)) {
- /* need a 0-packet */
- urb_priv->state = US_BULK0;
- } else {
- etd_done = 1;
- }
- break;
-
- case PIPE_INTERRUPT:
- urb->actual_length += bytes_xfrd;
- etd_done = 1;
- break;
- }
-
- if (etd_done)
- nonisoc_urb_completed_for_etd(imx21, etd, cc_to_error[cc]);
- else {
- dev_vdbg(imx21->dev, "next state=%d\n", urb_priv->state);
- schedule_nonisoc_etd(imx21, urb);
- }
-}
-
-
-static struct ep_priv *alloc_ep(void)
-{
- int i;
- struct ep_priv *ep_priv;
-
- ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
- if (!ep_priv)
- return NULL;
-
- for (i = 0; i < NUM_ISO_ETDS; ++i)
- ep_priv->etd[i] = -1;
-
- return ep_priv;
-}
-
-static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
- struct urb *urb, gfp_t mem_flags)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- struct usb_host_endpoint *ep = urb->ep;
- struct urb_priv *urb_priv;
- struct ep_priv *ep_priv;
- struct etd_priv *etd;
- int ret;
- unsigned long flags;
-
- dev_vdbg(imx21->dev,
- "enqueue urb=%p ep=%p len=%d "
- "buffer=%p dma=%pad setupBuf=%p setupDma=%pad\n",
- urb, ep,
- urb->transfer_buffer_length,
- urb->transfer_buffer, &urb->transfer_dma,
- urb->setup_packet, &urb->setup_dma);
-
- if (usb_pipeisoc(urb->pipe))
- return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags);
-
- urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
- if (!urb_priv)
- return -ENOMEM;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- ep_priv = ep->hcpriv;
- if (ep_priv == NULL) {
- ep_priv = alloc_ep();
- if (!ep_priv) {
- ret = -ENOMEM;
- goto failed_alloc_ep;
- }
- ep->hcpriv = ep_priv;
- ep_priv->ep = ep;
- }
-
- ret = usb_hcd_link_urb_to_ep(hcd, urb);
- if (ret)
- goto failed_link;
-
- urb->status = -EINPROGRESS;
- urb->actual_length = 0;
- urb->error_count = 0;
- urb->hcpriv = urb_priv;
- urb_priv->ep = ep;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- urb_priv->state = US_CTRL_SETUP;
- break;
- case PIPE_BULK:
- urb_priv->state = US_BULK;
- break;
- }
-
- debug_urb_submitted(imx21, urb);
- if (ep_priv->etd[0] < 0) {
- if (ep_priv->waiting_etd) {
- dev_dbg(imx21->dev,
- "no ETD available already queued %p\n",
- ep_priv);
- debug_urb_queued_for_etd(imx21, urb);
- goto out;
- }
- ep_priv->etd[0] = alloc_etd(imx21);
- if (ep_priv->etd[0] < 0) {
- dev_dbg(imx21->dev,
- "no ETD available queueing %p\n", ep_priv);
- debug_urb_queued_for_etd(imx21, urb);
- list_add_tail(&ep_priv->queue, &imx21->queue_for_etd);
- ep_priv->waiting_etd = 1;
- goto out;
- }
- }
-
- /* Schedule if no URB already active for this endpoint */
- etd = &imx21->etd[ep_priv->etd[0]];
- if (etd->urb == NULL) {
- DEBUG_LOG_FRAME(imx21, etd, last_req);
- schedule_nonisoc_etd(imx21, urb);
- }
-
-out:
- spin_unlock_irqrestore(&imx21->lock, flags);
- return 0;
-
-failed_link:
-failed_alloc_ep:
- spin_unlock_irqrestore(&imx21->lock, flags);
- kfree(urb_priv);
- return ret;
-}
-
-static int imx21_hc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
- int status)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- unsigned long flags;
- struct usb_host_endpoint *ep;
- struct ep_priv *ep_priv;
- struct urb_priv *urb_priv = urb->hcpriv;
- int ret = -EINVAL;
-
- dev_vdbg(imx21->dev, "dequeue urb=%p iso=%d status=%d\n",
- urb, usb_pipeisoc(urb->pipe), status);
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- ret = usb_hcd_check_unlink_urb(hcd, urb, status);
- if (ret)
- goto fail;
- ep = urb_priv->ep;
- ep_priv = ep->hcpriv;
-
- debug_urb_unlinked(imx21, urb);
-
- if (usb_pipeisoc(urb->pipe)) {
- dequeue_isoc_urb(imx21, urb, ep_priv);
- schedule_isoc_etds(hcd, ep);
- } else if (urb_priv->active) {
- int etd_num = ep_priv->etd[0];
- if (etd_num != -1) {
- struct etd_priv *etd = &imx21->etd[etd_num];
-
- disactivate_etd(imx21, etd_num);
- free_dmem(imx21, etd);
- etd->urb = NULL;
- kfree(etd->bounce_buffer);
- etd->bounce_buffer = NULL;
- }
- }
-
- urb_done(hcd, urb, status);
-
- spin_unlock_irqrestore(&imx21->lock, flags);
- return 0;
-
-fail:
- spin_unlock_irqrestore(&imx21->lock, flags);
- return ret;
-}
-
-/* =========================================== */
-/* Interrupt dispatch */
-/* =========================================== */
-
-static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof)
-{
- int etd_num;
- int enable_sof_int = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- for (etd_num = 0; etd_num < USB_NUM_ETD; etd_num++) {
- u32 etd_mask = 1 << etd_num;
- u32 enabled = readl(imx21->regs + USBH_ETDENSET) & etd_mask;
- u32 done = readl(imx21->regs + USBH_ETDDONESTAT) & etd_mask;
- struct etd_priv *etd = &imx21->etd[etd_num];
-
-
- if (done) {
- DEBUG_LOG_FRAME(imx21, etd, last_int);
- } else {
-/*
- * Kludge warning!
- *
- * When multiple transfers are using the bus we sometimes get into a state
- * where the transfer has completed (the CC field of the ETD is != 0x0F),
- * the ETD has self disabled but the ETDDONESTAT flag is not set
- * (and hence no interrupt occurs).
- * This causes the transfer in question to hang.
- * The kludge below checks for this condition at each SOF and processes any
- * blocked ETDs (after an arbitrary 10 frame wait)
- *
- * With a single active transfer the usbtest test suite will run for days
- * without the kludge.
- * With other bus activity (eg mass storage) even just test1 will hang without
- * the kludge.
- */
- u32 dword0;
- int cc;
-
- if (etd->active_count && !enabled) /* suspicious... */
- enable_sof_int = 1;
-
- if (!sof || enabled || !etd->active_count)
- continue;
-
- cc = etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE;
- if (cc == TD_NOTACCESSED)
- continue;
-
- if (++etd->active_count < 10)
- continue;
-
- dword0 = etd_readl(imx21, etd_num, 0);
- dev_dbg(imx21->dev,
- "unblock ETD %d dev=0x%X ep=0x%X cc=0x%02X!\n",
- etd_num, dword0 & 0x7F,
- (dword0 >> DW0_ENDPNT) & 0x0F,
- cc);
-
-#ifdef DEBUG
- dev_dbg(imx21->dev,
- "frame: act=%d disact=%d"
- " int=%d req=%d cur=%d\n",
- etd->activated_frame,
- etd->disactivated_frame,
- etd->last_int_frame,
- etd->last_req_frame,
- readl(imx21->regs + USBH_FRMNUB));
- imx21->debug_unblocks++;
-#endif
- etd->active_count = 0;
-/* End of kludge */
- }
-
- if (etd->ep == NULL || etd->urb == NULL) {
- dev_dbg(imx21->dev,
- "Interrupt for unexpected etd %d"
- " ep=%p urb=%p\n",
- etd_num, etd->ep, etd->urb);
- disactivate_etd(imx21, etd_num);
- continue;
- }
-
- if (usb_pipeisoc(etd->urb->pipe))
- isoc_etd_done(hcd, etd_num);
- else
- nonisoc_etd_done(hcd, etd_num);
- }
-
- /* only enable SOF interrupt if it may be needed for the kludge */
- if (enable_sof_int)
- set_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
- else
- clear_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
-
-
- spin_unlock_irqrestore(&imx21->lock, flags);
-}
-
-static irqreturn_t imx21_irq(struct usb_hcd *hcd)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- u32 ints = readl(imx21->regs + USBH_SYSISR);
-
- if (ints & USBH_SYSIEN_HERRINT)
- dev_dbg(imx21->dev, "Scheduling error\n");
-
- if (ints & USBH_SYSIEN_SORINT)
- dev_dbg(imx21->dev, "Scheduling overrun\n");
-
- if (ints & (USBH_SYSISR_DONEINT | USBH_SYSISR_SOFINT))
- process_etds(hcd, imx21, ints & USBH_SYSISR_SOFINT);
-
- writel(ints, imx21->regs + USBH_SYSISR);
- return IRQ_HANDLED;
-}
-
-static void imx21_hc_endpoint_disable(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- unsigned long flags;
- struct ep_priv *ep_priv;
- int i;
-
- if (ep == NULL)
- return;
-
- spin_lock_irqsave(&imx21->lock, flags);
- ep_priv = ep->hcpriv;
- dev_vdbg(imx21->dev, "disable ep=%p, ep->hcpriv=%p\n", ep, ep_priv);
-
- if (!list_empty(&ep->urb_list))
- dev_dbg(imx21->dev, "ep's URB list is not empty\n");
-
- if (ep_priv != NULL) {
- for (i = 0; i < NUM_ISO_ETDS; i++) {
- if (ep_priv->etd[i] > -1)
- dev_dbg(imx21->dev, "free etd %d for disable\n",
- ep_priv->etd[i]);
-
- free_etd(imx21, ep_priv->etd[i]);
- }
- kfree(ep_priv);
- ep->hcpriv = NULL;
- }
-
- for (i = 0; i < USB_NUM_ETD; i++) {
- if (imx21->etd[i].alloc && imx21->etd[i].ep == ep) {
- dev_err(imx21->dev,
- "Active etd %d for disabled ep=%p!\n", i, ep);
- free_etd(imx21, i);
- }
- }
- free_epdmem(imx21, ep);
- spin_unlock_irqrestore(&imx21->lock, flags);
-}
-
-/* =========================================== */
-/* Hub handling */
-/* =========================================== */
-
-static int get_hub_descriptor(struct usb_hcd *hcd,
- struct usb_hub_descriptor *desc)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- desc->bDescriptorType = USB_DT_HUB; /* HUB descriptor */
- desc->bHubContrCurrent = 0;
-
- desc->bNbrPorts = readl(imx21->regs + USBH_ROOTHUBA)
- & USBH_ROOTHUBA_NDNSTMPRT_MASK;
- desc->bDescLength = 9;
- desc->bPwrOn2PwrGood = 0;
- desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
- HUB_CHAR_NO_LPSM | /* No power switching */
- HUB_CHAR_NO_OCPM); /* No over current protection */
-
- desc->u.hs.DeviceRemovable[0] = 1 << 1;
- desc->u.hs.DeviceRemovable[1] = ~0;
- return 0;
-}
-
-static int imx21_hc_hub_status_data(struct usb_hcd *hcd, char *buf)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- int ports;
- int changed = 0;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&imx21->lock, flags);
- ports = readl(imx21->regs + USBH_ROOTHUBA)
- & USBH_ROOTHUBA_NDNSTMPRT_MASK;
- if (ports > 7) {
- ports = 7;
- dev_err(imx21->dev, "ports %d > 7\n", ports);
- }
- for (i = 0; i < ports; i++) {
- if (readl(imx21->regs + USBH_PORTSTAT(i)) &
- (USBH_PORTSTAT_CONNECTSC |
- USBH_PORTSTAT_PRTENBLSC |
- USBH_PORTSTAT_PRTSTATSC |
- USBH_PORTSTAT_OVRCURIC |
- USBH_PORTSTAT_PRTRSTSC)) {
-
- changed = 1;
- buf[0] |= 1 << (i + 1);
- }
- }
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- if (changed)
- dev_info(imx21->dev, "Hub status changed\n");
- return changed;
-}
-
-static int imx21_hc_hub_control(struct usb_hcd *hcd,
- u16 typeReq,
- u16 wValue, u16 wIndex, char *buf, u16 wLength)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- int rc = 0;
- u32 status_write = 0;
-
- switch (typeReq) {
- case ClearHubFeature:
- dev_dbg(imx21->dev, "ClearHubFeature\n");
- switch (wValue) {
- case C_HUB_OVER_CURRENT:
- dev_dbg(imx21->dev, " OVER_CURRENT\n");
- break;
- case C_HUB_LOCAL_POWER:
- dev_dbg(imx21->dev, " LOCAL_POWER\n");
- break;
- default:
- dev_dbg(imx21->dev, " unknown\n");
- rc = -EINVAL;
- break;
- }
- break;
-
- case ClearPortFeature:
- dev_dbg(imx21->dev, "ClearPortFeature\n");
- switch (wValue) {
- case USB_PORT_FEAT_ENABLE:
- dev_dbg(imx21->dev, " ENABLE\n");
- status_write = USBH_PORTSTAT_CURCONST;
- break;
- case USB_PORT_FEAT_SUSPEND:
- dev_dbg(imx21->dev, " SUSPEND\n");
- status_write = USBH_PORTSTAT_PRTOVRCURI;
- break;
- case USB_PORT_FEAT_POWER:
- dev_dbg(imx21->dev, " POWER\n");
- status_write = USBH_PORTSTAT_LSDEVCON;
- break;
- case USB_PORT_FEAT_C_ENABLE:
- dev_dbg(imx21->dev, " C_ENABLE\n");
- status_write = USBH_PORTSTAT_PRTENBLSC;
- break;
- case USB_PORT_FEAT_C_SUSPEND:
- dev_dbg(imx21->dev, " C_SUSPEND\n");
- status_write = USBH_PORTSTAT_PRTSTATSC;
- break;
- case USB_PORT_FEAT_C_CONNECTION:
- dev_dbg(imx21->dev, " C_CONNECTION\n");
- status_write = USBH_PORTSTAT_CONNECTSC;
- break;
- case USB_PORT_FEAT_C_OVER_CURRENT:
- dev_dbg(imx21->dev, " C_OVER_CURRENT\n");
- status_write = USBH_PORTSTAT_OVRCURIC;
- break;
- case USB_PORT_FEAT_C_RESET:
- dev_dbg(imx21->dev, " C_RESET\n");
- status_write = USBH_PORTSTAT_PRTRSTSC;
- break;
- default:
- dev_dbg(imx21->dev, " unknown\n");
- rc = -EINVAL;
- break;
- }
-
- break;
-
- case GetHubDescriptor:
- dev_dbg(imx21->dev, "GetHubDescriptor\n");
- rc = get_hub_descriptor(hcd, (void *)buf);
- break;
-
- case GetHubStatus:
- dev_dbg(imx21->dev, " GetHubStatus\n");
- *(__le32 *) buf = 0;
- break;
-
- case GetPortStatus:
- dev_dbg(imx21->dev, "GetPortStatus: port: %d, 0x%x\n",
- wIndex, USBH_PORTSTAT(wIndex - 1));
- *(__le32 *) buf = readl(imx21->regs +
- USBH_PORTSTAT(wIndex - 1));
- break;
-
- case SetHubFeature:
- dev_dbg(imx21->dev, "SetHubFeature\n");
- switch (wValue) {
- case C_HUB_OVER_CURRENT:
- dev_dbg(imx21->dev, " OVER_CURRENT\n");
- break;
-
- case C_HUB_LOCAL_POWER:
- dev_dbg(imx21->dev, " LOCAL_POWER\n");
- break;
- default:
- dev_dbg(imx21->dev, " unknown\n");
- rc = -EINVAL;
- break;
- }
-
- break;
-
- case SetPortFeature:
- dev_dbg(imx21->dev, "SetPortFeature\n");
- switch (wValue) {
- case USB_PORT_FEAT_SUSPEND:
- dev_dbg(imx21->dev, " SUSPEND\n");
- status_write = USBH_PORTSTAT_PRTSUSPST;
- break;
- case USB_PORT_FEAT_POWER:
- dev_dbg(imx21->dev, " POWER\n");
- status_write = USBH_PORTSTAT_PRTPWRST;
- break;
- case USB_PORT_FEAT_RESET:
- dev_dbg(imx21->dev, " RESET\n");
- status_write = USBH_PORTSTAT_PRTRSTST;
- break;
- default:
- dev_dbg(imx21->dev, " unknown\n");
- rc = -EINVAL;
- break;
- }
- break;
-
- default:
- dev_dbg(imx21->dev, " unknown\n");
- rc = -EINVAL;
- break;
- }
-
- if (status_write)
- writel(status_write, imx21->regs + USBH_PORTSTAT(wIndex - 1));
- return rc;
-}
-
-/* =========================================== */
-/* Host controller management */
-/* =========================================== */
-
-static int imx21_hc_reset(struct usb_hcd *hcd)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- unsigned long timeout;
- unsigned long flags;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- /* Reset the Host controller modules */
- writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH |
- USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC,
- imx21->regs + USBOTG_RST_CTRL);
-
- /* Wait for reset to finish */
- timeout = jiffies + HZ;
- while (readl(imx21->regs + USBOTG_RST_CTRL) != 0) {
- if (time_after(jiffies, timeout)) {
- spin_unlock_irqrestore(&imx21->lock, flags);
- dev_err(imx21->dev, "timeout waiting for reset\n");
- return -ETIMEDOUT;
- }
- spin_unlock_irq(&imx21->lock);
- schedule_timeout_uninterruptible(1);
- spin_lock_irq(&imx21->lock);
- }
- spin_unlock_irqrestore(&imx21->lock, flags);
- return 0;
-}
-
-static int imx21_hc_start(struct usb_hcd *hcd)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- unsigned long flags;
- int i, j;
- u32 hw_mode = USBOTG_HWMODE_CRECFG_HOST;
- u32 usb_control = 0;
-
- hw_mode |= ((imx21->pdata->host_xcvr << USBOTG_HWMODE_HOSTXCVR_SHIFT) &
- USBOTG_HWMODE_HOSTXCVR_MASK);
- hw_mode |= ((imx21->pdata->otg_xcvr << USBOTG_HWMODE_OTGXCVR_SHIFT) &
- USBOTG_HWMODE_OTGXCVR_MASK);
-
- if (imx21->pdata->host1_txenoe)
- usb_control |= USBCTRL_HOST1_TXEN_OE;
-
- if (!imx21->pdata->host1_xcverless)
- usb_control |= USBCTRL_HOST1_BYP_TLL;
-
- if (imx21->pdata->otg_ext_xcvr)
- usb_control |= USBCTRL_OTC_RCV_RXDP;
-
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- writel((USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN),
- imx21->regs + USBOTG_CLK_CTRL);
- writel(hw_mode, imx21->regs + USBOTG_HWMODE);
- writel(usb_control, imx21->regs + USBCTRL);
- writel(USB_MISCCONTROL_SKPRTRY | USB_MISCCONTROL_ARBMODE,
- imx21->regs + USB_MISCCONTROL);
-
- /* Clear the ETDs */
- for (i = 0; i < USB_NUM_ETD; i++)
- for (j = 0; j < 4; j++)
- etd_writel(imx21, i, j, 0);
-
- /* Take the HC out of reset */
- writel(USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL | USBH_HOST_CTRL_CTLBLKSR_1,
- imx21->regs + USBH_HOST_CTRL);
-
- /* Enable ports */
- if (imx21->pdata->enable_otg_host)
- writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
- imx21->regs + USBH_PORTSTAT(0));
-
- if (imx21->pdata->enable_host1)
- writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
- imx21->regs + USBH_PORTSTAT(1));
-
- if (imx21->pdata->enable_host2)
- writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
- imx21->regs + USBH_PORTSTAT(2));
-
-
- hcd->state = HC_STATE_RUNNING;
-
- /* Enable host controller interrupts */
- set_register_bits(imx21, USBH_SYSIEN,
- USBH_SYSIEN_HERRINT |
- USBH_SYSIEN_DONEINT | USBH_SYSIEN_SORINT);
- set_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
-
- spin_unlock_irqrestore(&imx21->lock, flags);
-
- return 0;
-}
-
-static void imx21_hc_stop(struct usb_hcd *hcd)
-{
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- unsigned long flags;
-
- spin_lock_irqsave(&imx21->lock, flags);
-
- writel(0, imx21->regs + USBH_SYSIEN);
- clear_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
- clear_register_bits(imx21, USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN,
- USBOTG_CLK_CTRL);
- spin_unlock_irqrestore(&imx21->lock, flags);
-}
-
-/* =========================================== */
-/* Driver glue */
-/* =========================================== */
-
-static const struct hc_driver imx21_hc_driver = {
- .description = hcd_name,
- .product_desc = "IMX21 USB Host Controller",
- .hcd_priv_size = sizeof(struct imx21),
-
- .flags = HCD_DMA | HCD_USB11,
- .irq = imx21_irq,
-
- .reset = imx21_hc_reset,
- .start = imx21_hc_start,
- .stop = imx21_hc_stop,
-
- /* I/O requests */
- .urb_enqueue = imx21_hc_urb_enqueue,
- .urb_dequeue = imx21_hc_urb_dequeue,
- .endpoint_disable = imx21_hc_endpoint_disable,
-
- /* scheduling support */
- .get_frame_number = imx21_hc_get_frame,
-
- /* Root hub support */
- .hub_status_data = imx21_hc_hub_status_data,
- .hub_control = imx21_hc_hub_control,
-
-};
-
-static struct mx21_usbh_platform_data default_pdata = {
- .host_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
- .otg_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
- .enable_host1 = 1,
- .enable_host2 = 1,
- .enable_otg_host = 1,
-
-};
-
-static int imx21_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct imx21 *imx21 = hcd_to_imx21(hcd);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- remove_debug_files(imx21);
- usb_remove_hcd(hcd);
-
- if (res != NULL) {
- clk_disable_unprepare(imx21->clk);
- clk_put(imx21->clk);
- iounmap(imx21->regs);
- release_mem_region(res->start, resource_size(res));
- }
-
- kfree(hcd);
- return 0;
-}
-
-
-static int imx21_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct imx21 *imx21;
- struct resource *res;
- int ret;
- int irq;
-
- printk(KERN_INFO "%s\n", imx21_hc_driver.product_desc);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- hcd = usb_create_hcd(&imx21_hc_driver,
- &pdev->dev, dev_name(&pdev->dev));
- if (hcd == NULL) {
- dev_err(&pdev->dev, "Cannot create hcd (%s)\n",
- dev_name(&pdev->dev));
- return -ENOMEM;
- }
-
- imx21 = hcd_to_imx21(hcd);
- imx21->hcd = hcd;
- imx21->dev = &pdev->dev;
- imx21->pdata = dev_get_platdata(&pdev->dev);
- if (!imx21->pdata)
- imx21->pdata = &default_pdata;
-
- spin_lock_init(&imx21->lock);
- INIT_LIST_HEAD(&imx21->dmem_list);
- INIT_LIST_HEAD(&imx21->queue_for_etd);
- INIT_LIST_HEAD(&imx21->queue_for_dmem);
- create_debug_files(imx21);
-
- res = request_mem_region(res->start, resource_size(res), hcd_name);
- if (!res) {
- ret = -EBUSY;
- goto failed_request_mem;
- }
-
- imx21->regs = ioremap(res->start, resource_size(res));
- if (imx21->regs == NULL) {
- dev_err(imx21->dev, "Cannot map registers\n");
- ret = -ENOMEM;
- goto failed_ioremap;
- }
-
- /* Enable clocks source */
- imx21->clk = clk_get(imx21->dev, NULL);
- if (IS_ERR(imx21->clk)) {
- dev_err(imx21->dev, "no clock found\n");
- ret = PTR_ERR(imx21->clk);
- goto failed_clock_get;
- }
-
- ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000));
- if (ret)
- goto failed_clock_set;
- ret = clk_prepare_enable(imx21->clk);
- if (ret)
- goto failed_clock_enable;
-
- dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n",
- (readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF);
-
- ret = usb_add_hcd(hcd, irq, 0);
- if (ret != 0) {
- dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);
- goto failed_add_hcd;
- }
- device_wakeup_enable(hcd->self.controller);
-
- return 0;
-
-failed_add_hcd:
- clk_disable_unprepare(imx21->clk);
-failed_clock_enable:
-failed_clock_set:
- clk_put(imx21->clk);
-failed_clock_get:
- iounmap(imx21->regs);
-failed_ioremap:
- release_mem_region(res->start, resource_size(res));
-failed_request_mem:
- remove_debug_files(imx21);
- usb_put_hcd(hcd);
- return ret;
-}
-
-static struct platform_driver imx21_hcd_driver = {
- .driver = {
- .name = hcd_name,
- },
- .probe = imx21_probe,
- .remove = imx21_remove,
- .suspend = NULL,
- .resume = NULL,
-};
-
-module_platform_driver(imx21_hcd_driver);
-
-MODULE_DESCRIPTION("i.MX21 USB Host controller");
-MODULE_AUTHOR("Martin Fuzzey");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx21-hcd");
diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h
deleted file mode 100644
index 96d16752a73e..000000000000
--- a/drivers/usb/host/imx21-hcd.h
+++ /dev/null
@@ -1,431 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Macros and prototypes for i.MX21
- *
- * Copyright (C) 2006 Loping Dog Embedded Systems
- * Copyright (C) 2009 Martin Fuzzey
- * Originally written by Jay Monkman <jtm@lopingdog.com>
- * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
- */
-
-#ifndef __LINUX_IMX21_HCD_H__
-#define __LINUX_IMX21_HCD_H__
-
-#ifdef CONFIG_DYNAMIC_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/platform_data/usb-mx2.h>
-
-#define NUM_ISO_ETDS 2
-#define USB_NUM_ETD 32
-#define DMEM_SIZE 4096
-
-/* Register definitions */
-#define USBOTG_HWMODE 0x00
-#define USBOTG_HWMODE_ANASDBEN (1 << 14)
-#define USBOTG_HWMODE_OTGXCVR_SHIFT 6
-#define USBOTG_HWMODE_OTGXCVR_MASK (3 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TD_RD (0 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TS_RD (2 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TD_RS (1 << 6)
-#define USBOTG_HWMODE_OTGXCVR_TS_RS (3 << 6)
-#define USBOTG_HWMODE_HOSTXCVR_SHIFT 4
-#define USBOTG_HWMODE_HOSTXCVR_MASK (3 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TD_RD (0 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TS_RD (2 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TD_RS (1 << 4)
-#define USBOTG_HWMODE_HOSTXCVR_TS_RS (3 << 4)
-#define USBOTG_HWMODE_CRECFG_MASK (3 << 0)
-#define USBOTG_HWMODE_CRECFG_HOST (1 << 0)
-#define USBOTG_HWMODE_CRECFG_FUNC (2 << 0)
-#define USBOTG_HWMODE_CRECFG_HNP (3 << 0)
-
-#define USBOTG_CINT_STAT 0x04
-#define USBOTG_CINT_STEN 0x08
-#define USBOTG_ASHNPINT (1 << 5)
-#define USBOTG_ASFCINT (1 << 4)
-#define USBOTG_ASHCINT (1 << 3)
-#define USBOTG_SHNPINT (1 << 2)
-#define USBOTG_FCINT (1 << 1)
-#define USBOTG_HCINT (1 << 0)
-
-#define USBOTG_CLK_CTRL 0x0c
-#define USBOTG_CLK_CTRL_FUNC (1 << 2)
-#define USBOTG_CLK_CTRL_HST (1 << 1)
-#define USBOTG_CLK_CTRL_MAIN (1 << 0)
-
-#define USBOTG_RST_CTRL 0x10
-#define USBOTG_RST_RSTI2C (1 << 15)
-#define USBOTG_RST_RSTCTRL (1 << 5)
-#define USBOTG_RST_RSTFC (1 << 4)
-#define USBOTG_RST_RSTFSKE (1 << 3)
-#define USBOTG_RST_RSTRH (1 << 2)
-#define USBOTG_RST_RSTHSIE (1 << 1)
-#define USBOTG_RST_RSTHC (1 << 0)
-
-#define USBOTG_FRM_INTVL 0x14
-#define USBOTG_FRM_REMAIN 0x18
-#define USBOTG_HNP_CSR 0x1c
-#define USBOTG_HNP_ISR 0x2c
-#define USBOTG_HNP_IEN 0x30
-
-#define USBOTG_I2C_TXCVR_REG(x) (0x100 + (x))
-#define USBOTG_I2C_XCVR_DEVAD 0x118
-#define USBOTG_I2C_SEQ_OP_REG 0x119
-#define USBOTG_I2C_SEQ_RD_STARTAD 0x11a
-#define USBOTG_I2C_OP_CTRL_REG 0x11b
-#define USBOTG_I2C_SCLK_TO_SCK_HPER 0x11e
-#define USBOTG_I2C_MASTER_INT_REG 0x11f
-
-#define USBH_HOST_CTRL 0x80
-#define USBH_HOST_CTRL_HCRESET (1 << 31)
-#define USBH_HOST_CTRL_SCHDOVR(x) ((x) << 16)
-#define USBH_HOST_CTRL_RMTWUEN (1 << 4)
-#define USBH_HOST_CTRL_HCUSBSTE_RESET (0 << 2)
-#define USBH_HOST_CTRL_HCUSBSTE_RESUME (1 << 2)
-#define USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL (2 << 2)
-#define USBH_HOST_CTRL_HCUSBSTE_SUSPEND (3 << 2)
-#define USBH_HOST_CTRL_CTLBLKSR_1 (0 << 0)
-#define USBH_HOST_CTRL_CTLBLKSR_2 (1 << 0)
-#define USBH_HOST_CTRL_CTLBLKSR_3 (2 << 0)
-#define USBH_HOST_CTRL_CTLBLKSR_4 (3 << 0)
-
-#define USBH_SYSISR 0x88
-#define USBH_SYSISR_PSCINT (1 << 6)
-#define USBH_SYSISR_FMOFINT (1 << 5)
-#define USBH_SYSISR_HERRINT (1 << 4)
-#define USBH_SYSISR_RESDETINT (1 << 3)
-#define USBH_SYSISR_SOFINT (1 << 2)
-#define USBH_SYSISR_DONEINT (1 << 1)
-#define USBH_SYSISR_SORINT (1 << 0)
-
-#define USBH_SYSIEN 0x8c
-#define USBH_SYSIEN_PSCINT (1 << 6)
-#define USBH_SYSIEN_FMOFINT (1 << 5)
-#define USBH_SYSIEN_HERRINT (1 << 4)
-#define USBH_SYSIEN_RESDETINT (1 << 3)
-#define USBH_SYSIEN_SOFINT (1 << 2)
-#define USBH_SYSIEN_DONEINT (1 << 1)
-#define USBH_SYSIEN_SORINT (1 << 0)
-
-#define USBH_XBUFSTAT 0x98
-#define USBH_YBUFSTAT 0x9c
-#define USBH_XYINTEN 0xa0
-#define USBH_XFILLSTAT 0xa8
-#define USBH_YFILLSTAT 0xac
-#define USBH_ETDENSET 0xc0
-#define USBH_ETDENCLR 0xc4
-#define USBH_IMMEDINT 0xcc
-#define USBH_ETDDONESTAT 0xd0
-#define USBH_ETDDONEEN 0xd4
-#define USBH_FRMNUB 0xe0
-#define USBH_LSTHRESH 0xe4
-
-#define USBH_ROOTHUBA 0xe8
-#define USBH_ROOTHUBA_PWRTOGOOD_MASK (0xff)
-#define USBH_ROOTHUBA_PWRTOGOOD_SHIFT (24)
-#define USBH_ROOTHUBA_NOOVRCURP (1 << 12)
-#define USBH_ROOTHUBA_OVRCURPM (1 << 11)
-#define USBH_ROOTHUBA_DEVTYPE (1 << 10)
-#define USBH_ROOTHUBA_PWRSWTMD (1 << 9)
-#define USBH_ROOTHUBA_NOPWRSWT (1 << 8)
-#define USBH_ROOTHUBA_NDNSTMPRT_MASK (0xff)
-
-#define USBH_ROOTHUBB 0xec
-#define USBH_ROOTHUBB_PRTPWRCM(x) (1 << ((x) + 16))
-#define USBH_ROOTHUBB_DEVREMOVE(x) (1 << (x))
-
-#define USBH_ROOTSTAT 0xf0
-#define USBH_ROOTSTAT_CLRRMTWUE (1 << 31)
-#define USBH_ROOTSTAT_OVRCURCHG (1 << 17)
-#define USBH_ROOTSTAT_DEVCONWUE (1 << 15)
-#define USBH_ROOTSTAT_OVRCURI (1 << 1)
-#define USBH_ROOTSTAT_LOCPWRS (1 << 0)
-
-#define USBH_PORTSTAT(x) (0xf4 + ((x) * 4))
-#define USBH_PORTSTAT_PRTRSTSC (1 << 20)
-#define USBH_PORTSTAT_OVRCURIC (1 << 19)
-#define USBH_PORTSTAT_PRTSTATSC (1 << 18)
-#define USBH_PORTSTAT_PRTENBLSC (1 << 17)
-#define USBH_PORTSTAT_CONNECTSC (1 << 16)
-#define USBH_PORTSTAT_LSDEVCON (1 << 9)
-#define USBH_PORTSTAT_PRTPWRST (1 << 8)
-#define USBH_PORTSTAT_PRTRSTST (1 << 4)
-#define USBH_PORTSTAT_PRTOVRCURI (1 << 3)
-#define USBH_PORTSTAT_PRTSUSPST (1 << 2)
-#define USBH_PORTSTAT_PRTENABST (1 << 1)
-#define USBH_PORTSTAT_CURCONST (1 << 0)
-
-#define USB_DMAREV 0x800
-#define USB_DMAINTSTAT 0x804
-#define USB_DMAINTSTAT_EPERR (1 << 1)
-#define USB_DMAINTSTAT_ETDERR (1 << 0)
-
-#define USB_DMAINTEN 0x808
-#define USB_DMAINTEN_EPERRINTEN (1 << 1)
-#define USB_DMAINTEN_ETDERRINTEN (1 << 0)
-
-#define USB_ETDDMAERSTAT 0x80c
-#define USB_EPDMAERSTAT 0x810
-#define USB_ETDDMAEN 0x820
-#define USB_EPDMAEN 0x824
-#define USB_ETDDMAXTEN 0x828
-#define USB_EPDMAXTEN 0x82c
-#define USB_ETDDMAENXYT 0x830
-#define USB_EPDMAENXYT 0x834
-#define USB_ETDDMABST4EN 0x838
-#define USB_EPDMABST4EN 0x83c
-
-#define USB_MISCCONTROL 0x840
-#define USB_MISCCONTROL_ISOPREVFRM (1 << 3)
-#define USB_MISCCONTROL_SKPRTRY (1 << 2)
-#define USB_MISCCONTROL_ARBMODE (1 << 1)
-#define USB_MISCCONTROL_FILTCC (1 << 0)
-
-#define USB_ETDDMACHANLCLR 0x848
-#define USB_EPDMACHANLCLR 0x84c
-#define USB_ETDSMSA(x) (0x900 + ((x) * 4))
-#define USB_EPSMSA(x) (0x980 + ((x) * 4))
-#define USB_ETDDMABUFPTR(x) (0xa00 + ((x) * 4))
-#define USB_EPDMABUFPTR(x) (0xa80 + ((x) * 4))
-
-#define USB_ETD_DWORD(x, w) (0x200 + ((x) * 16) + ((w) * 4))
-#define DW0_ADDRESS 0
-#define DW0_ENDPNT 7
-#define DW0_DIRECT 11
-#define DW0_SPEED 13
-#define DW0_FORMAT 14
-#define DW0_MAXPKTSIZ 16
-#define DW0_HALTED 27
-#define DW0_TOGCRY 28
-#define DW0_SNDNAK 30
-
-#define DW1_XBUFSRTAD 0
-#define DW1_YBUFSRTAD 16
-
-#define DW2_RTRYDELAY 0
-#define DW2_POLINTERV 0
-#define DW2_STARTFRM 0
-#define DW2_RELPOLPOS 8
-#define DW2_DIRPID 16
-#define DW2_BUFROUND 18
-#define DW2_DELAYINT 19
-#define DW2_DATATOG 22
-#define DW2_ERRORCNT 24
-#define DW2_COMPCODE 28
-
-#define DW3_TOTBYECNT 0
-#define DW3_PKTLEN0 0
-#define DW3_COMPCODE0 12
-#define DW3_PKTLEN1 16
-#define DW3_BUFSIZE 21
-#define DW3_COMPCODE1 28
-
-#define USBCTRL 0x600
-#define USBCTRL_I2C_WU_INT_STAT (1 << 27)
-#define USBCTRL_OTG_WU_INT_STAT (1 << 26)
-#define USBCTRL_HOST_WU_INT_STAT (1 << 25)
-#define USBCTRL_FNT_WU_INT_STAT (1 << 24)
-#define USBCTRL_I2C_WU_INT_EN (1 << 19)
-#define USBCTRL_OTG_WU_INT_EN (1 << 18)
-#define USBCTRL_HOST_WU_INT_EN (1 << 17)
-#define USBCTRL_FNT_WU_INT_EN (1 << 16)
-#define USBCTRL_OTC_RCV_RXDP (1 << 13)
-#define USBCTRL_HOST1_BYP_TLL (1 << 12)
-#define USBCTRL_OTG_BYP_VAL(x) ((x) << 10)
-#define USBCTRL_HOST1_BYP_VAL(x) ((x) << 8)
-#define USBCTRL_OTG_PWR_MASK (1 << 6)
-#define USBCTRL_HOST1_PWR_MASK (1 << 5)
-#define USBCTRL_HOST2_PWR_MASK (1 << 4)
-#define USBCTRL_USB_BYP (1 << 2)
-#define USBCTRL_HOST1_TXEN_OE (1 << 1)
-
-#define USBOTG_DMEM 0x1000
-
-/* Values in TD blocks */
-#define TD_DIR_SETUP 0
-#define TD_DIR_OUT 1
-#define TD_DIR_IN 2
-#define TD_FORMAT_CONTROL 0
-#define TD_FORMAT_ISO 1
-#define TD_FORMAT_BULK 2
-#define TD_FORMAT_INT 3
-#define TD_TOGGLE_CARRY 0
-#define TD_TOGGLE_DATA0 2
-#define TD_TOGGLE_DATA1 3
-
-/* control transfer states */
-#define US_CTRL_SETUP 2
-#define US_CTRL_DATA 1
-#define US_CTRL_ACK 0
-
-/* bulk transfer main state and 0-length packet */
-#define US_BULK 1
-#define US_BULK0 0
-
-/*ETD format description*/
-#define IMX_FMT_CTRL 0x0
-#define IMX_FMT_ISO 0x1
-#define IMX_FMT_BULK 0x2
-#define IMX_FMT_INT 0x3
-
-static char fmt_urb_to_etd[4] = {
-/*PIPE_ISOCHRONOUS*/ IMX_FMT_ISO,
-/*PIPE_INTERRUPT*/ IMX_FMT_INT,
-/*PIPE_CONTROL*/ IMX_FMT_CTRL,
-/*PIPE_BULK*/ IMX_FMT_BULK
-};
-
-/* condition (error) CC codes and mapping (OHCI like) */
-
-#define TD_CC_NOERROR 0x00
-#define TD_CC_CRC 0x01
-#define TD_CC_BITSTUFFING 0x02
-#define TD_CC_DATATOGGLEM 0x03
-#define TD_CC_STALL 0x04
-#define TD_DEVNOTRESP 0x05
-#define TD_PIDCHECKFAIL 0x06
-/*#define TD_UNEXPECTEDPID 0x07 - reserved, not active on MX2*/
-#define TD_DATAOVERRUN 0x08
-#define TD_DATAUNDERRUN 0x09
-#define TD_BUFFEROVERRUN 0x0C
-#define TD_BUFFERUNDERRUN 0x0D
-#define TD_SCHEDULEOVERRUN 0x0E
-#define TD_NOTACCESSED 0x0F
-
-static const int cc_to_error[16] = {
- /* No Error */ 0,
- /* CRC Error */ -EILSEQ,
- /* Bit Stuff */ -EPROTO,
- /* Data Togg */ -EILSEQ,
- /* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
- /* PIDCheck */ -EPROTO,
- /* UnExpPID */ -EPROTO,
- /* DataOver */ -EOVERFLOW,
- /* DataUnder */ -EREMOTEIO,
- /* (for hw) */ -EIO,
- /* (for hw) */ -EIO,
- /* BufferOver */ -ECOMM,
- /* BuffUnder */ -ENOSR,
- /* (for HCD) */ -ENOSPC,
- /* (for HCD) */ -EALREADY
-};
-
-/* HCD data associated with a usb core URB */
-struct urb_priv {
- struct urb *urb;
- struct usb_host_endpoint *ep;
- int active;
- int state;
- struct td *isoc_td;
- int isoc_remaining;
- int isoc_status;
-};
-
-/* HCD data associated with a usb core endpoint */
-struct ep_priv {
- struct usb_host_endpoint *ep;
- struct list_head td_list;
- struct list_head queue;
- int etd[NUM_ISO_ETDS];
- int waiting_etd;
-};
-
-/* isoc packet */
-struct td {
- struct list_head list;
- struct urb *urb;
- struct usb_host_endpoint *ep;
- dma_addr_t dma_handle;
- void *cpu_buffer;
- int len;
- int frame;
- int isoc_index;
-};
-
-/* HCD data associated with a hardware ETD */
-struct etd_priv {
- struct usb_host_endpoint *ep;
- struct urb *urb;
- struct td *td;
- struct list_head queue;
- dma_addr_t dma_handle;
- void *cpu_buffer;
- void *bounce_buffer;
- int alloc;
- int len;
- int dmem_size;
- int dmem_offset;
- int active_count;
-#ifdef DEBUG
- int activated_frame;
- int disactivated_frame;
- int last_int_frame;
- int last_req_frame;
- u32 submitted_dwords[4];
-#endif
-};
-
-/* Hardware data memory info */
-struct imx21_dmem_area {
- struct usb_host_endpoint *ep;
- unsigned int offset;
- unsigned int size;
- struct list_head list;
-};
-
-#ifdef DEBUG
-struct debug_usage_stats {
- unsigned int value;
- unsigned int maximum;
-};
-
-struct debug_stats {
- unsigned long submitted;
- unsigned long completed_ok;
- unsigned long completed_failed;
- unsigned long unlinked;
- unsigned long queue_etd;
- unsigned long queue_dmem;
-};
-
-struct debug_isoc_trace {
- int schedule_frame;
- int submit_frame;
- int request_len;
- int done_frame;
- int done_len;
- int cc;
- struct td *td;
-};
-#endif
-
-/* HCD data structure */
-struct imx21 {
- spinlock_t lock;
- struct device *dev;
- struct usb_hcd *hcd;
- struct mx21_usbh_platform_data *pdata;
- struct list_head dmem_list;
- struct list_head queue_for_etd; /* eps queued due to etd shortage */
- struct list_head queue_for_dmem; /* etds queued due to dmem shortage */
- struct etd_priv etd[USB_NUM_ETD];
- struct clk *clk;
- void __iomem *regs;
-#ifdef DEBUG
- struct dentry *debug_root;
- struct debug_stats nonisoc_stats;
- struct debug_stats isoc_stats;
- struct debug_usage_stats etd_usage;
- struct debug_usage_stats dmem_usage;
- struct debug_isoc_trace isoc_trace[20];
- struct debug_isoc_trace isoc_trace_failed[20];
- unsigned long debug_unblocks;
- int isoc_trace_index;
- int isoc_trace_index_failed;
-#endif
-};
-
-#endif
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 3055d9abfec3..8544a2a2c1e6 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1447,6 +1447,7 @@ static int isp116x_bus_resume(struct usb_hcd *hcd)
val &= ~HCCONTROL_HCFS;
val |= HCCONTROL_USB_RESUME;
isp116x_write_reg32(isp116x, HCCONTROL, val);
+ break;
case HCCONTROL_USB_RESUME:
break;
case HCCONTROL_USB_OPER:
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 9bbfcc3fdd3c..208705b08d37 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -793,60 +793,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r)); \
}
-static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd)
-{
- isp1362_show_reg(isp1362_hcd, HCREVISION);
- isp1362_show_reg(isp1362_hcd, HCCONTROL);
- isp1362_show_reg(isp1362_hcd, HCCMDSTAT);
- isp1362_show_reg(isp1362_hcd, HCINTSTAT);
- isp1362_show_reg(isp1362_hcd, HCINTENB);
- isp1362_show_reg(isp1362_hcd, HCFMINTVL);
- isp1362_show_reg(isp1362_hcd, HCFMREM);
- isp1362_show_reg(isp1362_hcd, HCFMNUM);
- isp1362_show_reg(isp1362_hcd, HCLSTHRESH);
- isp1362_show_reg(isp1362_hcd, HCRHDESCA);
- isp1362_show_reg(isp1362_hcd, HCRHDESCB);
- isp1362_show_reg(isp1362_hcd, HCRHSTATUS);
- isp1362_show_reg(isp1362_hcd, HCRHPORT1);
- isp1362_show_reg(isp1362_hcd, HCRHPORT2);
-
- isp1362_show_reg(isp1362_hcd, HCHWCFG);
- isp1362_show_reg(isp1362_hcd, HCDMACFG);
- isp1362_show_reg(isp1362_hcd, HCXFERCTR);
- isp1362_show_reg(isp1362_hcd, HCuPINT);
-
- if (in_interrupt())
- DBG(0, "%-12s[%02x]: %04x\n", "HCuPINTENB",
- ISP1362_REG_NO(ISP1362_REG_HCuPINTENB), isp1362_hcd->irqenb);
- else
- isp1362_show_reg(isp1362_hcd, HCuPINTENB);
- isp1362_show_reg(isp1362_hcd, HCCHIPID);
- isp1362_show_reg(isp1362_hcd, HCSCRATCH);
- isp1362_show_reg(isp1362_hcd, HCBUFSTAT);
- isp1362_show_reg(isp1362_hcd, HCDIRADDR);
- /* Access would advance fifo
- * isp1362_show_reg(isp1362_hcd, HCDIRDATA);
- */
- isp1362_show_reg(isp1362_hcd, HCISTLBUFSZ);
- isp1362_show_reg(isp1362_hcd, HCISTLRATE);
- isp1362_show_reg(isp1362_hcd, HCINTLBUFSZ);
- isp1362_show_reg(isp1362_hcd, HCINTLBLKSZ);
- isp1362_show_reg(isp1362_hcd, HCINTLDONE);
- isp1362_show_reg(isp1362_hcd, HCINTLSKIP);
- isp1362_show_reg(isp1362_hcd, HCINTLLAST);
- isp1362_show_reg(isp1362_hcd, HCINTLCURR);
- isp1362_show_reg(isp1362_hcd, HCATLBUFSZ);
- isp1362_show_reg(isp1362_hcd, HCATLBLKSZ);
- /* only valid after ATL_DONE interrupt
- * isp1362_show_reg(isp1362_hcd, HCATLDONE);
- */
- isp1362_show_reg(isp1362_hcd, HCATLSKIP);
- isp1362_show_reg(isp1362_hcd, HCATLLAST);
- isp1362_show_reg(isp1362_hcd, HCATLCURR);
- isp1362_show_reg(isp1362_hcd, HCATLDTC);
- isp1362_show_reg(isp1362_hcd, HCATLDTCTO);
-}
-
static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len)
{
len = (len + 1) & ~1;
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 0894f6caccb2..afd9174d83b1 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -1537,6 +1537,7 @@ max3421_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
__func__, urb->interval);
return -EINVAL;
}
+ break;
default:
break;
}
@@ -1847,7 +1848,7 @@ max3421_probe(struct spi_device *spi)
struct max3421_hcd *max3421_hcd;
struct usb_hcd *hcd = NULL;
struct max3421_hcd_platform_data *pdata = NULL;
- int retval = -ENOMEM;
+ int retval;
if (spi_setup(spi) < 0) {
dev_err(&spi->dev, "Unable to setup SPI bus");
@@ -1889,6 +1890,7 @@ max3421_probe(struct spi_device *spi)
goto error;
}
+ retval = -ENOMEM;
hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev,
dev_name(&spi->dev));
if (!hcd) {
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 0487a4b0501e..9bbd7ddd0003 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -155,7 +155,10 @@ static struct regmap *at91_dt_syscon_sfr(void)
/*
* usb_hcd_at91_probe - initialize AT91-based HCDs
- * Context: !in_interrupt()
+ * @driver: Pointer to hc driver instance
+ * @pdev: USB controller to probe
+ *
+ * Context: task context, might sleep
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
@@ -246,12 +249,14 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
/*
* usb_hcd_at91_remove - shutdown processing for AT91-based HCDs
- * Context: !in_interrupt()
+ * @hcd: USB controller to remove
+ * @pdev: Platform device required for cleanup
+ *
+ * Context: task context, might sleep
*
* Reverses the effect of usb_hcd_at91_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, "rmmod" or something similar.
- *
*/
static void usb_hcd_at91_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 73e13e7c2b46..1f5e69314a17 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -171,7 +171,7 @@ static int ohci_urb_enqueue (
/* 1 TD for setup, 1 for ACK, plus ... */
size = 2;
- /* FALLTHROUGH */
+ fallthrough;
// case PIPE_INTERRUPT:
// case PIPE_BULK:
default:
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 44504c1751e0..f474f2f9c1e4 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -692,6 +692,7 @@ int ohci_hub_control(
case C_HUB_OVER_CURRENT:
ohci_writel (ohci, RH_HS_OCIC,
&ohci->regs->roothub.status);
+ break;
case C_HUB_LOCAL_POWER:
break;
default:
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 9ccdf2c216b5..0b3722770760 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -91,14 +91,14 @@ static int omap_ohci_transceiver_power(struct ohci_omap_priv *priv, int on)
| ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (priv->power)
- gpiod_set_value(priv->power, 0);
+ gpiod_set_value_cansleep(priv->power, 0);
} else {
if (machine_is_omap_innovator() && cpu_is_omap1510())
__raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL)
& ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (priv->power)
- gpiod_set_value(priv->power, 1);
+ gpiod_set_value_cansleep(priv->power, 1);
}
return 0;
@@ -285,7 +285,9 @@ static int ohci_omap_reset(struct usb_hcd *hcd)
/**
* ohci_hcd_omap_probe - initialize OMAP-based HCDs
- * Context: !in_interrupt()
+ * @pdev: USB controller to probe
+ *
+ * Context: task context, might sleep
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
@@ -399,8 +401,9 @@ err_put_hcd:
/**
* ohci_hcd_omap_remove - shutdown processing for OMAP-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ * @pdev: USB Host Controller being removed
+ *
+ * Context: task context, might sleep
*
* Reverses the effect of ohci_hcd_omap_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index f77cd6af0ccf..4f5af929c3e4 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -184,7 +184,7 @@ fail_start:
return result;
}
-static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
+static void ps3_ohci_remove(struct ps3_system_bus_device *dev)
{
unsigned int tmp;
struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
@@ -212,8 +212,6 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
ps3_dma_region_free(dev->d_region);
ps3_close_hv_device(dev);
-
- return 0;
}
static int __init ps3_ohci_driver_register(struct ps3_system_bus_driver *drv)
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 7679fb583e41..54aa5c77e549 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -410,12 +410,13 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
/**
* ohci_hcd_pxa27x_probe - initialize pxa27x-based HCDs
- * Context: !in_interrupt()
+ * @pdev: USB Host controller to probe
+ *
+ * Context: task context, might sleep
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
- *
*/
static int ohci_hcd_pxa27x_probe(struct platform_device *pdev)
{
@@ -509,13 +510,13 @@ static int ohci_hcd_pxa27x_probe(struct platform_device *pdev)
/**
* ohci_hcd_pxa27x_remove - shutdown processing for pxa27x-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ * @pdev: USB Host Controller being removed
+ *
+ * Context: task context, might sleep
*
* Reverses the effect of ohci_hcd_pxa27x_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
- *
*/
static int ohci_hcd_pxa27x_remove(struct platform_device *pdev)
{
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index de5e570c58ba..1bec9b585e2d 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -324,14 +324,13 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
/*
* ohci_hcd_s3c2410_remove - shutdown processing for HCD
* @dev: USB Host Controller being removed
- * Context: !in_interrupt()
+ *
+ * Context: task context, might sleep
*
* Reverses the effect of ohci_hcd_3c2410_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
- *
-*/
-
+ */
static int
ohci_hcd_s3c2410_remove(struct platform_device *dev)
{
@@ -345,12 +344,13 @@ ohci_hcd_s3c2410_remove(struct platform_device *dev)
/*
* ohci_hcd_s3c2410_probe - initialize S3C2410-based HCDs
- * Context: !in_interrupt()
+ * @dev: USB Host Controller to be probed
+ *
+ * Context: task context, might sleep
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
- *
*/
static int ohci_hcd_s3c2410_probe(struct platform_device *dev)
{
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 27dbbe1b28b1..4300326b3730 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -1365,6 +1365,7 @@ __acquires(oxu->lock)
switch (urb->status) {
case -EINPROGRESS: /* success */
urb->status = 0;
+ break;
default: /* fault */
break;
case -EREMOTEIO: /* fault or normal */
@@ -4151,8 +4152,10 @@ static struct usb_hcd *oxu_create(struct platform_device *pdev,
oxu->is_otg = otg;
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret < 0)
+ if (ret < 0) {
+ usb_put_hcd(hcd);
return ERR_PTR(ret);
+ }
device_wakeup_enable(hcd->self.controller);
return hcd;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index adaf4063690a..115ced0d93e1 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1614,12 +1614,18 @@ sl811h_probe(struct platform_device *dev)
void __iomem *addr_reg;
void __iomem *data_reg;
int retval;
- u8 tmp, ioaddr = 0;
+ u8 tmp, ioaddr;
unsigned long irqflags;
if (usb_disabled())
return -ENODEV;
+ /* the chip may be wired for either kind of addressing */
+ addr = platform_get_mem_or_io(dev, 0);
+ data = platform_get_mem_or_io(dev, 1);
+ if (!addr || !data || resource_type(addr) != resource_type(data))
+ return -ENODEV;
+
/* basic sanity checks first. board-specific init logic should
* have initialized these three resources and probably board
* specific platform_data. we don't probe for IRQs, and do only
@@ -1632,16 +1638,8 @@ sl811h_probe(struct platform_device *dev)
irq = ires->start;
irqflags = ires->flags & IRQF_TRIGGER_MASK;
- /* the chip may be wired for either kind of addressing */
- addr = platform_get_resource(dev, IORESOURCE_MEM, 0);
- data = platform_get_resource(dev, IORESOURCE_MEM, 1);
- retval = -EBUSY;
- if (!addr || !data) {
- addr = platform_get_resource(dev, IORESOURCE_IO, 0);
- data = platform_get_resource(dev, IORESOURCE_IO, 1);
- if (!addr || !data)
- return -ENODEV;
- ioaddr = 1;
+ ioaddr = resource_type(addr) == IORESOURCE_IO;
+ if (ioaddr) {
/*
* NOTE: 64-bit resource->start is getting truncated
* to avoid compiler warning, assuming that ->start
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 995bc52d2d22..eb96e1e15b71 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -208,13 +208,13 @@ struct u132 {
#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
offsetof(struct ohci_regs, member), 0, data);
#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
- offsetof(struct ohci_regs, member), 0, data);
+ offsetof(struct ohci_regs, member), 0, data)
#define u132_read_pcimem(u132, member, data) \
usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
- ohci_regs, member), 0, data);
+ ohci_regs, member), 0, data)
#define u132_write_pcimem(u132, member, data) \
usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
- ohci_regs, member), 0, data);
+ ohci_regs, member), 0, data)
static inline struct u132 *udev_to_u132(struct u132_udev *udev)
{
u8 udev_number = udev->udev_number;
diff --git a/drivers/usb/host/xhci-histb.c b/drivers/usb/host/xhci-histb.c
index 5546e7e013a8..08369857686e 100644
--- a/drivers/usb/host/xhci-histb.c
+++ b/drivers/usb/host/xhci-histb.c
@@ -240,7 +240,7 @@ static int xhci_histb_probe(struct platform_device *pdev)
/* Initialize dma_mask and coherent_dma_mask to 32-bits */
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
- return ret;
+ goto disable_pm;
hcd = usb_create_hcd(driver, dev, dev_name(dev));
if (!hcd) {
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index c799ca5361d4..74c497fd3476 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1712,6 +1712,10 @@ retry:
hcd->state = HC_STATE_SUSPENDED;
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irqrestore(&xhci->lock, flags);
+
+ if (bus_state->bus_suspended)
+ usleep_range(5000, 10000);
+
return 0;
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index fe405cd38dbc..3589b49b6c8b 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1144,7 +1144,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
case USB_SPEED_WIRELESS:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
return -EINVAL;
- break;
default:
/* Speed was set earlier, this shouldn't happen. */
return -EINVAL;
@@ -2110,7 +2109,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
xhci->event_ring->dequeue);
- if (deq == 0 && !in_interrupt())
+ if (!deq)
xhci_warn(xhci, "WARN something wrong with SW event ring "
"dequeue ptr.\n");
/* Update HC event ring dequeue pointer */
@@ -2252,8 +2251,8 @@ static void xhci_create_rhub_port_array(struct xhci_hcd *xhci,
if (!rhub->num_ports)
return;
- rhub->ports = kcalloc_node(rhub->num_ports, sizeof(rhub->ports), flags,
- dev_to_node(dev));
+ rhub->ports = kcalloc_node(rhub->num_ports, sizeof(*rhub->ports),
+ flags, dev_to_node(dev));
for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
if (xhci->hw_ports[i].rhub != rhub ||
xhci->hw_ports[i].hcd_portnum == DUPLICATE_ENTRY)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index c26c06e5c88c..84da8406d5b4 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -23,6 +23,8 @@
#define SSIC_PORT_CFG2_OFFSET 0x30
#define PROG_DONE (1 << 30)
#define SSIC_PORT_UNUSED (1 << 31)
+#define SPARSE_DISABLE_BIT 17
+#define SPARSE_CNTL_ENABLE 0xC12C
/* Device for a quirk */
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
@@ -45,6 +47,7 @@
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_XHCI 0x15c1
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI 0x15db
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI 0x15d4
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9
@@ -53,6 +56,7 @@
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
#define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
+#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
@@ -161,6 +165,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
(pdev->device == 0x15e0 || pdev->device == 0x15e1))
xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;
+ if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5)
+ xhci->quirks |= XHCI_DISABLE_SPARSE;
+
if (pdev->vendor == PCI_VENDOR_ID_AMD)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
@@ -227,13 +234,15 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI ||
- pdev->device == PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI))
+ pdev->device == PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI))
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
@@ -498,6 +507,15 @@ static void xhci_pme_quirk(struct usb_hcd *hcd)
readl(reg);
}
+static void xhci_sparse_control_quirk(struct usb_hcd *hcd)
+{
+ u32 reg;
+
+ reg = readl(hcd->regs + SPARSE_CNTL_ENABLE);
+ reg &= ~BIT(SPARSE_DISABLE_BIT);
+ writel(reg, hcd->regs + SPARSE_CNTL_ENABLE);
+}
+
static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -517,6 +535,9 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
if (xhci->quirks & XHCI_SSIC_PORT_UNUSED)
xhci_ssic_port_unused_quirk(hcd, true);
+ if (xhci->quirks & XHCI_DISABLE_SPARSE)
+ xhci_sparse_control_quirk(hcd);
+
ret = xhci_suspend(xhci, do_wakeup);
if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED))
xhci_ssic_port_unused_quirk(hcd, false);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index aa2d35f98200..4d34f6005381 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -333,6 +333,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
hcd->skip_phy_initialization = 1;
+ if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
+ xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
+
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto disable_usb_phy;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 167dae117f73..5677b81c0915 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2418,6 +2418,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_warn_ratelimited(xhci,
"WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n",
slot_id, ep_index);
+ break;
case COMP_SHORT_PACKET:
break;
/* Completion codes for endpoint stopped state */
@@ -2962,6 +2963,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
return -EINVAL;
case EP_STATE_HALTED:
xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n");
+ break;
case EP_STATE_STOPPED:
case EP_STATE_RUNNING:
break;
@@ -3325,7 +3327,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
full_len = urb->transfer_buffer_length;
/* If we have scatter/gather list, we use it. */
- if (urb->num_sgs) {
+ if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)) {
num_sgs = urb->num_mapped_sgs;
sg = urb->sg;
addr = (u64) sg_dma_address(sg);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 482fe8c5e3b4..91ab81c3fc79 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1259,6 +1259,108 @@ EXPORT_SYMBOL_GPL(xhci_resume);
/*-------------------------------------------------------------------------*/
+static int xhci_map_temp_buffer(struct usb_hcd *hcd, struct urb *urb)
+{
+ void *temp;
+ int ret = 0;
+ unsigned int buf_len;
+ enum dma_data_direction dir;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ buf_len = urb->transfer_buffer_length;
+
+ temp = kzalloc_node(buf_len, GFP_ATOMIC,
+ dev_to_node(hcd->self.sysdev));
+
+ if (usb_urb_dir_out(urb))
+ sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
+ temp, buf_len, 0);
+
+ urb->transfer_buffer = temp;
+ urb->transfer_dma = dma_map_single(hcd->self.sysdev,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+
+ if (dma_mapping_error(hcd->self.sysdev,
+ urb->transfer_dma)) {
+ ret = -EAGAIN;
+ kfree(temp);
+ } else {
+ urb->transfer_flags |= URB_DMA_MAP_SINGLE;
+ }
+
+ return ret;
+}
+
+static bool xhci_urb_temp_buffer_required(struct usb_hcd *hcd,
+ struct urb *urb)
+{
+ bool ret = false;
+ unsigned int i;
+ unsigned int len = 0;
+ unsigned int trb_size;
+ unsigned int max_pkt;
+ struct scatterlist *sg;
+ struct scatterlist *tail_sg;
+
+ tail_sg = urb->sg;
+ max_pkt = usb_endpoint_maxp(&urb->ep->desc);
+
+ if (!urb->num_sgs)
+ return ret;
+
+ if (urb->dev->speed >= USB_SPEED_SUPER)
+ trb_size = TRB_CACHE_SIZE_SS;
+ else
+ trb_size = TRB_CACHE_SIZE_HS;
+
+ if (urb->transfer_buffer_length != 0 &&
+ !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+ for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+ len = len + sg->length;
+ if (i > trb_size - 2) {
+ len = len - tail_sg->length;
+ if (len < max_pkt) {
+ ret = true;
+ break;
+ }
+
+ tail_sg = sg_next(tail_sg);
+ }
+ }
+ }
+ return ret;
+}
+
+static void xhci_unmap_temp_buf(struct usb_hcd *hcd, struct urb *urb)
+{
+ unsigned int len;
+ unsigned int buf_len;
+ enum dma_data_direction dir;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ buf_len = urb->transfer_buffer_length;
+
+ if (IS_ENABLED(CONFIG_HAS_DMA) &&
+ (urb->transfer_flags & URB_DMA_MAP_SINGLE))
+ dma_unmap_single(hcd->self.sysdev,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ dir);
+
+ if (usb_urb_dir_in(urb))
+ len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs,
+ urb->transfer_buffer,
+ buf_len,
+ 0);
+
+ urb->transfer_flags &= ~URB_DMA_MAP_SINGLE;
+ kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+}
+
/*
* Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT),
* we'll copy the actual data into the TRB address register. This is limited to
@@ -1268,13 +1370,37 @@ EXPORT_SYMBOL_GPL(xhci_resume);
static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(hcd);
+
if (xhci_urb_suitable_for_idt(urb))
return 0;
+ if (xhci->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK) {
+ if (xhci_urb_temp_buffer_required(hcd, urb))
+ return xhci_map_temp_buffer(hcd, urb);
+ }
return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
}
-/*
+static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct xhci_hcd *xhci;
+ bool unmap_temp_buf = false;
+
+ xhci = hcd_to_xhci(hcd);
+
+ if (urb->num_sgs && (urb->transfer_flags & URB_DMA_MAP_SINGLE))
+ unmap_temp_buf = true;
+
+ if ((xhci->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK) && unmap_temp_buf)
+ xhci_unmap_temp_buf(hcd, urb);
+ else
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+}
+
+/**
* xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
* HCDs. Find the index for an endpoint given its descriptor. Use the return
* value to right shift 1 for the bitmask.
@@ -1476,11 +1602,9 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
- if (!HCD_HW_ACCESSIBLE(hcd)) {
- if (!in_interrupt())
- xhci_dbg(xhci, "urb submitted during PCI suspend\n");
+ if (!HCD_HW_ACCESSIBLE(hcd))
return -ESHUTDOWN;
- }
+
if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
return -ENODEV;
@@ -3533,11 +3657,14 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
xhci_dbg(xhci, "Slot %u ep ctx %u now has streams.\n",
udev->slot_id, ep_index);
vdev->eps[ep_index].ep_state |= EP_HAS_STREAMS;
- xhci_debugfs_create_stream_files(xhci, vdev, ep_index);
}
xhci_free_command(xhci, config_cmd);
spin_unlock_irqrestore(&xhci->lock, flags);
+ for (i = 0; i < num_eps; i++) {
+ ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+ xhci_debugfs_create_stream_files(xhci, vdev, ep_index);
+ }
/* Subtract 1 for stream 0, which drivers can't use */
return num_streams - 1;
@@ -5326,6 +5453,7 @@ static const struct hc_driver xhci_hc_driver = {
* managing i/o requests and associated device resources
*/
.map_urb_for_dma = xhci_map_urb_for_dma,
+ .unmap_urb_for_dma = xhci_unmap_urb_for_dma,
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 8be88379c0fb..25e57bc9c3cc 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1330,6 +1330,10 @@ enum xhci_setup_dev {
#define TRB_SIA (1<<31)
#define TRB_FRAME_ID(p) (((p) & 0x7ff) << 20)
+/* TRB cache size for xHC with TRB cache */
+#define TRB_CACHE_SIZE_HS 8
+#define TRB_CACHE_SIZE_SS 16
+
struct xhci_generic_trb {
__le32 field[4];
};
@@ -1877,6 +1881,8 @@ struct xhci_hcd {
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
#define XHCI_RENESAS_FW_QUIRK BIT_ULL(36)
#define XHCI_SKIP_PHY_INIT BIT_ULL(37)
+#define XHCI_DISABLE_SPARSE BIT_ULL(38)
+#define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 6818ea689cd9..8f1144359012 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -275,3 +275,12 @@ config USB_CHAOSKEY
To compile this driver as a module, choose M here: the
module will be called chaoskey.
+
+config BRCM_USB_PINMAP
+ tristate "Broadcom pinmap driver support"
+ depends on (ARCH_BRCMSTB && PHY_BRCM_USB) || COMPILE_TEST
+ default ARCH_BRCMSTB && PHY_BRCM_USB
+ help
+ This option enables support for remapping some USB external
+ signals, which are typically on dedicated pins on the chip,
+ to any gpio.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index da39bddb0604..5f4e598573ab 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -31,3 +31,4 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o
+obj-$(CONFIG_BRCM_USB_PINMAP) += brcmstb-usb-pinmap.o
diff --git a/drivers/usb/misc/apple-mfi-fastcharge.c b/drivers/usb/misc/apple-mfi-fastcharge.c
index b403094a6b3a..ac8695195c13 100644
--- a/drivers/usb/misc/apple-mfi-fastcharge.c
+++ b/drivers/usb/misc/apple-mfi-fastcharge.c
@@ -120,8 +120,10 @@ static int apple_mfi_fc_set_property(struct power_supply *psy,
dev_dbg(&mfi->udev->dev, "prop: %d\n", psp);
ret = pm_runtime_get_sync(&mfi->udev->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_noidle(&mfi->udev->dev);
return ret;
+ }
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_TYPE:
@@ -163,23 +165,27 @@ static const struct power_supply_desc apple_mfi_fc_desc = {
.property_is_writeable = apple_mfi_fc_property_is_writeable
};
+static bool mfi_fc_match(struct usb_device *udev)
+{
+ int idProduct;
+
+ idProduct = le16_to_cpu(udev->descriptor.idProduct);
+ /* See comment above mfi_fc_id_table[] */
+ return (idProduct >= 0x1200 && idProduct <= 0x12ff);
+}
+
static int mfi_fc_probe(struct usb_device *udev)
{
struct power_supply_config battery_cfg = {};
struct mfi_device *mfi = NULL;
- int err, idProduct;
+ int err;
- idProduct = le16_to_cpu(udev->descriptor.idProduct);
- /* See comment above mfi_fc_id_table[] */
- if (idProduct < 0x1200 || idProduct > 0x12ff) {
+ if (!mfi_fc_match(udev))
return -ENODEV;
- }
mfi = kzalloc(sizeof(struct mfi_device), GFP_KERNEL);
- if (!mfi) {
- err = -ENOMEM;
- goto error;
- }
+ if (!mfi)
+ return -ENOMEM;
battery_cfg.drv_data = mfi;
@@ -190,17 +196,14 @@ static int mfi_fc_probe(struct usb_device *udev)
if (IS_ERR(mfi->battery)) {
dev_err(&udev->dev, "Can't register battery\n");
err = PTR_ERR(mfi->battery);
- goto error;
+ kfree(mfi);
+ return err;
}
mfi->udev = usb_get_dev(udev);
dev_set_drvdata(&udev->dev, mfi);
return 0;
-
-error:
- kfree(mfi);
- return err;
}
static void mfi_fc_disconnect(struct usb_device *udev)
@@ -220,6 +223,7 @@ static struct usb_device_driver mfi_fc_driver = {
.probe = mfi_fc_probe,
.disconnect = mfi_fc_disconnect,
.id_table = mfi_fc_id_table,
+ .match = mfi_fc_match,
.generic_subclass = 1,
};
diff --git a/drivers/usb/misc/brcmstb-usb-pinmap.c b/drivers/usb/misc/brcmstb-usb-pinmap.c
new file mode 100644
index 000000000000..b3cfe8666ea7
--- /dev/null
+++ b/drivers/usb/misc/brcmstb-usb-pinmap.c
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2020, Broadcom */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/kdebug.h>
+#include <linux/gpio/consumer.h>
+
+struct out_pin {
+ u32 enable_mask;
+ u32 value_mask;
+ u32 changed_mask;
+ u32 clr_changed_mask;
+ struct gpio_desc *gpiod;
+ const char *name;
+};
+
+struct in_pin {
+ u32 enable_mask;
+ u32 value_mask;
+ struct gpio_desc *gpiod;
+ const char *name;
+ struct brcmstb_usb_pinmap_data *pdata;
+};
+
+struct brcmstb_usb_pinmap_data {
+ void __iomem *regs;
+ int in_count;
+ struct in_pin *in_pins;
+ int out_count;
+ struct out_pin *out_pins;
+};
+
+
+static void pinmap_set(void __iomem *reg, u32 mask)
+{
+ u32 val;
+
+ val = readl(reg);
+ val |= mask;
+ writel(val, reg);
+}
+
+static void pinmap_unset(void __iomem *reg, u32 mask)
+{
+ u32 val;
+
+ val = readl(reg);
+ val &= ~mask;
+ writel(val, reg);
+}
+
+static void sync_in_pin(struct in_pin *pin)
+{
+ u32 val;
+
+ val = gpiod_get_value(pin->gpiod);
+ if (val)
+ pinmap_set(pin->pdata->regs, pin->value_mask);
+ else
+ pinmap_unset(pin->pdata->regs, pin->value_mask);
+}
+
+/*
+ * Interrupt from override register, propagate from override bit
+ * to GPIO.
+ */
+static irqreturn_t brcmstb_usb_pinmap_ovr_isr(int irq, void *dev_id)
+{
+ struct brcmstb_usb_pinmap_data *pdata = dev_id;
+ struct out_pin *pout;
+ u32 val;
+ u32 bit;
+ int x;
+
+ pr_debug("%s: reg: 0x%x\n", __func__, readl(pdata->regs));
+ pout = pdata->out_pins;
+ for (x = 0; x < pdata->out_count; x++) {
+ val = readl(pdata->regs);
+ if (val & pout->changed_mask) {
+ pinmap_set(pdata->regs, pout->clr_changed_mask);
+ pinmap_unset(pdata->regs, pout->clr_changed_mask);
+ bit = val & pout->value_mask;
+ gpiod_set_value(pout->gpiod, bit ? 1 : 0);
+ pr_debug("%s: %s bit changed state to %d\n",
+ __func__, pout->name, bit ? 1 : 0);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/*
+ * Interrupt from GPIO, propagate from GPIO to override bit.
+ */
+static irqreturn_t brcmstb_usb_pinmap_gpio_isr(int irq, void *dev_id)
+{
+ struct in_pin *pin = dev_id;
+
+ pr_debug("%s: %s pin changed state\n", __func__, pin->name);
+ sync_in_pin(pin);
+ return IRQ_HANDLED;
+}
+
+
+static void get_pin_counts(struct device_node *dn, int *in_count,
+ int *out_count)
+{
+ int in;
+ int out;
+
+ *in_count = 0;
+ *out_count = 0;
+ in = of_property_count_strings(dn, "brcm,in-functions");
+ if (in < 0)
+ return;
+ out = of_property_count_strings(dn, "brcm,out-functions");
+ if (out < 0)
+ return;
+ *in_count = in;
+ *out_count = out;
+}
+
+static int parse_pins(struct device *dev, struct device_node *dn,
+ struct brcmstb_usb_pinmap_data *pdata)
+{
+ struct out_pin *pout;
+ struct in_pin *pin;
+ int index;
+ int res;
+ int x;
+
+ pin = pdata->in_pins;
+ for (x = 0, index = 0; x < pdata->in_count; x++) {
+ pin->gpiod = devm_gpiod_get_index(dev, "in", x, GPIOD_IN);
+ if (IS_ERR(pin->gpiod)) {
+ dev_err(dev, "Error getting gpio %s\n", pin->name);
+ return PTR_ERR(pin->gpiod);
+
+ }
+ res = of_property_read_string_index(dn, "brcm,in-functions", x,
+ &pin->name);
+ if (res < 0) {
+ dev_err(dev, "Error getting brcm,in-functions for %s\n",
+ pin->name);
+ return res;
+ }
+ res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
+ &pin->enable_mask);
+ if (res < 0) {
+ dev_err(dev, "Error getting 1st brcm,in-masks for %s\n",
+ pin->name);
+ return res;
+ }
+ res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
+ &pin->value_mask);
+ if (res < 0) {
+ dev_err(dev, "Error getting 2nd brcm,in-masks for %s\n",
+ pin->name);
+ return res;
+ }
+ pin->pdata = pdata;
+ pin++;
+ }
+ pout = pdata->out_pins;
+ for (x = 0, index = 0; x < pdata->out_count; x++) {
+ pout->gpiod = devm_gpiod_get_index(dev, "out", x,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(pout->gpiod)) {
+ dev_err(dev, "Error getting gpio %s\n", pin->name);
+ return PTR_ERR(pout->gpiod);
+ }
+ res = of_property_read_string_index(dn, "brcm,out-functions", x,
+ &pout->name);
+ if (res < 0) {
+ dev_err(dev, "Error getting brcm,out-functions for %s\n",
+ pout->name);
+ return res;
+ }
+ res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+ &pout->enable_mask);
+ if (res < 0) {
+ dev_err(dev, "Error getting 1st brcm,out-masks for %s\n",
+ pout->name);
+ return res;
+ }
+ res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+ &pout->value_mask);
+ if (res < 0) {
+ dev_err(dev, "Error getting 2nd brcm,out-masks for %s\n",
+ pout->name);
+ return res;
+ }
+ res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+ &pout->changed_mask);
+ if (res < 0) {
+ dev_err(dev, "Error getting 3rd brcm,out-masks for %s\n",
+ pout->name);
+ return res;
+ }
+ res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
+ &pout->clr_changed_mask);
+ if (res < 0) {
+ dev_err(dev, "Error getting 4th out-masks for %s\n",
+ pout->name);
+ return res;
+ }
+ pout++;
+ }
+ return 0;
+}
+
+static void sync_all_pins(struct brcmstb_usb_pinmap_data *pdata)
+{
+ struct out_pin *pout;
+ struct in_pin *pin;
+ int val;
+ int x;
+
+ /*
+ * Enable the override, clear any changed condition and
+ * propagate the state to the GPIO for all out pins.
+ */
+ pout = pdata->out_pins;
+ for (x = 0; x < pdata->out_count; x++) {
+ pinmap_set(pdata->regs, pout->enable_mask);
+ pinmap_set(pdata->regs, pout->clr_changed_mask);
+ pinmap_unset(pdata->regs, pout->clr_changed_mask);
+ val = readl(pdata->regs) & pout->value_mask;
+ gpiod_set_value(pout->gpiod, val ? 1 : 0);
+ pout++;
+ }
+
+ /* sync and enable all in pins. */
+ pin = pdata->in_pins;
+ for (x = 0; x < pdata->in_count; x++) {
+ sync_in_pin(pin);
+ pinmap_set(pdata->regs, pin->enable_mask);
+ pin++;
+ }
+}
+
+static int __init brcmstb_usb_pinmap_probe(struct platform_device *pdev)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ struct brcmstb_usb_pinmap_data *pdata;
+ struct in_pin *pin;
+ struct resource *r;
+ int out_count;
+ int in_count;
+ int err;
+ int irq;
+ int x;
+
+ get_pin_counts(dn, &in_count, &out_count);
+ if ((in_count + out_count) == 0)
+ return -EINVAL;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(*pdata) +
+ (sizeof(struct in_pin) * in_count) +
+ (sizeof(struct out_pin) * out_count), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->in_count = in_count;
+ pdata->out_count = out_count;
+ pdata->in_pins = (struct in_pin *)(pdata + 1);
+ pdata->out_pins = (struct out_pin *)(pdata->in_pins + in_count);
+
+ pdata->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!pdata->regs)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, pdata);
+
+ err = parse_pins(&pdev->dev, dn, pdata);
+ if (err)
+ return err;
+
+ sync_all_pins(pdata);
+
+ if (out_count) {
+
+ /* Enable interrupt for out pins */
+ irq = platform_get_irq(pdev, 0);
+ err = devm_request_irq(&pdev->dev, irq,
+ brcmstb_usb_pinmap_ovr_isr,
+ IRQF_TRIGGER_RISING,
+ pdev->name, pdata);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Error requesting IRQ\n");
+ return err;
+ }
+ }
+
+ for (x = 0, pin = pdata->in_pins; x < pdata->in_count; x++, pin++) {
+ irq = gpiod_to_irq(pin->gpiod);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Error getting IRQ for %s pin\n",
+ pin->name);
+ return irq;
+ }
+ err = devm_request_irq(&pdev->dev, irq,
+ brcmstb_usb_pinmap_gpio_isr,
+ IRQF_SHARED | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ pdev->name, pin);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Error requesting IRQ for %s pin\n",
+ pin->name);
+ return err;
+ }
+ }
+
+ dev_dbg(&pdev->dev, "Driver probe succeeded\n");
+ dev_dbg(&pdev->dev, "In pin count: %d, out pin count: %d\n",
+ pdata->in_count, pdata->out_count);
+ return 0;
+}
+
+
+static const struct of_device_id brcmstb_usb_pinmap_of_match[] = {
+ { .compatible = "brcm,usb-pinmap" },
+ { },
+};
+
+static struct platform_driver brcmstb_usb_pinmap_driver = {
+ .driver = {
+ .name = "brcm-usb-pinmap",
+ .of_match_table = brcmstb_usb_pinmap_of_match,
+ },
+};
+
+static int __init brcmstb_usb_pinmap_init(void)
+{
+ return platform_driver_probe(&brcmstb_usb_pinmap_driver,
+ brcmstb_usb_pinmap_probe);
+}
+
+module_init(brcmstb_usb_pinmap_init);
+MODULE_AUTHOR("Al Cooper <alcooperx@gmail.com>");
+MODULE_DESCRIPTION("Broadcom USB Pinmap Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 70ec29681526..efbd317f2f25 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -384,7 +384,6 @@ static ssize_t iowarrior_write(struct file *file,
retval = usb_set_report(dev->interface, 2, 0, buf, count);
kfree(buf);
goto exit;
- break;
case USB_DEVICE_ID_CODEMERCS_IOW56:
case USB_DEVICE_ID_CODEMERCS_IOW56AM:
case USB_DEVICE_ID_CODEMERCS_IOW28:
@@ -454,14 +453,12 @@ static ssize_t iowarrior_write(struct file *file,
retval = count;
usb_free_urb(int_out_urb);
goto exit;
- break;
default:
/* what do we have here ? An unsupported Product-ID ? */
dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n",
__func__, dev->product_id);
retval = -EFAULT;
goto exit;
- break;
}
error:
usb_free_coherent(dev->udev, dev->report_size, buf,
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index ba655b4af4fc..1c9e09138c10 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -797,7 +797,7 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_
&get_version_reply,
sizeof(get_version_reply),
1000, GFP_KERNEL);
- if (!result) {
+ if (result) {
dev_err(idev, "get version request failed: %d\n", result);
retval = result;
goto error;
diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig
index 655d9cb0651a..c12cdd015410 100644
--- a/drivers/usb/misc/sisusbvga/Kconfig
+++ b/drivers/usb/misc/sisusbvga/Kconfig
@@ -16,7 +16,7 @@ config USB_SISUSBVGA
config USB_SISUSBVGA_CON
bool "Text console and mode switching support" if USB_SISUSBVGA
- depends on VT
+ depends on VT && BROKEN
select FONT_8x16
help
Say Y here if you want a VGA text console via the USB dongle or
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index c63e545fb105..dfa0d5ce6012 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -1345,24 +1345,6 @@ static int sisusbdummycon_blank(struct vc_data *vc, int blank, int mode_switch)
return 0;
}
-static int sisusbdummycon_font_set(struct vc_data *vc,
- struct console_font *font,
- unsigned int flags)
-{
- return 0;
-}
-
-static int sisusbdummycon_font_default(struct vc_data *vc,
- struct console_font *font, char *name)
-{
- return 0;
-}
-
-static int sisusbdummycon_font_copy(struct vc_data *vc, int con)
-{
- return 0;
-}
-
static const struct consw sisusb_dummy_con = {
.owner = THIS_MODULE,
.con_startup = sisusbdummycon_startup,
@@ -1375,9 +1357,6 @@ static const struct consw sisusb_dummy_con = {
.con_scroll = sisusbdummycon_scroll,
.con_switch = sisusbdummycon_switch,
.con_blank = sisusbdummycon_blank,
- .con_font_set = sisusbdummycon_font_set,
- .con_font_default = sisusbdummycon_font_default,
- .con_font_copy = sisusbdummycon_font_copy,
};
int
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index e3165d79b5f6..73ebfa6e9715 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -137,6 +137,7 @@ static void yurex_interrupt(struct urb *urb)
dev_err(&dev->interface->dev,
"%s - overflow with length %d, actual length is %d\n",
__func__, YUREX_BUF_SIZE, dev->urb->actual_length);
+ return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
diff --git a/drivers/usb/mtu3/mtu3_debug.h b/drivers/usb/mtu3/mtu3_debug.h
index 3084c46017c3..9a36134b322d 100644
--- a/drivers/usb/mtu3/mtu3_debug.h
+++ b/drivers/usb/mtu3/mtu3_debug.h
@@ -19,7 +19,6 @@ struct ssusb_mtk;
struct mtu3_regset {
char name[MTU3_DEBUGFS_NAME_LEN];
struct debugfs_regset32 regset;
- size_t nregs;
};
struct mtu3_file_map {
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
index fdeade6254ae..7537bfd651af 100644
--- a/drivers/usb/mtu3/mtu3_debugfs.c
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -127,7 +127,7 @@ static void mtu3_debugfs_regset(struct mtu3 *mtu, void __iomem *base,
struct debugfs_regset32 *regset;
struct mtu3_regset *mregs;
- mregs = devm_kzalloc(mtu->dev, sizeof(*regset), GFP_KERNEL);
+ mregs = devm_kzalloc(mtu->dev, sizeof(*mregs), GFP_KERNEL);
if (!mregs)
return;
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 1de5c9a1d20a..38f17d66d5bc 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -564,6 +564,7 @@ static int mtu3_gadget_stop(struct usb_gadget *g)
spin_unlock_irqrestore(&mtu->lock, flags);
+ synchronize_irq(mtu->irq);
return 0;
}
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 30085b2be7b9..5892f3ce0cdc 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -429,10 +429,12 @@ static int dsps_musb_init(struct musb *musb)
struct platform_device *parent = to_platform_device(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
void __iomem *reg_base;
+ struct resource *r;
u32 rev, val;
int ret;
- reg_base = devm_platform_ioremap_resource_byname(parent, "control");
+ r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
+ reg_base = devm_ioremap_resource(dev, r);
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
musb->ctrl_base = reg_base;
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index c26683a2702b..c42937692207 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -467,6 +467,7 @@ static void musb_do_idle(struct timer_list *t)
fallthrough;
case OTG_STATE_A_IDLE:
tusb_musb_set_vbus(musb, 0);
+ break;
default:
break;
}
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index ef4787cd3d37..52eebcb88c1f 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -144,7 +144,7 @@ config USB_MV_OTG
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
select USB_PHY
help
- Say Y here if you want to build Marvell USB OTG transciever
+ Say Y here if you want to build Marvell USB OTG transceiver
driver in kernel (including PXA and MMP series). This driver
implements role switch between EHCI host driver and gadget driver.
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index 4a6462c92ef2..02bb7ddd4bd6 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -1208,9 +1208,6 @@ static int isp1301_remove(struct i2c_client *i2c)
#ifdef CONFIG_USB_OTG
otg_unbind(isp);
#endif
- if (machine_is_omap_h2())
- gpio_free(2);
-
set_bit(WORK_STOP, &isp->todo);
del_timer_sync(&isp->timer);
flush_work(&isp->work);
@@ -1480,6 +1477,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
int status;
struct isp1301 *isp;
+ int irq;
if (the_transceiver)
return 0;
@@ -1543,20 +1541,27 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
#endif
if (machine_is_omap_h2()) {
+ struct gpio_desc *gpiod;
+
/* full speed signaling by default */
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
MC1_SPEED);
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
MC2_SPD_SUSP_CTRL);
- /* IRQ wired at M14 */
- omap_cfg_reg(M14_1510_GPIO2);
- if (gpio_request(2, "isp1301") == 0)
- gpio_direction_input(2);
+ gpiod = devm_gpiod_get(&i2c->dev, NULL, GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ dev_err(&i2c->dev, "cannot obtain H2 GPIO\n");
+ goto fail;
+ }
+ gpiod_set_consumer_name(gpiod, "isp1301");
+ irq = gpiod_to_irq(gpiod);
isp->irq_type = IRQF_TRIGGER_FALLING;
+ } else {
+ irq = i2c->irq;
}
- status = request_irq(i2c->irq, isp1301_irq,
+ status = request_irq(irq, isp1301_irq,
isp->irq_type, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
@@ -1566,13 +1571,13 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
isp->phy.dev = &i2c->dev;
isp->phy.label = DRIVER_NAME;
- isp->phy.set_power = isp1301_set_power,
+ isp->phy.set_power = isp1301_set_power;
isp->phy.otg->usb_phy = &isp->phy;
- isp->phy.otg->set_host = isp1301_set_host,
- isp->phy.otg->set_peripheral = isp1301_set_peripheral,
- isp->phy.otg->start_srp = isp1301_start_srp,
- isp->phy.otg->start_hnp = isp1301_start_hnp,
+ isp->phy.otg->set_host = isp1301_set_host;
+ isp->phy.otg->set_peripheral = isp1301_set_peripheral;
+ isp->phy.otg->start_srp = isp1301_start_srp;
+ isp->phy.otg->start_hnp = isp1301_start_hnp;
enable_vbus_draw(isp, 0);
power_down(isp);
diff --git a/drivers/usb/phy/phy-jz4770.c b/drivers/usb/phy/phy-jz4770.c
index f6d3731581eb..4025da20b3fd 100644
--- a/drivers/usb/phy/phy-jz4770.c
+++ b/drivers/usb/phy/phy-jz4770.c
@@ -350,7 +350,7 @@ static struct platform_driver ingenic_phy_driver = {
.probe = jz4770_phy_probe,
.driver = {
.name = "jz4770-phy",
- .of_match_table = of_match_ptr(ingenic_usb_phy_of_matches),
+ .of_match_table = ingenic_usb_phy_of_matches,
},
};
module_platform_driver(ingenic_phy_driver);
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 4007fa25a8ff..a21ff5ab6df9 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -298,12 +298,12 @@ config USB_SERIAL_IUU
module will be called iuu_phoenix.o
config USB_SERIAL_KEYSPAN_PDA
- tristate "USB Keyspan PDA Single Port Serial Driver"
+ tristate "USB Keyspan PDA / Xircom Single Port Serial Driver"
select USB_EZUSB_FX2
help
- Say Y here if you want to use a Keyspan PDA single port USB to
- serial converter device. This driver makes use of firmware
- developed from scratch by Brian Warner.
+ Say Y here if you want to use a Keyspan PDA, Xircom or Entrega single
+ port USB to serial converter device. This driver makes use of
+ firmware developed from scratch by Brian Warner.
To compile this driver as a module, choose M here: the
module will be called keyspan_pda.
@@ -538,17 +538,6 @@ config USB_SERIAL_CYBERJACK
If unsure, say N.
-config USB_SERIAL_XIRCOM
- tristate "USB Xircom / Entrega Single Port Serial Driver"
- select USB_EZUSB_FX2
- help
- Say Y here if you want to use a Xircom or Entrega single port USB to
- serial converter device. This driver makes use of firmware
- developed from scratch by Brian Warner.
-
- To compile this driver as a module, choose M here: the
- module will be called keyspan_pda.
-
config USB_SERIAL_WWAN
tristate
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 2d491e434f11..50c53aed787a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -61,5 +61,4 @@ obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
-obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index a2e2f56c88cd..28deaaec581f 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -81,10 +81,11 @@
#define CH341_QUIRK_SIMULATE_BREAK BIT(1)
static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x4348, 0x5523) },
+ { USB_DEVICE(0x1a86, 0x5512) },
+ { USB_DEVICE(0x1a86, 0x5523) },
{ USB_DEVICE(0x1a86, 0x7522) },
{ USB_DEVICE(0x1a86, 0x7523) },
- { USB_DEVICE(0x1a86, 0x5523) },
+ { USB_DEVICE(0x4348, 0x5523) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index d0c05aa8a0d6..fbb10dfc56e3 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -31,9 +31,6 @@
*/
static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
static void cp210x_close(struct usb_serial_port *);
-static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
-static void cp210x_get_termios_port(struct usb_serial_port *port,
- tcflag_t *cflagp, unsigned int *baudp);
static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
struct ktermios *);
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
@@ -49,7 +46,7 @@ static void cp210x_disconnect(struct usb_serial *);
static void cp210x_release(struct usb_serial *);
static int cp210x_port_probe(struct usb_serial_port *);
static int cp210x_port_remove(struct usb_serial_port *);
-static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
+static void cp210x_dtr_rts(struct usb_serial_port *port, int on);
static void cp210x_process_read_urb(struct urb *urb);
static void cp210x_enable_event_mode(struct usb_serial_port *port);
static void cp210x_disable_event_mode(struct usb_serial_port *port);
@@ -267,7 +264,6 @@ enum cp210x_event_state {
struct cp210x_port_private {
u8 bInterfaceNumber;
- bool has_swapped_line_ctl;
bool event_mode;
enum cp210x_event_state event_state;
u8 lsr;
@@ -559,14 +555,8 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
int result;
dmabuf = kmalloc(bufsize, GFP_KERNEL);
- if (!dmabuf) {
- /*
- * FIXME Some callers don't bother to check for error,
- * at least give them consistent junk until they are fixed
- */
- memset(buf, 0, bufsize);
+ if (!dmabuf)
return -ENOMEM;
- }
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
req, REQTYPE_INTERFACE_TO_HOST, 0,
@@ -580,12 +570,6 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
req, bufsize, result);
if (result >= 0)
result = -EIO;
-
- /*
- * FIXME Some callers don't bother to check for error,
- * at least give them consistent junk until they are fixed
- */
- memset(buf, 0, bufsize);
}
kfree(dmabuf);
@@ -594,46 +578,6 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
}
/*
- * Reads any 32-bit CP210X_ register identified by req.
- */
-static int cp210x_read_u32_reg(struct usb_serial_port *port, u8 req, u32 *val)
-{
- __le32 le32_val;
- int err;
-
- err = cp210x_read_reg_block(port, req, &le32_val, sizeof(le32_val));
- if (err) {
- /*
- * FIXME Some callers don't bother to check for error,
- * at least give them consistent junk until they are fixed
- */
- *val = 0;
- return err;
- }
-
- *val = le32_to_cpu(le32_val);
-
- return 0;
-}
-
-/*
- * Reads any 16-bit CP210X_ register identified by req.
- */
-static int cp210x_read_u16_reg(struct usb_serial_port *port, u8 req, u16 *val)
-{
- __le16 le16_val;
- int err;
-
- err = cp210x_read_reg_block(port, req, &le16_val, sizeof(le16_val));
- if (err)
- return err;
-
- *val = le16_to_cpu(le16_val);
-
- return 0;
-}
-
-/*
* Reads any 8-bit CP210X_ register identified by req.
*/
static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val)
@@ -780,59 +724,6 @@ static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type,
}
#endif
-/*
- * Detect CP2108 GET_LINE_CTL bug and activate workaround.
- * Write a known good value 0x800, read it back.
- * If it comes back swapped the bug is detected.
- * Preserve the original register value.
- */
-static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port)
-{
- struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
- u16 line_ctl_save;
- u16 line_ctl_test;
- int err;
-
- err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_save);
- if (err)
- return err;
-
- err = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, 0x800);
- if (err)
- return err;
-
- err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_test);
- if (err)
- return err;
-
- if (line_ctl_test == 8) {
- port_priv->has_swapped_line_ctl = true;
- line_ctl_save = swab16(line_ctl_save);
- }
-
- return cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, line_ctl_save);
-}
-
-/*
- * Must always be called instead of cp210x_read_u16_reg(CP210X_GET_LINE_CTL)
- * to workaround cp2108 bug and get correct value.
- */
-static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl)
-{
- struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
- int err;
-
- err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, ctl);
- if (err)
- return err;
-
- /* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */
- if (port_priv->has_swapped_line_ctl)
- *ctl = swab16(*ctl);
-
- return 0;
-}
-
static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
@@ -844,16 +735,8 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
return result;
}
- /* Configure the termios structure */
- cp210x_get_termios(tty, port);
-
- if (tty) {
- /* The baud rate must be initialised on cp2104 */
- cp210x_change_speed(tty, port, NULL);
-
- if (I_INPCK(tty))
- cp210x_enable_event_mode(port);
- }
+ if (tty)
+ cp210x_set_termios(tty, port, NULL);
result = usb_serial_generic_open(tty, port);
if (result)
@@ -1032,167 +915,6 @@ static bool cp210x_tx_empty(struct usb_serial_port *port)
return !count;
}
-/*
- * cp210x_get_termios
- * Reads the baud rate, data bits, parity, stop bits and flow control mode
- * from the device, corrects any unsupported values, and configures the
- * termios structure to reflect the state of the device
- */
-static void cp210x_get_termios(struct tty_struct *tty,
- struct usb_serial_port *port)
-{
- unsigned int baud;
-
- if (tty) {
- cp210x_get_termios_port(tty->driver_data,
- &tty->termios.c_cflag, &baud);
- tty_encode_baud_rate(tty, baud, baud);
- } else {
- tcflag_t cflag;
- cflag = 0;
- cp210x_get_termios_port(port, &cflag, &baud);
- }
-}
-
-/*
- * cp210x_get_termios_port
- * This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
- */
-static void cp210x_get_termios_port(struct usb_serial_port *port,
- tcflag_t *cflagp, unsigned int *baudp)
-{
- struct device *dev = &port->dev;
- tcflag_t cflag;
- struct cp210x_flow_ctl flow_ctl;
- u32 baud;
- u16 bits;
- u32 ctl_hs;
- u32 flow_repl;
-
- cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud);
-
- dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud);
- *baudp = baud;
-
- cflag = *cflagp;
-
- cp210x_get_line_ctl(port, &bits);
- cflag &= ~CSIZE;
- switch (bits & BITS_DATA_MASK) {
- case BITS_DATA_5:
- dev_dbg(dev, "%s - data bits = 5\n", __func__);
- cflag |= CS5;
- break;
- case BITS_DATA_6:
- dev_dbg(dev, "%s - data bits = 6\n", __func__);
- cflag |= CS6;
- break;
- case BITS_DATA_7:
- dev_dbg(dev, "%s - data bits = 7\n", __func__);
- cflag |= CS7;
- break;
- case BITS_DATA_8:
- dev_dbg(dev, "%s - data bits = 8\n", __func__);
- cflag |= CS8;
- break;
- case BITS_DATA_9:
- dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__);
- cflag |= CS8;
- bits &= ~BITS_DATA_MASK;
- bits |= BITS_DATA_8;
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
- break;
- default:
- dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__);
- cflag |= CS8;
- bits &= ~BITS_DATA_MASK;
- bits |= BITS_DATA_8;
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
- break;
- }
-
- switch (bits & BITS_PARITY_MASK) {
- case BITS_PARITY_NONE:
- dev_dbg(dev, "%s - parity = NONE\n", __func__);
- cflag &= ~PARENB;
- break;
- case BITS_PARITY_ODD:
- dev_dbg(dev, "%s - parity = ODD\n", __func__);
- cflag |= (PARENB|PARODD);
- break;
- case BITS_PARITY_EVEN:
- dev_dbg(dev, "%s - parity = EVEN\n", __func__);
- cflag &= ~PARODD;
- cflag |= PARENB;
- break;
- case BITS_PARITY_MARK:
- dev_dbg(dev, "%s - parity = MARK\n", __func__);
- cflag |= (PARENB|PARODD|CMSPAR);
- break;
- case BITS_PARITY_SPACE:
- dev_dbg(dev, "%s - parity = SPACE\n", __func__);
- cflag &= ~PARODD;
- cflag |= (PARENB|CMSPAR);
- break;
- default:
- dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__);
- cflag &= ~PARENB;
- bits &= ~BITS_PARITY_MASK;
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
- break;
- }
-
- cflag &= ~CSTOPB;
- switch (bits & BITS_STOP_MASK) {
- case BITS_STOP_1:
- dev_dbg(dev, "%s - stop bits = 1\n", __func__);
- break;
- case BITS_STOP_1_5:
- dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);
- bits &= ~BITS_STOP_MASK;
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
- break;
- case BITS_STOP_2:
- dev_dbg(dev, "%s - stop bits = 2\n", __func__);
- cflag |= CSTOPB;
- break;
- default:
- dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__);
- bits &= ~BITS_STOP_MASK;
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
- break;
- }
-
- cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
- sizeof(flow_ctl));
- ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
- if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) {
- dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
- /*
- * When the port is closed, the CP210x hardware disables
- * auto-RTS and RTS is deasserted but it leaves auto-CTS when
- * in hardware flow control mode. When re-opening the port, if
- * auto-CTS is enabled on the cp210x, then auto-RTS must be
- * re-enabled in the driver.
- */
- flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
- flow_repl &= ~CP210X_SERIAL_RTS_MASK;
- flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
- flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
- cp210x_write_reg_block(port,
- CP210X_SET_FLOW,
- &flow_ctl,
- sizeof(flow_ctl));
-
- cflag |= CRTSCTS;
- } else {
- dev_dbg(dev, "%s - flow control = NONE\n", __func__);
- cflag &= ~CRTSCTS;
- }
-
- *cflagp = cflag;
-}
-
struct cp210x_rate {
speed_t rate;
speed_t high;
@@ -1352,127 +1074,121 @@ static void cp210x_disable_event_mode(struct usb_serial_port *port)
port_priv->event_mode = false;
}
+static bool cp210x_termios_change(const struct ktermios *a, const struct ktermios *b)
+{
+ bool iflag_change;
+
+ iflag_change = ((a->c_iflag ^ b->c_iflag) & INPCK);
+
+ return tty_termios_hw_change(a, b) || iflag_change;
+}
+
+static void cp210x_set_flow_control(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
+{
+ struct cp210x_flow_ctl flow_ctl;
+ u32 flow_repl;
+ u32 ctl_hs;
+ int ret;
+
+ if (old_termios && C_CRTSCTS(tty) == (old_termios->c_cflag & CRTSCTS))
+ return;
+
+ ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
+ sizeof(flow_ctl));
+ if (ret)
+ return;
+
+ ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
+ flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
+
+ ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
+ ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
+ ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
+ ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
+ ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
+
+ if (C_CRTSCTS(tty)) {
+ ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
+ flow_repl &= ~CP210X_SERIAL_RTS_MASK;
+ flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
+ } else {
+ ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
+ flow_repl &= ~CP210X_SERIAL_RTS_MASK;
+ flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
+ }
+
+ dev_dbg(&port->dev, "%s - ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
+ __func__, ctl_hs, flow_repl);
+
+ flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
+ flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
+
+ cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
+ sizeof(flow_ctl));
+}
+
static void cp210x_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
- struct device *dev = &port->dev;
- unsigned int cflag, old_cflag;
+ struct cp210x_serial_private *priv = usb_get_serial_data(port->serial);
u16 bits;
+ int ret;
- cflag = tty->termios.c_cflag;
- old_cflag = old_termios->c_cflag;
+ if (old_termios && !cp210x_termios_change(&tty->termios, old_termios))
+ return;
- if (tty->termios.c_ospeed != old_termios->c_ospeed)
+ if (!old_termios || tty->termios.c_ospeed != old_termios->c_ospeed)
cp210x_change_speed(tty, port, old_termios);
- /* If the number of data bits is to be updated */
- if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
- cp210x_get_line_ctl(port, &bits);
- bits &= ~BITS_DATA_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- bits |= BITS_DATA_5;
- dev_dbg(dev, "%s - data bits = 5\n", __func__);
- break;
- case CS6:
- bits |= BITS_DATA_6;
- dev_dbg(dev, "%s - data bits = 6\n", __func__);
- break;
- case CS7:
- bits |= BITS_DATA_7;
- dev_dbg(dev, "%s - data bits = 7\n", __func__);
- break;
- case CS8:
- default:
- bits |= BITS_DATA_8;
- dev_dbg(dev, "%s - data bits = 8\n", __func__);
- break;
- }
- if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
- dev_dbg(dev, "Number of data bits requested not supported by device\n");
+ /* CP2101 only supports CS8, 1 stop bit and non-stick parity. */
+ if (priv->partnum == CP210X_PARTNUM_CP2101) {
+ tty->termios.c_cflag &= ~(CSIZE | CSTOPB | CMSPAR);
+ tty->termios.c_cflag |= CS8;
}
- if ((cflag & (PARENB|PARODD|CMSPAR)) !=
- (old_cflag & (PARENB|PARODD|CMSPAR))) {
- cp210x_get_line_ctl(port, &bits);
- bits &= ~BITS_PARITY_MASK;
- if (cflag & PARENB) {
- if (cflag & CMSPAR) {
- if (cflag & PARODD) {
- bits |= BITS_PARITY_MARK;
- dev_dbg(dev, "%s - parity = MARK\n", __func__);
- } else {
- bits |= BITS_PARITY_SPACE;
- dev_dbg(dev, "%s - parity = SPACE\n", __func__);
- }
- } else {
- if (cflag & PARODD) {
- bits |= BITS_PARITY_ODD;
- dev_dbg(dev, "%s - parity = ODD\n", __func__);
- } else {
- bits |= BITS_PARITY_EVEN;
- dev_dbg(dev, "%s - parity = EVEN\n", __func__);
- }
- }
- }
- if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
- dev_dbg(dev, "Parity mode not supported by device\n");
+ bits = 0;
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
+ bits |= BITS_DATA_5;
+ break;
+ case CS6:
+ bits |= BITS_DATA_6;
+ break;
+ case CS7:
+ bits |= BITS_DATA_7;
+ break;
+ case CS8:
+ default:
+ bits |= BITS_DATA_8;
+ break;
}
- if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
- cp210x_get_line_ctl(port, &bits);
- bits &= ~BITS_STOP_MASK;
- if (cflag & CSTOPB) {
- bits |= BITS_STOP_2;
- dev_dbg(dev, "%s - stop bits = 2\n", __func__);
+ if (C_PARENB(tty)) {
+ if (C_CMSPAR(tty)) {
+ if (C_PARODD(tty))
+ bits |= BITS_PARITY_MARK;
+ else
+ bits |= BITS_PARITY_SPACE;
} else {
- bits |= BITS_STOP_1;
- dev_dbg(dev, "%s - stop bits = 1\n", __func__);
+ if (C_PARODD(tty))
+ bits |= BITS_PARITY_ODD;
+ else
+ bits |= BITS_PARITY_EVEN;
}
- if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
- dev_dbg(dev, "Number of stop bits requested not supported by device\n");
}
- if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
- struct cp210x_flow_ctl flow_ctl;
- u32 ctl_hs;
- u32 flow_repl;
-
- cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
- sizeof(flow_ctl));
- ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
- flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
- dev_dbg(dev, "%s - read ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
- __func__, ctl_hs, flow_repl);
-
- ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
- ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
- ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
- ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
- ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
- if (cflag & CRTSCTS) {
- ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
-
- flow_repl &= ~CP210X_SERIAL_RTS_MASK;
- flow_repl |= CP210X_SERIAL_RTS_SHIFT(
- CP210X_SERIAL_RTS_FLOW_CTL);
- dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
- } else {
- ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
+ if (C_CSTOPB(tty))
+ bits |= BITS_STOP_2;
+ else
+ bits |= BITS_STOP_1;
- flow_repl &= ~CP210X_SERIAL_RTS_MASK;
- flow_repl |= CP210X_SERIAL_RTS_SHIFT(
- CP210X_SERIAL_RTS_ACTIVE);
- dev_dbg(dev, "%s - flow control = NONE\n", __func__);
- }
+ ret = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
+ if (ret)
+ dev_err(&port->dev, "failed to set line control: %d\n", ret);
- dev_dbg(dev, "%s - write ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
- __func__, ctl_hs, flow_repl);
- flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
- flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
- cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
- sizeof(flow_ctl));
- }
+ cp210x_set_flow_control(tty, port, old_termios);
/*
* Enable event-insertion mode only if input parity checking is
@@ -1518,12 +1234,12 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
return cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
}
-static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
+static void cp210x_dtr_rts(struct usb_serial_port *port, int on)
{
if (on)
- cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0);
+ cp210x_tiocmset_port(port, TIOCM_DTR | TIOCM_RTS, 0);
else
- cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS);
+ cp210x_tiocmset_port(port, 0, TIOCM_DTR | TIOCM_RTS);
}
static int cp210x_tiocmget(struct tty_struct *tty)
@@ -1986,7 +1702,6 @@ static int cp210x_port_probe(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct cp210x_port_private *port_priv;
- int ret;
port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
if (!port_priv)
@@ -1996,12 +1711,6 @@ static int cp210x_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, port_priv);
- ret = cp210x_detect_swapped_line_ctl(port);
- if (ret) {
- kfree(port_priv);
- return ret;
- }
-
return 0;
}
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 821970609695..2e40908963da 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -357,11 +357,12 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
struct device *dev = &port->dev;
int status = urb->status;
unsigned long flags;
+ bool resubmitted = false;
- set_bit(0, &port->write_urbs_free);
if (status) {
dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
__func__, status);
+ set_bit(0, &port->write_urbs_free);
return;
}
@@ -394,6 +395,8 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
goto exit;
}
+ resubmitted = true;
+
dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
@@ -410,6 +413,8 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
exit:
spin_unlock_irqrestore(&priv->lock, flags);
+ if (!resubmitted)
+ set_bit(0, &port->write_urbs_free);
usb_serial_port_softint(port);
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 91055a191995..0ecd5316d85f 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -19,7 +19,6 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/workqueue.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/wait.h>
@@ -198,14 +197,13 @@ struct digi_port {
int dp_throttle_restart;
wait_queue_head_t dp_flush_wait;
wait_queue_head_t dp_close_wait; /* wait queue for close */
- struct work_struct dp_wakeup_work;
+ wait_queue_head_t write_wait;
struct usb_serial_port *dp_port;
};
/* Local Function Declarations */
-static void digi_wakeup_write_lock(struct work_struct *work);
static int digi_write_oob_command(struct usb_serial_port *port,
unsigned char *buf, int count, int interruptible);
static int digi_write_inb_command(struct usb_serial_port *port,
@@ -356,26 +354,6 @@ __releases(lock)
return timeout;
}
-
-/*
- * Digi Wakeup Write
- *
- * Wake up port, line discipline, and tty processes sleeping
- * on writes.
- */
-
-static void digi_wakeup_write_lock(struct work_struct *work)
-{
- struct digi_port *priv =
- container_of(work, struct digi_port, dp_wakeup_work);
- struct usb_serial_port *port = priv->dp_port;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->dp_port_lock, flags);
- tty_port_tty_wakeup(&port->port);
- spin_unlock_irqrestore(&priv->dp_port_lock, flags);
-}
-
/*
* Digi Write OOB Command
*
@@ -404,7 +382,7 @@ static int digi_write_oob_command(struct usb_serial_port *port,
while (count > 0) {
while (oob_priv->dp_write_urb_in_use) {
cond_wait_interruptible_timeout_irqrestore(
- &oob_port->write_wait, DIGI_RETRY_TIMEOUT,
+ &oob_priv->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags);
if (interruptible && signal_pending(current))
return -EINTR;
@@ -467,7 +445,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
while (priv->dp_write_urb_in_use &&
time_before(jiffies, timeout)) {
cond_wait_interruptible_timeout_irqrestore(
- &port->write_wait, DIGI_RETRY_TIMEOUT,
+ &priv->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags);
if (signal_pending(current))
return -EINTR;
@@ -546,7 +524,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
while (oob_priv->dp_write_urb_in_use) {
spin_unlock(&port_priv->dp_port_lock);
cond_wait_interruptible_timeout_irqrestore(
- &oob_port->write_wait, DIGI_RETRY_TIMEOUT,
+ &oob_priv->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags);
if (interruptible && signal_pending(current))
return -EINTR;
@@ -911,9 +889,8 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long flags = 0;
- dev_dbg(&port->dev,
- "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld\n",
- priv->dp_port_num, count, in_interrupt());
+ dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n",
+ priv->dp_port_num, count);
/* copy user data (which can sleep) before getting spin lock */
count = min(count, port->bulk_out_size-2);
@@ -986,6 +963,7 @@ static void digi_write_bulk_callback(struct urb *urb)
unsigned long flags;
int ret = 0;
int status = urb->status;
+ bool wakeup;
/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
@@ -1006,12 +984,13 @@ static void digi_write_bulk_callback(struct urb *urb)
dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n");
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_write_urb_in_use = 0;
- wake_up_interruptible(&port->write_wait);
+ wake_up_interruptible(&priv->write_wait);
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return;
}
/* try to send any buffered data on this port */
+ wakeup = true;
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_write_urb_in_use = 0;
if (priv->dp_out_buf_len > 0) {
@@ -1027,19 +1006,18 @@ static void digi_write_bulk_callback(struct urb *urb)
if (ret == 0) {
priv->dp_write_urb_in_use = 1;
priv->dp_out_buf_len = 0;
+ wakeup = false;
}
}
- /* wake up processes sleeping on writes immediately */
- tty_port_tty_wakeup(&port->port);
- /* also queue up a wakeup at scheduler time, in case we */
- /* lost the race in write_chan(). */
- schedule_work(&priv->dp_wakeup_work);
-
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+
if (ret && ret != -EPERM)
dev_err_console(port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
+
+ if (wakeup)
+ tty_port_tty_wakeup(&port->port);
}
static int digi_write_room(struct tty_struct *tty)
@@ -1239,11 +1217,9 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
init_waitqueue_head(&priv->dp_transmit_idle_wait);
init_waitqueue_head(&priv->dp_flush_wait);
init_waitqueue_head(&priv->dp_close_wait);
- INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
+ init_waitqueue_head(&priv->write_wait);
priv->dp_port = port;
- init_waitqueue_head(&port->write_wait);
-
usb_set_serial_port_data(port, priv);
return 0;
@@ -1508,13 +1484,14 @@ static int digi_read_oob_callback(struct urb *urb)
rts = C_CRTSCTS(tty);
if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
+ bool wakeup = false;
+
spin_lock_irqsave(&priv->dp_port_lock, flags);
/* convert from digi flags to termiox flags */
if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
priv->dp_modem_signals |= TIOCM_CTS;
- /* port must be open to use tty struct */
if (rts)
- tty_port_tty_wakeup(&port->port);
+ wakeup = true;
} else {
priv->dp_modem_signals &= ~TIOCM_CTS;
/* port must be open to use tty struct */
@@ -1533,6 +1510,9 @@ static int digi_read_oob_callback(struct urb *urb)
priv->dp_modem_signals &= ~TIOCM_CD;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+
+ if (wakeup)
+ tty_port_tty_wakeup(&port->port);
} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_transmit_idle = 1;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index e0f4c3d9649c..94398f89e600 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1841,9 +1841,6 @@ static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int result;
- if (priv->gpio_altfunc & BIT(offset))
- return -ENODEV;
-
mutex_lock(&priv->gpio_lock);
if (!priv->gpio_used) {
/* Set default pin states, as we cannot get them from device */
@@ -2002,6 +1999,25 @@ static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
return result;
}
+static int ftdi_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ unsigned long map = priv->gpio_altfunc;
+
+ bitmap_complement(valid_mask, &map, ngpios);
+
+ if (bitmap_empty(valid_mask, ngpios))
+ dev_dbg(&port->dev, "no CBUS pin configured for GPIO\n");
+ else
+ dev_dbg(&port->dev, "CBUS%*pbl configured for GPIO\n", ngpios,
+ valid_mask);
+
+ return 0;
+}
+
static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr,
u16 nbytes)
{
@@ -2173,6 +2189,7 @@ static int ftdi_gpio_init(struct usb_serial_port *port)
priv->gc.get_direction = ftdi_gpio_direction_get;
priv->gc.direction_input = ftdi_gpio_direction_input;
priv->gc.direction_output = ftdi_gpio_direction_output;
+ priv->gc.init_valid_mask = ftdi_gpio_init_valid_mask;
priv->gc.get = ftdi_gpio_get;
priv->gc.set = ftdi_gpio_set;
priv->gc.get_multiple = ftdi_gpio_get_multiple;
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index b4ba79123d9d..f1201d4de297 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -850,7 +850,6 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base,
default:
kfree(dataout);
return IUU_INVALID_PARAMETER;
- break;
}
switch (parity & 0xF0) {
@@ -864,7 +863,6 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base,
default:
kfree(dataout);
return IUU_INVALID_PARAMETER;
- break;
}
status = bulk_immediate(port, dataout, DataCount);
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index c1333919716b..e6f933e8d25f 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -5,12 +5,12 @@
* Copyright (C) 1999 - 2001 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com>
* Copyright (C) 2000 Al Borchers <borchers@steinerpoint.com>
+ * Copyright (C) 2020 Johan Hovold <johan@kernel.org>
*
* See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
-
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -25,30 +25,19 @@
#include <linux/usb/serial.h>
#include <linux/usb/ezusb.h>
-/* make a simple define to handle if we are compiling keyspan_pda or xircom support */
-#if IS_ENABLED(CONFIG_USB_SERIAL_KEYSPAN_PDA)
- #define KEYSPAN
-#else
- #undef KEYSPAN
-#endif
-#if IS_ENABLED(CONFIG_USB_SERIAL_XIRCOM)
- #define XIRCOM
-#else
- #undef XIRCOM
-#endif
-
-#define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>"
+#define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>, Johan Hovold <johan@kernel.org>"
#define DRIVER_DESC "USB Keyspan PDA Converter driver"
+#define KEYSPAN_TX_THRESHOLD 128
+
struct keyspan_pda_private {
int tx_room;
- int tx_throttled;
- struct work_struct wakeup_work;
- struct work_struct unthrottle_work;
+ struct work_struct unthrottle_work;
struct usb_serial *serial;
struct usb_serial_port *port;
};
+static int keyspan_pda_write_start(struct usb_serial_port *port);
#define KEYSPAN_VENDOR_ID 0x06cd
#define KEYSPAN_PDA_FAKE_ID 0x0103
@@ -62,18 +51,13 @@ struct keyspan_pda_private {
#define ENTREGA_FAKE_ID 0x8093
static const struct usb_device_id id_table_combined[] = {
-#ifdef KEYSPAN
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
-#endif
-#ifdef XIRCOM
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
{ USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
-#endif
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
{ } /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table_combined);
static const struct usb_device_id id_table_std[] = {
@@ -81,46 +65,71 @@ static const struct usb_device_id id_table_std[] = {
{ } /* Terminating entry */
};
-#ifdef KEYSPAN
static const struct usb_device_id id_table_fake[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
- { } /* Terminating entry */
-};
-#endif
-
-#ifdef XIRCOM
-static const struct usb_device_id id_table_fake_xircom[] = {
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
{ USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
- { }
+ { } /* Terminating entry */
};
-#endif
-static void keyspan_pda_wakeup_write(struct work_struct *work)
+static int keyspan_pda_get_write_room(struct keyspan_pda_private *priv)
{
- struct keyspan_pda_private *priv =
- container_of(work, struct keyspan_pda_private, wakeup_work);
struct usb_serial_port *port = priv->port;
+ struct usb_serial *serial = port->serial;
+ u8 *room;
+ int rc;
+
+ room = kmalloc(1, GFP_KERNEL);
+ if (!room)
+ return -ENOMEM;
- tty_port_tty_wakeup(&port->port);
+ rc = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 6, /* write_room */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_IN,
+ 0, /* value: 0 means "remaining room" */
+ 0, /* index */
+ room,
+ 1,
+ 2000);
+ if (rc != 1) {
+ if (rc >= 0)
+ rc = -EIO;
+ dev_dbg(&port->dev, "roomquery failed: %d\n", rc);
+ goto out_free;
+ }
+
+ dev_dbg(&port->dev, "roomquery says %d\n", *room);
+ rc = *room;
+out_free:
+ kfree(room);
+
+ return rc;
}
static void keyspan_pda_request_unthrottle(struct work_struct *work)
{
struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, unthrottle_work);
- struct usb_serial *serial = priv->serial;
+ struct usb_serial_port *port = priv->port;
+ struct usb_serial *serial = port->serial;
+ unsigned long flags;
int result;
- /* ask the device to tell us when the tx buffer becomes
- sufficiently empty */
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ /*
+ * Ask the device to tell us when the tx buffer becomes
+ * sufficiently empty.
+ */
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
7, /* request_unthrottle */
USB_TYPE_VENDOR | USB_RECIP_INTERFACE
| USB_DIR_OUT,
- 16, /* value: threshold */
+ KEYSPAN_TX_THRESHOLD,
0, /* index */
NULL,
0,
@@ -128,9 +137,20 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
if (result < 0)
dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n",
__func__, result);
+ /*
+ * Need to check available space after requesting notification in case
+ * buffer is already empty so that no notification is sent.
+ */
+ result = keyspan_pda_get_write_room(priv);
+ if (result > KEYSPAN_TX_THRESHOLD) {
+ spin_lock_irqsave(&port->lock, flags);
+ priv->tx_room = max(priv->tx_room, result);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ usb_serial_port_softint(port);
+ }
}
-
static void keyspan_pda_rx_interrupt(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -139,6 +159,8 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
int retval;
int status = urb->status;
struct keyspan_pda_private *priv;
+ unsigned long flags;
+
priv = usb_get_serial_port_data(port);
switch (status) {
@@ -172,18 +194,22 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
break;
case 1:
/* status interrupt */
- if (len < 3) {
+ if (len < 2) {
dev_warn(&port->dev, "short interrupt message received\n");
break;
}
- dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]);
+ dev_dbg(&port->dev, "rx int, d1=%d\n", data[1]);
switch (data[1]) {
case 1: /* modemline change */
break;
case 2: /* tx unthrottle interrupt */
- priv->tx_throttled = 0;
- /* queue up a wakeup at scheduler time */
- schedule_work(&priv->wakeup_work);
+ spin_lock_irqsave(&port->lock, flags);
+ priv->tx_room = max(priv->tx_room, KEYSPAN_TX_THRESHOLD);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ keyspan_pda_write_start(port);
+
+ usb_serial_port_softint(port);
break;
default:
break;
@@ -201,31 +227,30 @@ exit:
__func__, retval);
}
-
static void keyspan_pda_rx_throttle(struct tty_struct *tty)
{
- /* stop receiving characters. We just turn off the URB request, and
- let chars pile up in the device. If we're doing hardware
- flowcontrol, the device will signal the other end when its buffer
- fills up. If we're doing XON/XOFF, this would be a good time to
- send an XOFF, although it might make sense to foist that off
- upon the device too. */
struct usb_serial_port *port = tty->driver_data;
+ /*
+ * Stop receiving characters. We just turn off the URB request, and
+ * let chars pile up in the device. If we're doing hardware
+ * flowcontrol, the device will signal the other end when its buffer
+ * fills up. If we're doing XON/XOFF, this would be a good time to
+ * send an XOFF, although it might make sense to foist that off upon
+ * the device too.
+ */
usb_kill_urb(port->interrupt_in_urb);
}
-
static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- /* just restart the receive interrupt URB */
+ /* just restart the receive interrupt URB */
if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n");
}
-
static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
{
int rc;
@@ -267,8 +292,6 @@ static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
baud = 9600;
}
- /* rather than figure out how to sleep while waiting for this
- to complete, I just use the "legacy" API. */
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
0, /* set baud */
USB_TYPE_VENDOR
@@ -281,10 +304,10 @@ static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
2000); /* timeout */
if (rc < 0)
return 0;
+
return baud;
}
-
static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
@@ -296,6 +319,7 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state)
value = 1; /* start break */
else
value = 0; /* clear break */
+
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
4, /* set break */
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -303,39 +327,35 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state)
if (result < 0)
dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n",
__func__, result);
- /* there is something funky about this.. the TCSBRK that 'cu' performs
- ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
- seconds apart, but it feels like the break sent isn't as long as it
- is on /dev/ttyS0 */
}
-
static void keyspan_pda_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
speed_t speed;
- /* cflag specifies lots of stuff: number of stop bits, parity, number
- of data bits, baud. What can the device actually handle?:
- CSTOPB (1 stop bit or 2)
- PARENB (parity)
- CSIZE (5bit .. 8bit)
- There is minimal hw support for parity (a PSW bit seems to hold the
- parity of whatever is in the accumulator). The UART either deals
- with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
- 1 special, stop). So, with firmware changes, we could do:
- 8N1: 10 bit
- 8N2: 11 bit, extra bit always (mark?)
- 8[EOMS]1: 11 bit, extra bit is parity
- 7[EOMS]1: 10 bit, b0/b7 is parity
- 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
-
- HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS
- bit.
-
- For now, just do baud. */
-
+ /*
+ * cflag specifies lots of stuff: number of stop bits, parity, number
+ * of data bits, baud. What can the device actually handle?:
+ * CSTOPB (1 stop bit or 2)
+ * PARENB (parity)
+ * CSIZE (5bit .. 8bit)
+ * There is minimal hw support for parity (a PSW bit seems to hold the
+ * parity of whatever is in the accumulator). The UART either deals
+ * with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
+ * 1 special, stop). So, with firmware changes, we could do:
+ * 8N1: 10 bit
+ * 8N2: 11 bit, extra bit always (mark?)
+ * 8[EOMS]1: 11 bit, extra bit is parity
+ * 7[EOMS]1: 10 bit, b0/b7 is parity
+ * 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
+ *
+ * HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS
+ * bit.
+ *
+ * For now, just do baud.
+ */
speed = tty_get_baud_rate(tty);
speed = keyspan_pda_setbaud(serial, speed);
@@ -344,17 +364,19 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
/* It hasn't changed so.. */
speed = tty_termios_baud_rate(old_termios);
}
- /* Only speed can change so copy the old h/w parameters
- then encode the new speed */
+ /*
+ * Only speed can change so copy the old h/w parameters then encode
+ * the new speed.
+ */
tty_termios_copy_hw(&tty->termios, old_termios);
tty_encode_baud_rate(tty, speed, speed);
}
-
-/* modem control pins: DTR and RTS are outputs and can be controlled.
- DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
- read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
-
+/*
+ * Modem control pins: DTR and RTS are outputs and can be controlled.
+ * DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
+ * read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused.
+ */
static int keyspan_pda_get_modem_info(struct usb_serial *serial,
unsigned char *value)
{
@@ -378,7 +400,6 @@ static int keyspan_pda_get_modem_info(struct usb_serial *serial,
return rc;
}
-
static int keyspan_pda_set_modem_info(struct usb_serial *serial,
unsigned char value)
{
@@ -401,13 +422,14 @@ static int keyspan_pda_tiocmget(struct tty_struct *tty)
rc = keyspan_pda_get_modem_info(serial, &status);
if (rc < 0)
return rc;
- value =
- ((status & (1<<7)) ? TIOCM_DTR : 0) |
- ((status & (1<<6)) ? TIOCM_CAR : 0) |
- ((status & (1<<5)) ? TIOCM_RNG : 0) |
- ((status & (1<<4)) ? TIOCM_DSR : 0) |
- ((status & (1<<3)) ? TIOCM_CTS : 0) |
- ((status & (1<<2)) ? TIOCM_RTS : 0);
+
+ value = ((status & BIT(7)) ? TIOCM_DTR : 0) |
+ ((status & BIT(6)) ? TIOCM_CAR : 0) |
+ ((status & BIT(5)) ? TIOCM_RNG : 0) |
+ ((status & BIT(4)) ? TIOCM_DSR : 0) |
+ ((status & BIT(3)) ? TIOCM_CTS : 0) |
+ ((status & BIT(2)) ? TIOCM_RTS : 0);
+
return value;
}
@@ -424,186 +446,127 @@ static int keyspan_pda_tiocmset(struct tty_struct *tty,
return rc;
if (set & TIOCM_RTS)
- status |= (1<<2);
+ status |= BIT(2);
if (set & TIOCM_DTR)
- status |= (1<<7);
+ status |= BIT(7);
if (clear & TIOCM_RTS)
- status &= ~(1<<2);
+ status &= ~BIT(2);
if (clear & TIOCM_DTR)
- status &= ~(1<<7);
+ status &= ~BIT(7);
rc = keyspan_pda_set_modem_info(serial, status);
return rc;
}
-static int keyspan_pda_write(struct tty_struct *tty,
- struct usb_serial_port *port, const unsigned char *buf, int count)
+static int keyspan_pda_write_start(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
- int request_unthrottle = 0;
- int rc = 0;
- struct keyspan_pda_private *priv;
+ struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ struct urb *urb;
+ int count;
+ int room;
+ int rc;
- priv = usb_get_serial_port_data(port);
- /* guess how much room is left in the device's ring buffer, and if we
- want to send more than that, check first, updating our notion of
- what is left. If our write will result in no room left, ask the
- device to give us an interrupt when the room available rises above
- a threshold, and hold off all writers (eventually, those using
- select() or poll() too) until we receive that unthrottle interrupt.
- Block if we can't write anything at all, otherwise write as much as
- we can. */
- if (count == 0) {
- dev_dbg(&port->dev, "write request of 0 bytes\n");
- return 0;
- }
+ /*
+ * Guess how much room is left in the device's ring buffer. If our
+ * write will result in no room left, ask the device to give us an
+ * interrupt when the room available rises above a threshold but also
+ * query how much room is currently available (in case our guess was
+ * too conservative and the buffer is already empty when the
+ * unthrottle work is scheduled).
+ */
+
+ /*
+ * We might block because of:
+ * the TX urb is in-flight (wait until it completes)
+ * the device is full (wait until it says there is room)
+ */
+ spin_lock_irqsave(&port->lock, flags);
+
+ room = priv->tx_room;
+ count = kfifo_len(&port->write_fifo);
- /* we might block because of:
- the TX urb is in-flight (wait until it completes)
- the device is full (wait until it says there is room)
- */
- spin_lock_bh(&port->lock);
- if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) {
- spin_unlock_bh(&port->lock);
+ if (!test_bit(0, &port->write_urbs_free) || count == 0 || room == 0) {
+ spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
- clear_bit(0, &port->write_urbs_free);
- spin_unlock_bh(&port->lock);
-
- /* At this point the URB is in our control, nobody else can submit it
- again (the only sudden transition was the one from EINPROGRESS to
- finished). Also, the tx process is not throttled. So we are
- ready to write. */
-
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
- /* Check if we might overrun the Tx buffer. If so, ask the
- device how much room it really has. This is done only on
- scheduler time, since usb_control_msg() sleeps. */
- if (count > priv->tx_room && !in_interrupt()) {
- u8 *room;
-
- room = kmalloc(1, GFP_KERNEL);
- if (!room) {
- rc = -ENOMEM;
- goto exit;
- }
+ __clear_bit(0, &port->write_urbs_free);
- rc = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value: 0 means "remaining room" */
- 0, /* index */
- room,
- 1,
- 2000);
- if (rc > 0) {
- dev_dbg(&port->dev, "roomquery says %d\n", *room);
- priv->tx_room = *room;
- }
- kfree(room);
- if (rc < 0) {
- dev_dbg(&port->dev, "roomquery failed\n");
- goto exit;
- }
- if (rc == 0) {
- dev_dbg(&port->dev, "roomquery returned 0 bytes\n");
- rc = -EIO; /* device didn't return any data */
- goto exit;
- }
- }
- if (count > priv->tx_room) {
- /* we're about to completely fill the Tx buffer, so
- we'll be throttled afterwards. */
- count = priv->tx_room;
- request_unthrottle = 1;
- }
+ if (count > room)
+ count = room;
+ if (count > port->bulk_out_size)
+ count = port->bulk_out_size;
- if (count) {
- /* now transfer data */
- memcpy(port->write_urb->transfer_buffer, buf, count);
- /* send the data out the bulk port */
- port->write_urb->transfer_buffer_length = count;
+ urb = port->write_urb;
+ count = kfifo_out(&port->write_fifo, urb->transfer_buffer, count);
+ urb->transfer_buffer_length = count;
- priv->tx_room -= count;
+ port->tx_bytes += count;
+ priv->tx_room -= count;
- rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (rc) {
- dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n");
- goto exit;
- }
- } else {
- /* There wasn't any room left, so we are throttled until
- the buffer empties a bit */
- request_unthrottle = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ dev_dbg(&port->dev, "%s - count = %d, txroom = %d\n", __func__, count, room);
+
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc) {
+ dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n");
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->tx_bytes -= count;
+ priv->tx_room = max(priv->tx_room, room + count);
+ __set_bit(0, &port->write_urbs_free);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return rc;
}
- if (request_unthrottle) {
- priv->tx_throttled = 1; /* block writers */
+ if (count == room)
schedule_work(&priv->unthrottle_work);
- }
- rc = count;
-exit:
- if (rc < 0)
- set_bit(0, &port->write_urbs_free);
- return rc;
+ return count;
}
-
static void keyspan_pda_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct keyspan_pda_private *priv;
+ unsigned long flags;
- set_bit(0, &port->write_urbs_free);
- priv = usb_get_serial_port_data(port);
+ spin_lock_irqsave(&port->lock, flags);
+ port->tx_bytes -= urb->transfer_buffer_length;
+ __set_bit(0, &port->write_urbs_free);
+ spin_unlock_irqrestore(&port->lock, flags);
- /* queue up a wakeup at scheduler time */
- schedule_work(&priv->wakeup_work);
-}
+ keyspan_pda_write_start(port);
+ usb_serial_port_softint(port);
+}
-static int keyspan_pda_write_room(struct tty_struct *tty)
+static int keyspan_pda_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count)
{
- struct usb_serial_port *port = tty->driver_data;
- struct keyspan_pda_private *priv;
- priv = usb_get_serial_port_data(port);
- /* used by n_tty.c for processing of tabs and such. Giving it our
- conservative guess is probably good enough, but needs testing by
- running a console through the device. */
- return priv->tx_room;
-}
+ int rc;
+ dev_dbg(&port->dev, "%s - count = %d\n", __func__, count);
-static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct keyspan_pda_private *priv;
- unsigned long flags;
- int ret = 0;
+ if (!count)
+ return 0;
- priv = usb_get_serial_port_data(port);
+ count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
- /* when throttled, return at least WAKEUP_CHARS to tell select() (via
- n_tty.c:normal_poll() ) that we're not writeable. */
+ rc = keyspan_pda_write_start(port);
+ if (rc)
+ return rc;
- spin_lock_irqsave(&port->lock, flags);
- if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled)
- ret = 256;
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
+ return count;
}
-
static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
if (on)
- keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2));
+ keyspan_pda_set_modem_info(serial, BIT(7) | BIT(2));
else
keyspan_pda_set_modem_info(serial, 0);
}
@@ -612,74 +575,63 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
static int keyspan_pda_open(struct tty_struct *tty,
struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
- u8 *room;
- int rc = 0;
- struct keyspan_pda_private *priv;
+ struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+ int rc;
/* find out how much room is in the Tx ring */
- room = kmalloc(1, GFP_KERNEL);
- if (!room)
- return -ENOMEM;
+ rc = keyspan_pda_get_write_room(priv);
+ if (rc < 0)
+ return rc;
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 0, /* value */
- 0, /* index */
- room,
- 1,
- 2000);
- if (rc < 0) {
- dev_dbg(&port->dev, "%s - roomquery failed\n", __func__);
- goto error;
- }
- if (rc == 0) {
- dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__);
- rc = -EIO;
- goto error;
- }
- priv = usb_get_serial_port_data(port);
- priv->tx_room = *room;
- priv->tx_throttled = *room ? 0 : 1;
+ spin_lock_irq(&port->lock);
+ priv->tx_room = rc;
+ spin_unlock_irq(&port->lock);
- /*Start reading from the device*/
rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (rc) {
dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__);
- goto error;
+ return rc;
}
-error:
- kfree(room);
- return rc;
+
+ return 0;
}
+
static void keyspan_pda_close(struct usb_serial_port *port)
{
- usb_kill_urb(port->write_urb);
+ struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+
+ /*
+ * Stop the interrupt URB first as its completion handler may submit
+ * the write URB.
+ */
usb_kill_urb(port->interrupt_in_urb);
-}
+ usb_kill_urb(port->write_urb);
+
+ cancel_work_sync(&priv->unthrottle_work);
+ spin_lock_irq(&port->lock);
+ kfifo_reset(&port->write_fifo);
+ spin_unlock_irq(&port->lock);
+}
/* download the firmware to a "fake" device (pre-renumeration) */
static int keyspan_pda_fake_startup(struct usb_serial *serial)
{
+ unsigned int vid = le16_to_cpu(serial->dev->descriptor.idVendor);
const char *fw_name;
/* download the firmware here ... */
ezusb_fx1_set_reset(serial->dev, 1);
- if (0) { ; }
-#ifdef KEYSPAN
- else if (le16_to_cpu(serial->dev->descriptor.idVendor) == KEYSPAN_VENDOR_ID)
+ switch (vid) {
+ case KEYSPAN_VENDOR_ID:
fw_name = "keyspan_pda/keyspan_pda.fw";
-#endif
-#ifdef XIRCOM
- else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) ||
- (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGA_VENDOR_ID))
+ break;
+ case XIRCOM_VENDOR_ID:
+ case ENTREGA_VENDOR_ID:
fw_name = "keyspan_pda/xircom_pgs.fw";
-#endif
- else {
+ break;
+ default:
dev_err(&serial->dev->dev, "%s: unknown vendor, aborting.\n",
__func__);
return -ENODEV;
@@ -691,19 +643,17 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
return -ENOENT;
}
- /* after downloading firmware Renumeration will occur in a
- moment and the new device will bind to the real driver */
+ /*
+ * After downloading firmware renumeration will occur in a moment and
+ * the new device will bind to the real driver.
+ */
- /* we want this device to fail to have a driver assigned to it. */
+ /* We want this device to fail to have a driver assigned to it. */
return 1;
}
-#ifdef KEYSPAN
MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
-#endif
-#ifdef XIRCOM
MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
-#endif
static int keyspan_pda_port_probe(struct usb_serial_port *port)
{
@@ -714,9 +664,7 @@ static int keyspan_pda_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
- INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write);
INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle);
- priv->serial = port->serial;
priv->port = port;
usb_set_serial_port_data(port, priv);
@@ -734,7 +682,6 @@ static int keyspan_pda_port_remove(struct usb_serial_port *port)
return 0;
}
-#ifdef KEYSPAN
static struct usb_serial_driver keyspan_pda_fake_device = {
.driver = {
.owner = THIS_MODULE,
@@ -745,20 +692,6 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
.num_ports = 1,
.attach = keyspan_pda_fake_startup,
};
-#endif
-
-#ifdef XIRCOM
-static struct usb_serial_driver xircom_pgs_fake_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "xircom_no_firm",
- },
- .description = "Xircom / Entrega PGS - (prerenumeration)",
- .id_table = id_table_fake_xircom,
- .num_ports = 1,
- .attach = keyspan_pda_fake_startup,
-};
-#endif
static struct usb_serial_driver keyspan_pda_device = {
.driver = {
@@ -774,10 +707,8 @@ static struct usb_serial_driver keyspan_pda_device = {
.open = keyspan_pda_open,
.close = keyspan_pda_close,
.write = keyspan_pda_write,
- .write_room = keyspan_pda_write_room,
- .write_bulk_callback = keyspan_pda_write_bulk_callback,
+ .write_bulk_callback = keyspan_pda_write_bulk_callback,
.read_int_callback = keyspan_pda_rx_interrupt,
- .chars_in_buffer = keyspan_pda_chars_in_buffer,
.throttle = keyspan_pda_rx_throttle,
.unthrottle = keyspan_pda_rx_unthrottle,
.set_termios = keyspan_pda_set_termios,
@@ -790,12 +721,7 @@ static struct usb_serial_driver keyspan_pda_device = {
static struct usb_serial_driver * const serial_drivers[] = {
&keyspan_pda_device,
-#ifdef KEYSPAN
&keyspan_pda_fake_device,
-#endif
-#ifdef XIRCOM
- &xircom_pgs_fake_device,
-#endif
NULL
};
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5ee48b0650c4..5f6b82ebccc5 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -276,12 +276,12 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
priv->cfg.unknown2 = cfg->unknown2;
spin_unlock_irqrestore(&priv->lock, flags);
+ kfree(cfg);
+
/* READ_ON and urb submission */
rc = usb_serial_generic_open(tty, port);
- if (rc) {
- retval = rc;
- goto err_free_cfg;
- }
+ if (rc)
+ return rc;
rc = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
@@ -324,8 +324,6 @@ err_disable_read:
KLSI_TIMEOUT);
err_generic_close:
usb_serial_generic_close(port);
-err_free_cfg:
- kfree(cfg);
return retval;
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 5eed1078fac8..41ee2984a0df 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -79,14 +79,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define DCR_INIT_VAL 0x0c /* SLCTIN, nINIT */
#define ECR_INIT_VAL 0x00 /* SPP mode */
-struct urbtracker {
- struct mos7715_parport *mos_parport;
- struct list_head urblist_entry;
- struct kref ref_count;
- struct urb *urb;
- struct usb_ctrlrequest *setup;
-};
-
enum mos7715_pp_modes {
SPP = 0<<5,
PS2 = 1<<5, /* moschip calls this 'NIBBLE' mode */
@@ -96,12 +88,9 @@ enum mos7715_pp_modes {
struct mos7715_parport {
struct parport *pp; /* back to containing struct */
struct kref ref_count; /* to instance of this struct */
- struct list_head deferred_urbs; /* list deferred async urbs */
- struct list_head active_urbs; /* list async urbs in flight */
- spinlock_t listlock; /* protects list access */
bool msg_pending; /* usb sync call pending */
struct completion syncmsg_compl; /* usb sync call completed */
- struct tasklet_struct urb_tasklet; /* for sending deferred urbs */
+ struct work_struct work; /* restore deferred writes */
struct usb_serial *serial; /* back to containing struct */
__u8 shadowECR; /* parallel port regs... */
__u8 shadowDCR;
@@ -265,174 +254,8 @@ static void destroy_mos_parport(struct kref *kref)
kfree(mos_parport);
}
-static void destroy_urbtracker(struct kref *kref)
-{
- struct urbtracker *urbtrack =
- container_of(kref, struct urbtracker, ref_count);
- struct mos7715_parport *mos_parport = urbtrack->mos_parport;
-
- usb_free_urb(urbtrack->urb);
- kfree(urbtrack->setup);
- kfree(urbtrack);
- kref_put(&mos_parport->ref_count, destroy_mos_parport);
-}
-
/*
- * This runs as a tasklet when sending an urb in a non-blocking parallel
- * port callback had to be deferred because the disconnect mutex could not be
- * obtained at the time.
- */
-static void send_deferred_urbs(struct tasklet_struct *t)
-{
- int ret_val;
- unsigned long flags;
- struct mos7715_parport *mos_parport = from_tasklet(mos_parport, t,
- urb_tasklet);
- struct urbtracker *urbtrack, *tmp;
- struct list_head *cursor, *next;
- struct device *dev;
-
- /* if release function ran, game over */
- if (unlikely(mos_parport->serial == NULL))
- return;
-
- dev = &mos_parport->serial->dev->dev;
-
- /* try again to get the mutex */
- if (!mutex_trylock(&mos_parport->serial->disc_mutex)) {
- dev_dbg(dev, "%s: rescheduling tasklet\n", __func__);
- tasklet_schedule(&mos_parport->urb_tasklet);
- return;
- }
-
- /* if device disconnected, game over */
- if (unlikely(mos_parport->serial->disconnected)) {
- mutex_unlock(&mos_parport->serial->disc_mutex);
- return;
- }
-
- spin_lock_irqsave(&mos_parport->listlock, flags);
- if (list_empty(&mos_parport->deferred_urbs)) {
- spin_unlock_irqrestore(&mos_parport->listlock, flags);
- mutex_unlock(&mos_parport->serial->disc_mutex);
- dev_dbg(dev, "%s: deferred_urbs list empty\n", __func__);
- return;
- }
-
- /* move contents of deferred_urbs list to active_urbs list and submit */
- list_for_each_safe(cursor, next, &mos_parport->deferred_urbs)
- list_move_tail(cursor, &mos_parport->active_urbs);
- list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs,
- urblist_entry) {
- ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
- dev_dbg(dev, "%s: urb submitted\n", __func__);
- if (ret_val) {
- dev_err(dev, "usb_submit_urb() failed: %d\n", ret_val);
- list_del(&urbtrack->urblist_entry);
- kref_put(&urbtrack->ref_count, destroy_urbtracker);
- }
- }
- spin_unlock_irqrestore(&mos_parport->listlock, flags);
- mutex_unlock(&mos_parport->serial->disc_mutex);
-}
-
-/* callback for parallel port control urbs submitted asynchronously */
-static void async_complete(struct urb *urb)
-{
- struct urbtracker *urbtrack = urb->context;
- int status = urb->status;
- unsigned long flags;
-
- if (unlikely(status))
- dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
-
- /* remove the urbtracker from the active_urbs list */
- spin_lock_irqsave(&urbtrack->mos_parport->listlock, flags);
- list_del(&urbtrack->urblist_entry);
- spin_unlock_irqrestore(&urbtrack->mos_parport->listlock, flags);
- kref_put(&urbtrack->ref_count, destroy_urbtracker);
-}
-
-static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
- enum mos_regs reg, __u8 data)
-{
- struct urbtracker *urbtrack;
- int ret_val;
- unsigned long flags;
- struct usb_serial *serial = mos_parport->serial;
- struct usb_device *usbdev = serial->dev;
-
- /* create and initialize the control urb and containing urbtracker */
- urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
- if (!urbtrack)
- return -ENOMEM;
-
- urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urbtrack->urb) {
- kfree(urbtrack);
- return -ENOMEM;
- }
- urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC);
- if (!urbtrack->setup) {
- usb_free_urb(urbtrack->urb);
- kfree(urbtrack);
- return -ENOMEM;
- }
- urbtrack->setup->bRequestType = (__u8)0x40;
- urbtrack->setup->bRequest = (__u8)0x0e;
- urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy));
- urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg));
- urbtrack->setup->wLength = 0;
- usb_fill_control_urb(urbtrack->urb, usbdev,
- usb_sndctrlpipe(usbdev, 0),
- (unsigned char *)urbtrack->setup,
- NULL, 0, async_complete, urbtrack);
- kref_get(&mos_parport->ref_count);
- urbtrack->mos_parport = mos_parport;
- kref_init(&urbtrack->ref_count);
- INIT_LIST_HEAD(&urbtrack->urblist_entry);
-
- /*
- * get the disconnect mutex, or add tracker to the deferred_urbs list
- * and schedule a tasklet to try again later
- */
- if (!mutex_trylock(&serial->disc_mutex)) {
- spin_lock_irqsave(&mos_parport->listlock, flags);
- list_add_tail(&urbtrack->urblist_entry,
- &mos_parport->deferred_urbs);
- spin_unlock_irqrestore(&mos_parport->listlock, flags);
- tasklet_schedule(&mos_parport->urb_tasklet);
- dev_dbg(&usbdev->dev, "tasklet scheduled\n");
- return 0;
- }
-
- /* bail if device disconnected */
- if (serial->disconnected) {
- kref_put(&urbtrack->ref_count, destroy_urbtracker);
- mutex_unlock(&serial->disc_mutex);
- return -ENODEV;
- }
-
- /* add the tracker to the active_urbs list and submit */
- spin_lock_irqsave(&mos_parport->listlock, flags);
- list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs);
- spin_unlock_irqrestore(&mos_parport->listlock, flags);
- ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
- mutex_unlock(&serial->disc_mutex);
- if (ret_val) {
- dev_err(&usbdev->dev,
- "%s: submit_urb() failed: %d\n", __func__, ret_val);
- spin_lock_irqsave(&mos_parport->listlock, flags);
- list_del(&urbtrack->urblist_entry);
- spin_unlock_irqrestore(&mos_parport->listlock, flags);
- kref_put(&urbtrack->ref_count, destroy_urbtracker);
- return ret_val;
- }
- return 0;
-}
-
-/*
- * This is the the common top part of all parallel port callback operations that
+ * This is the common top part of all parallel port callback operations that
* send synchronous messages to the device. This implements convoluted locking
* that avoids two scenarios: (1) a port operation is called after usbserial
* has called our release function, at which point struct mos7715_parport has
@@ -458,6 +281,10 @@ static int parport_prologue(struct parport *pp)
reinit_completion(&mos_parport->syncmsg_compl);
spin_unlock(&release_lock);
+ /* ensure writes from restore are submitted before new requests */
+ if (work_pending(&mos_parport->work))
+ flush_work(&mos_parport->work);
+
mutex_lock(&mos_parport->serial->disc_mutex);
if (mos_parport->serial->disconnected) {
/* device disconnected */
@@ -482,6 +309,26 @@ static inline void parport_epilogue(struct parport *pp)
complete(&mos_parport->syncmsg_compl);
}
+static void deferred_restore_writes(struct work_struct *work)
+{
+ struct mos7715_parport *mos_parport;
+
+ mos_parport = container_of(work, struct mos7715_parport, work);
+
+ mutex_lock(&mos_parport->serial->disc_mutex);
+
+ /* if device disconnected, game over */
+ if (mos_parport->serial->disconnected)
+ goto done;
+
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+ mos_parport->shadowDCR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
+ mos_parport->shadowECR);
+done:
+ mutex_unlock(&mos_parport->serial->disc_mutex);
+}
+
static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
{
struct mos7715_parport *mos_parport = pp->private_data;
@@ -639,10 +486,10 @@ static void parport_mos7715_restore_state(struct parport *pp,
spin_unlock(&release_lock);
return;
}
- write_parport_reg_nonblock(mos_parport, MOS7720_DCR,
- mos_parport->shadowDCR);
- write_parport_reg_nonblock(mos_parport, MOS7720_ECR,
- mos_parport->shadowECR);
+ mos_parport->shadowDCR = s->u.pc.ctr;
+ mos_parport->shadowECR = s->u.pc.ecr;
+
+ schedule_work(&mos_parport->work);
spin_unlock(&release_lock);
}
@@ -712,12 +559,9 @@ static int mos7715_parport_init(struct usb_serial *serial)
mos_parport->msg_pending = false;
kref_init(&mos_parport->ref_count);
- spin_lock_init(&mos_parport->listlock);
- INIT_LIST_HEAD(&mos_parport->active_urbs);
- INIT_LIST_HEAD(&mos_parport->deferred_urbs);
usb_set_serial_data(serial, mos_parport); /* hijack private pointer */
mos_parport->serial = serial;
- tasklet_setup(&mos_parport->urb_tasklet, send_deferred_urbs);
+ INIT_WORK(&mos_parport->work, deferred_restore_writes);
init_completion(&mos_parport->syncmsg_compl);
/* cycle parallel port reset bit */
@@ -1867,8 +1711,6 @@ static void mos7720_release(struct usb_serial *serial)
if (le16_to_cpu(serial->dev->descriptor.idProduct)
== MOSCHIP_DEVICE_ID_7715) {
- struct urbtracker *urbtrack;
- unsigned long flags;
struct mos7715_parport *mos_parport =
usb_get_serial_data(serial);
@@ -1881,21 +1723,17 @@ static void mos7720_release(struct usb_serial *serial)
if (mos_parport->msg_pending)
wait_for_completion_timeout(&mos_parport->syncmsg_compl,
msecs_to_jiffies(MOS_WDR_TIMEOUT));
+ /*
+ * If delayed work is currently scheduled, wait for it to
+ * complete. This also implies barriers that ensure the
+ * below serial clearing is not hoisted above the ->work.
+ */
+ cancel_work_sync(&mos_parport->work);
parport_remove_port(mos_parport->pp);
usb_set_serial_data(serial, NULL);
mos_parport->serial = NULL;
- /* if tasklet currently scheduled, wait for it to complete */
- tasklet_kill(&mos_parport->urb_tasklet);
-
- /* unlink any urbs sent by the tasklet */
- spin_lock_irqsave(&mos_parport->listlock, flags);
- list_for_each_entry(urbtrack,
- &mos_parport->active_urbs,
- urblist_entry)
- usb_unlink_urb(urbtrack->urb);
- spin_unlock_irqrestore(&mos_parport->listlock, flags);
parport_del_port(mos_parport->pp);
kref_put(&mos_parport->ref_count, destroy_mos_parport);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 2a3bfd6f867e..2c21e34235bb 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -250,6 +250,7 @@ static void option_instat_callback(struct urb *urb);
#define QUECTEL_PRODUCT_EP06 0x0306
#define QUECTEL_PRODUCT_EM12 0x0512
#define QUECTEL_PRODUCT_RM500Q 0x0800
+#define QUECTEL_PRODUCT_EC200T 0x6026
#define CMOTECH_VENDOR_ID 0x16d8
#define CMOTECH_PRODUCT_6001 0x6001
@@ -418,6 +419,7 @@ static void option_instat_callback(struct urb *urb);
#define CINTERION_PRODUCT_PH8 0x0053
#define CINTERION_PRODUCT_AHXX 0x0055
#define CINTERION_PRODUCT_PLXX 0x0060
+#define CINTERION_PRODUCT_EXS82 0x006c
#define CINTERION_PRODUCT_PH8_2RMNET 0x0082
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
@@ -561,6 +563,9 @@ static void option_instat_callback(struct urb *urb);
/* Device flags */
+/* Highest interface number which can be used with NCTRL() and RSVD() */
+#define FLAG_IFNUM_MAX 7
+
/* Interface does not support modem-control requests */
#define NCTRL(ifnum) ((BIT(ifnum) & 0xff) << 8)
@@ -1104,9 +1109,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0xff, 0xff),
.driver_info = NUMEP2 },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0, 0) },
- { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96, 0xff, 0xff, 0xff),
- .driver_info = NUMEP2 },
- { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96, 0xff, 0, 0) },
+ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
@@ -1117,6 +1121,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x10),
.driver_info = ZLP },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
@@ -1189,6 +1194,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1054, 0xff), /* Telit FT980-KS */
.driver_info = NCTRL(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1055, 0xff), /* Telit FN980 (PCIe) */
+ .driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
@@ -1201,6 +1208,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1203, 0xff), /* Telit LE910Cx (RNDIS) */
+ .driver_info = NCTRL(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
@@ -1215,6 +1224,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1230, 0xff), /* Telit LE910Cx (rmnet) */
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1231, 0xff), /* Telit LE910Cx (RNDIS) */
+ .driver_info = NCTRL(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, 0x1260),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, 0x1261),
@@ -1892,6 +1905,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_CLS8, 0xff),
.driver_info = RSVD(0) | RSVD(4) },
+ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EXS82, 0xff) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
@@ -2036,12 +2050,13 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(0x0489, 0xe0b5), /* Foxconn T77W968 ESIM */
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
- { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */
+ { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */
.driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
{ USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */
.driver_info = RSVD(4) | RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */
.driver_info = RSVD(6) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */
@@ -2089,6 +2104,14 @@ static struct usb_serial_driver * const serial_drivers[] = {
module_usb_serial_driver(serial_drivers, option_ids);
+static bool iface_is_reserved(unsigned long device_flags, u8 ifnum)
+{
+ if (ifnum > FLAG_IFNUM_MAX)
+ return false;
+
+ return device_flags & RSVD(ifnum);
+}
+
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
@@ -2105,7 +2128,7 @@ static int option_probe(struct usb_serial *serial,
* the same class/subclass/protocol as the serial interfaces. Look at
* the Windows driver .INF files for reserved interface numbers.
*/
- if (device_flags & RSVD(iface_desc->bInterfaceNumber))
+ if (iface_is_reserved(device_flags, iface_desc->bInterfaceNumber))
return -ENODEV;
/*
@@ -2121,6 +2144,14 @@ static int option_probe(struct usb_serial *serial,
return 0;
}
+static bool iface_no_modem_control(unsigned long device_flags, u8 ifnum)
+{
+ if (ifnum > FLAG_IFNUM_MAX)
+ return false;
+
+ return device_flags & NCTRL(ifnum);
+}
+
static int option_attach(struct usb_serial *serial)
{
struct usb_interface_descriptor *iface_desc;
@@ -2136,7 +2167,7 @@ static int option_attach(struct usb_serial *serial)
iface_desc = &serial->interface->cur_altsetting->desc;
- if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber)))
+ if (!iface_no_modem_control(device_flags, iface_desc->bInterfaceNumber))
data->use_send_setup = 1;
if (device_flags & ZLP)
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 98c1aa594e6c..5f7d678502be 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -861,6 +861,7 @@ static int ms_count_freeblock(struct us_data *us, u16 PhyBlock)
case MS_LB_NOT_USED:
case MS_LB_NOT_USED_ERASED:
Count++;
+ break;
default:
break;
}
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 3d5f7d0ff0f1..2b098b55c4cb 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -431,7 +431,6 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
us->srb->sc_data_direction);
/* Return fail, SCSI seems to handle this better. */
return USB_STOR_TRANSPORT_FAILED;
- break;
}
return USB_STOR_TRANSPORT_GOOD;
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 560efd1479ba..e5a971b83e3f 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -92,7 +92,7 @@ static int slave_alloc (struct scsi_device *sdev)
static int slave_configure(struct scsi_device *sdev)
{
struct us_data *us = host_to_us(sdev->host);
- struct device *dev = sdev->host->dma_dev;
+ struct device *dev = us->pusb_dev->bus->sysdev;
/*
* Many devices have trouble transferring more than 32KB at a time,
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 238a8088e17f..5eb895b19c55 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -416,7 +416,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* don't submit s-g requests during abort processing */
if (test_bit(US_FLIDX_ABORTING, &us->dflags))
- return USB_STOR_XFER_ERROR;
+ goto usb_stor_xfer_error;
/* initialize the scatter-gather request block */
usb_stor_dbg(us, "xfer %u bytes, %d entries\n", length, num_sg);
@@ -424,7 +424,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
sg, num_sg, length, GFP_NOIO);
if (result) {
usb_stor_dbg(us, "usb_sg_init returned %d\n", result);
- return USB_STOR_XFER_ERROR;
+ goto usb_stor_xfer_error;
}
/*
@@ -452,6 +452,11 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
*act_len = us->current_sg.bytes;
return interpret_urb_result(us, pipe, length, result,
us->current_sg.bytes);
+
+usb_stor_xfer_error:
+ if (act_len)
+ *act_len = 0;
+ return USB_STOR_XFER_ERROR;
}
/*
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index c8a577309e8f..bef89c6bd1d7 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -690,6 +690,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
fallthrough;
case DMA_TO_DEVICE:
cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
+ break;
case DMA_NONE:
break;
}
@@ -837,24 +838,17 @@ static int uas_slave_alloc(struct scsi_device *sdev)
*/
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+ if (devinfo->flags & US_FL_MAX_SECTORS_64)
+ blk_queue_max_hw_sectors(sdev->request_queue, 64);
+ else if (devinfo->flags & US_FL_MAX_SECTORS_240)
+ blk_queue_max_hw_sectors(sdev->request_queue, 240);
+
return 0;
}
static int uas_slave_configure(struct scsi_device *sdev)
{
struct uas_dev_info *devinfo = sdev->hostdata;
- struct device *dev = sdev->host->dma_dev;
-
- if (devinfo->flags & US_FL_MAX_SECTORS_64)
- blk_queue_max_hw_sectors(sdev->request_queue, 64);
- else if (devinfo->flags & US_FL_MAX_SECTORS_240)
- blk_queue_max_hw_sectors(sdev->request_queue, 240);
- else if (devinfo->udev->speed >= USB_SPEED_SUPER)
- blk_queue_max_hw_sectors(sdev->request_queue, 2048);
-
- blk_queue_max_hw_sectors(sdev->request_queue,
- min_t(size_t, queue_max_hw_sectors(sdev->request_queue),
- dma_max_mapping_size(dev) >> SECTOR_SHIFT));
if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
sdev->no_report_opcodes = 1;
@@ -874,6 +868,9 @@ static int uas_slave_configure(struct scsi_device *sdev)
if (devinfo->flags & US_FL_NO_READ_CAPACITY_16)
sdev->no_read_capacity_16 = 1;
+ /* Some disks cannot handle WRITE_SAME */
+ if (devinfo->flags & US_FL_NO_SAME)
+ sdev->no_write_same = 1;
/*
* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number.
@@ -1040,7 +1037,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
shost->can_queue = devinfo->qdepth - 2;
usb_set_intfdata(intf, shost);
- result = scsi_add_host_with_dma(shost, &intf->dev, udev->bus->sysdev);
+ result = scsi_add_host(shost, &intf->dev);
if (result)
goto free_streams;
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index 711ab240058c..870e9cf3d5dc 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -35,12 +35,15 @@ UNUSUAL_DEV(0x054c, 0x087d, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_REPORT_OPCODES),
-/* Reported-by: Julian Groß <julian.g@posteo.de> */
+/*
+ * Initially Reported-by: Julian Groß <julian.g@posteo.de>
+ * Further reports David C. Partridge <david.partridge@perdrix.co.uk>
+ */
UNUSUAL_DEV(0x059f, 0x105f, 0x0000, 0x9999,
"LaCie",
"2Big Quadra USB3",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
- US_FL_NO_REPORT_OPCODES),
+ US_FL_NO_REPORT_OPCODES | US_FL_NO_SAME),
/*
* Apricorn USB3 dongle sometimes returns "USBSUSBSUSBS" in response to SCSI
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index c2ef367cf257..90aa9c12ffac 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -541,6 +541,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
case 'j':
f |= US_FL_NO_REPORT_LUNS;
break;
+ case 'k':
+ f |= US_FL_NO_SAME;
+ break;
case 'l':
f |= US_FL_NOT_LOCKABLE;
break;
@@ -1049,9 +1052,8 @@ int usb_stor_probe2(struct us_data *us)
goto BadDevice;
usb_autopm_get_interface_no_resume(us->pusb_intf);
snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
- dev_name(dev));
- result = scsi_add_host_with_dma(us_to_host(us), dev,
- us->pusb_dev->bus->sysdev);
+ dev_name(&us->pusb_intf->dev));
+ result = scsi_add_host(us_to_host(us), dev);
if (result) {
dev_warn(dev,
"Unable to add the scsi host\n");
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
index 6c5908a37ee8..270e81c087e9 100644
--- a/drivers/usb/typec/Kconfig
+++ b/drivers/usb/typec/Kconfig
@@ -64,8 +64,9 @@ config TYPEC_HD3SS3220
config TYPEC_TPS6598X
tristate "TI TPS6598x USB Power Delivery controller driver"
depends on I2C
- depends on REGMAP_I2C
- depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
+ select POWER_SUPPLY
+ select REGMAP_I2C
+ select USB_ROLE_SWITCH
help
Say Y or M here if your system has TI TPS65982 or TPS65983 USB Power
Delivery controller.
@@ -88,6 +89,7 @@ config TYPEC_STUSB160X
config TYPEC_QCOM_PMIC
tristate "Qualcomm PMIC USB Type-C driver"
depends on ARCH_QCOM || COMPILE_TEST
+ depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
help
Driver for supporting role switch over the Qualcomm PMIC. This will
handle the USB Type-C role and orientation detection reported by the
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 35eec707cb51..ebfd3113a9a8 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -11,6 +11,7 @@
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/usb/pd_vdo.h>
#include "bus.h"
@@ -18,6 +19,7 @@ struct typec_plug {
struct device dev;
enum typec_plug_index index;
struct ida mode_ids;
+ int num_altmodes;
};
struct typec_cable {
@@ -33,6 +35,7 @@ struct typec_partner {
struct usb_pd_identity *identity;
enum typec_accessory accessory;
struct ida mode_ids;
+ int num_altmodes;
};
struct typec_port {
@@ -81,6 +84,29 @@ static const char * const typec_accessory_modes[] = {
[TYPEC_ACCESSORY_DEBUG] = "debug",
};
+/* Product types defined in USB PD Specification R3.0 V2.0 */
+static const char * const product_type_ufp[8] = {
+ [IDH_PTYPE_UNDEF] = "undefined",
+ [IDH_PTYPE_HUB] = "hub",
+ [IDH_PTYPE_PERIPH] = "peripheral",
+ [IDH_PTYPE_PSD] = "psd",
+ [IDH_PTYPE_AMA] = "ama",
+};
+
+static const char * const product_type_dfp[8] = {
+ [IDH_PTYPE_DFP_UNDEF] = "undefined",
+ [IDH_PTYPE_DFP_HUB] = "hub",
+ [IDH_PTYPE_DFP_HOST] = "host",
+ [IDH_PTYPE_DFP_PB] = "power_brick",
+ [IDH_PTYPE_DFP_AMC] = "amc",
+};
+
+static const char * const product_type_cable[8] = {
+ [IDH_PTYPE_UNDEF] = "undefined",
+ [IDH_PTYPE_PCABLE] = "passive",
+ [IDH_PTYPE_ACABLE] = "active",
+};
+
static struct usb_pd_identity *get_pd_identity(struct device *dev)
{
if (is_typec_partner(dev)) {
@@ -95,6 +121,32 @@ static struct usb_pd_identity *get_pd_identity(struct device *dev)
return NULL;
}
+static const char *get_pd_product_type(struct device *dev)
+{
+ struct typec_port *port = to_typec_port(dev->parent);
+ struct usb_pd_identity *id = get_pd_identity(dev);
+ const char *ptype = NULL;
+
+ if (is_typec_partner(dev)) {
+ if (!id)
+ return NULL;
+
+ if (port->data_role == TYPEC_HOST)
+ ptype = product_type_ufp[PD_IDH_PTYPE(id->id_header)];
+ else
+ ptype = product_type_dfp[PD_IDH_DFP_PTYPE(id->id_header)];
+ } else if (is_typec_cable(dev)) {
+ if (id)
+ ptype = product_type_cable[PD_IDH_PTYPE(id->id_header)];
+ else
+ ptype = to_typec_cable(dev)->active ?
+ product_type_cable[IDH_PTYPE_ACABLE] :
+ product_type_cable[IDH_PTYPE_PCABLE];
+ }
+
+ return ptype;
+}
+
static ssize_t id_header_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -122,10 +174,40 @@ static ssize_t product_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(product);
+static ssize_t product_type_vdo1_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_pd_identity *id = get_pd_identity(dev);
+
+ return sysfs_emit(buf, "0x%08x\n", id->vdo[0]);
+}
+static DEVICE_ATTR_RO(product_type_vdo1);
+
+static ssize_t product_type_vdo2_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_pd_identity *id = get_pd_identity(dev);
+
+ return sysfs_emit(buf, "0x%08x\n", id->vdo[1]);
+}
+static DEVICE_ATTR_RO(product_type_vdo2);
+
+static ssize_t product_type_vdo3_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_pd_identity *id = get_pd_identity(dev);
+
+ return sysfs_emit(buf, "0x%08x\n", id->vdo[2]);
+}
+static DEVICE_ATTR_RO(product_type_vdo3);
+
static struct attribute *usb_pd_id_attrs[] = {
&dev_attr_id_header.attr,
&dev_attr_cert_stat.attr,
&dev_attr_product.attr,
+ &dev_attr_product_type_vdo1.attr,
+ &dev_attr_product_type_vdo2.attr,
+ &dev_attr_product_type_vdo3.attr,
NULL
};
@@ -139,12 +221,48 @@ static const struct attribute_group *usb_pd_id_groups[] = {
NULL,
};
+static void typec_product_type_notify(struct device *dev)
+{
+ char *envp[2] = { };
+ const char *ptype;
+
+ ptype = get_pd_product_type(dev);
+ if (!ptype)
+ return;
+
+ sysfs_notify(&dev->kobj, NULL, "type");
+
+ envp[0] = kasprintf(GFP_KERNEL, "PRODUCT_TYPE=%s", ptype);
+ if (!envp[0])
+ return;
+
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+ kfree(envp[0]);
+}
+
static void typec_report_identity(struct device *dev)
{
sysfs_notify(&dev->kobj, "identity", "id_header");
sysfs_notify(&dev->kobj, "identity", "cert_stat");
sysfs_notify(&dev->kobj, "identity", "product");
+ sysfs_notify(&dev->kobj, "identity", "product_type_vdo1");
+ sysfs_notify(&dev->kobj, "identity", "product_type_vdo2");
+ sysfs_notify(&dev->kobj, "identity", "product_type_vdo3");
+ typec_product_type_notify(dev);
+}
+
+static ssize_t
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ const char *ptype;
+
+ ptype = get_pd_product_type(dev);
+ if (!ptype)
+ return 0;
+
+ return sysfs_emit(buf, "%s\n", ptype);
}
+static DEVICE_ATTR_RO(type);
/* ------------------------------------------------------------------------- */
/* Alternate Modes */
@@ -382,7 +500,7 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
return attr->mode;
}
-static struct attribute_group typec_altmode_group = {
+static const struct attribute_group typec_altmode_group = {
.is_visible = typec_altmode_attr_is_visible,
.attrs = typec_altmode_attrs,
};
@@ -482,6 +600,10 @@ typec_register_altmode(struct device *parent,
if (is_typec_partner(parent))
alt->adev.dev.bus = &typec_bus;
+ /* Plug alt modes need a class to generate udev events. */
+ if (is_typec_plug(parent))
+ alt->adev.dev.class = typec_class;
+
ret = device_register(&alt->adev.dev);
if (ret) {
dev_err(parent, "failed to register alternate mode (%d)\n",
@@ -532,12 +654,60 @@ static ssize_t supports_usb_power_delivery_show(struct device *dev,
}
static DEVICE_ATTR_RO(supports_usb_power_delivery);
+static ssize_t number_of_alternate_modes_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_partner *partner;
+ struct typec_plug *plug;
+ int num_altmodes;
+
+ if (is_typec_partner(dev)) {
+ partner = to_typec_partner(dev);
+ num_altmodes = partner->num_altmodes;
+ } else if (is_typec_plug(dev)) {
+ plug = to_typec_plug(dev);
+ num_altmodes = plug->num_altmodes;
+ } else {
+ return 0;
+ }
+
+ return sysfs_emit(buf, "%d\n", num_altmodes);
+}
+static DEVICE_ATTR_RO(number_of_alternate_modes);
+
static struct attribute *typec_partner_attrs[] = {
&dev_attr_accessory_mode.attr,
&dev_attr_supports_usb_power_delivery.attr,
+ &dev_attr_number_of_alternate_modes.attr,
+ &dev_attr_type.attr,
+ NULL
+};
+
+static umode_t typec_partner_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ struct typec_partner *partner = to_typec_partner(kobj_to_dev(kobj));
+
+ if (attr == &dev_attr_number_of_alternate_modes.attr) {
+ if (partner->num_altmodes < 0)
+ return 0;
+ }
+
+ if (attr == &dev_attr_type.attr)
+ if (!get_pd_product_type(kobj_to_dev(kobj)))
+ return 0;
+
+ return attr->mode;
+}
+
+static const struct attribute_group typec_partner_group = {
+ .is_visible = typec_partner_attr_is_visible,
+ .attrs = typec_partner_attrs
+};
+
+static const struct attribute_group *typec_partner_groups[] = {
+ &typec_partner_group,
NULL
};
-ATTRIBUTE_GROUPS(typec_partner);
static void typec_partner_release(struct device *dev)
{
@@ -571,6 +741,37 @@ int typec_partner_set_identity(struct typec_partner *partner)
EXPORT_SYMBOL_GPL(typec_partner_set_identity);
/**
+ * typec_partner_set_num_altmodes - Set the number of available partner altmodes
+ * @partner: The partner to be updated.
+ * @num_altmodes: The number of altmodes we want to specify as available.
+ *
+ * This routine is used to report the number of alternate modes supported by the
+ * partner. This value is *not* enforced in alternate mode registration routines.
+ *
+ * @partner.num_altmodes is set to -1 on partner registration, denoting that
+ * a valid value has not been set for it yet.
+ *
+ * Returns 0 on success or negative error number on failure.
+ */
+int typec_partner_set_num_altmodes(struct typec_partner *partner, int num_altmodes)
+{
+ int ret;
+
+ if (num_altmodes < 0)
+ return -EINVAL;
+
+ partner->num_altmodes = num_altmodes;
+ ret = sysfs_update_group(&partner->dev.kobj, &typec_partner_group);
+ if (ret < 0)
+ return ret;
+
+ sysfs_notify(&partner->dev.kobj, NULL, "number_of_alternate_modes");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_partner_set_num_altmodes);
+
+/**
* typec_partner_register_altmode - Register USB Type-C Partner Alternate Mode
* @partner: USB Type-C Partner that supports the alternate mode
* @desc: Description of the alternate mode
@@ -612,6 +813,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
ida_init(&partner->mode_ids);
partner->usb_pd = desc->usb_pd;
partner->accessory = desc->accessory;
+ partner->num_altmodes = -1;
if (desc->identity) {
/*
@@ -662,12 +864,71 @@ static void typec_plug_release(struct device *dev)
kfree(plug);
}
+static struct attribute *typec_plug_attrs[] = {
+ &dev_attr_number_of_alternate_modes.attr,
+ NULL
+};
+
+static umode_t typec_plug_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ struct typec_plug *plug = to_typec_plug(kobj_to_dev(kobj));
+
+ if (attr == &dev_attr_number_of_alternate_modes.attr) {
+ if (plug->num_altmodes < 0)
+ return 0;
+ }
+
+ return attr->mode;
+}
+
+static const struct attribute_group typec_plug_group = {
+ .is_visible = typec_plug_attr_is_visible,
+ .attrs = typec_plug_attrs
+};
+
+static const struct attribute_group *typec_plug_groups[] = {
+ &typec_plug_group,
+ NULL
+};
+
static const struct device_type typec_plug_dev_type = {
.name = "typec_plug",
+ .groups = typec_plug_groups,
.release = typec_plug_release,
};
/**
+ * typec_plug_set_num_altmodes - Set the number of available plug altmodes
+ * @plug: The plug to be updated.
+ * @num_altmodes: The number of altmodes we want to specify as available.
+ *
+ * This routine is used to report the number of alternate modes supported by the
+ * plug. This value is *not* enforced in alternate mode registration routines.
+ *
+ * @plug.num_altmodes is set to -1 on plug registration, denoting that
+ * a valid value has not been set for it yet.
+ *
+ * Returns 0 on success or negative error number on failure.
+ */
+int typec_plug_set_num_altmodes(struct typec_plug *plug, int num_altmodes)
+{
+ int ret;
+
+ if (num_altmodes < 0)
+ return -EINVAL;
+
+ plug->num_altmodes = num_altmodes;
+ ret = sysfs_update_group(&plug->dev.kobj, &typec_plug_group);
+ if (ret < 0)
+ return ret;
+
+ sysfs_notify(&plug->dev.kobj, NULL, "number_of_alternate_modes");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_plug_set_num_altmodes);
+
+/**
* typec_plug_register_altmode - Register USB Type-C Cable Plug Alternate Mode
* @plug: USB Type-C Cable Plug that supports the alternate mode
* @desc: Description of the alternate mode
@@ -712,6 +973,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable,
sprintf(name, "plug%d", desc->index);
ida_init(&plug->mode_ids);
+ plug->num_altmodes = -1;
plug->index = desc->index;
plug->dev.class = typec_class;
plug->dev.parent = &cable->dev;
@@ -744,15 +1006,6 @@ EXPORT_SYMBOL_GPL(typec_unregister_plug);
/* Type-C Cables */
-static ssize_t
-type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct typec_cable *cable = to_typec_cable(dev);
-
- return sprintf(buf, "%s\n", cable->active ? "active" : "passive");
-}
-static DEVICE_ATTR_RO(type);
-
static const char * const typec_plug_types[] = {
[USB_PLUG_NONE] = "unknown",
[USB_PLUG_TYPE_A] = "type-a",
@@ -1309,7 +1562,7 @@ static umode_t typec_attr_is_visible(struct kobject *kobj,
return attr->mode;
}
-static struct attribute_group typec_group = {
+static const struct attribute_group typec_group = {
.is_visible = typec_attr_is_visible,
.attrs = typec_attrs,
};
@@ -1352,6 +1605,11 @@ const struct device_type typec_port_dev_type = {
/* --------------------------------------- */
/* Driver callbacks to report role updates */
+static int partner_match(struct device *dev, void *data)
+{
+ return is_typec_partner(dev);
+}
+
/**
* typec_set_data_role - Report data role change
* @port: The USB Type-C Port where the role was changed
@@ -1361,12 +1619,23 @@ const struct device_type typec_port_dev_type = {
*/
void typec_set_data_role(struct typec_port *port, enum typec_data_role role)
{
+ struct device *partner_dev;
+
if (port->data_role == role)
return;
port->data_role = role;
sysfs_notify(&port->dev.kobj, NULL, "data_role");
kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+
+ partner_dev = device_find_child(&port->dev, NULL, partner_match);
+ if (!partner_dev)
+ return;
+
+ if (to_typec_partner(partner_dev)->identity)
+ typec_product_type_notify(partner_dev);
+
+ put_device(partner_dev);
}
EXPORT_SYMBOL_GPL(typec_set_data_role);
@@ -1407,11 +1676,6 @@ void typec_set_vconn_role(struct typec_port *port, enum typec_role role)
}
EXPORT_SYMBOL_GPL(typec_set_vconn_role);
-static int partner_match(struct device *dev, void *data)
-{
- return is_typec_partner(dev);
-}
-
/**
* typec_set_pwr_opmode - Report changed power operation mode
* @port: The USB Type-C Port where the mode was changed
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index b069a5122aaa..cf720e944aaa 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -71,7 +71,7 @@ struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode)
EXPORT_SYMBOL_GPL(fwnode_typec_switch_get);
/**
- * typec_put_switch - Release USB Type-C orientation switch
+ * typec_switch_put - Release USB Type-C orientation switch
* @sw: USB Type-C orientation switch
*
* Decrement reference count for @sw.
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index d7f63b74c6b1..cf37a59ce130 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -176,6 +176,7 @@ static int hsl_orientation(struct pmc_usb_port *port)
static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len)
{
u8 response[4];
+ u8 status_res;
int ret;
/*
@@ -189,9 +190,13 @@ static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len)
if (ret)
return ret;
- if (response[2] & PMC_USB_RESP_STATUS_FAILURE) {
- if (response[2] & PMC_USB_RESP_STATUS_FATAL)
+ status_res = (msg[0] & 0xf) < PMC_USB_SAFE_MODE ?
+ response[2] : response[1];
+
+ if (status_res & PMC_USB_RESP_STATUS_FAILURE) {
+ if (status_res & PMC_USB_RESP_STATUS_FATAL)
return -EIO;
+
return -EBUSY;
}
@@ -256,6 +261,7 @@ static int
pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
{
struct typec_thunderbolt_data *data = state->data;
+ u8 cable_rounded = TBT_CABLE_ROUNDED_SUPPORT(data->cable_mode);
u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode);
struct altmode_req req = { };
@@ -284,6 +290,8 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed);
+ req.mode_data |= PMC_USB_ALTMODE_TBT_GEN(cable_rounded);
+
return pmc_usb_command(port, (void *)&req, sizeof(req));
}
@@ -319,6 +327,11 @@ pmc_usb_mux_usb4(struct pmc_usb_port *port, struct typec_mux_state *state)
fallthrough;
default:
req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE;
+
+ /* Configure data rate to rounded in the case of Active TBT3
+ * and USB4 cables.
+ */
+ req.mode_data |= PMC_USB_ALTMODE_TBT_GEN(1);
break;
}
diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c
index ce0bd7b3ad88..d21750bbbb44 100644
--- a/drivers/usb/typec/stusb160x.c
+++ b/drivers/usb/typec/stusb160x.c
@@ -544,11 +544,10 @@ static int stusb160x_get_fw_caps(struct stusb160x *chip,
*/
ret = fwnode_property_read_string(fwnode, "power-role", &cap_str);
if (!ret) {
- chip->port_type = typec_find_port_power_role(cap_str);
- if (chip->port_type < 0) {
- ret = chip->port_type;
+ ret = typec_find_port_power_role(cap_str);
+ if (ret < 0)
return ret;
- }
+ chip->port_type = ret;
}
chip->capability.type = chip->port_type;
@@ -563,17 +562,15 @@ static int stusb160x_get_fw_caps(struct stusb160x *chip,
* Supported power operation mode can be configured through device tree
* else it is read from chip registers in stusb160x_get_caps.
*/
- ret = fwnode_property_read_string(fwnode, "power-opmode", &cap_str);
+ ret = fwnode_property_read_string(fwnode, "typec-power-opmode", &cap_str);
if (!ret) {
- chip->pwr_opmode = typec_find_pwr_opmode(cap_str);
+ ret = typec_find_pwr_opmode(cap_str);
/* Power delivery not yet supported */
- if (chip->pwr_opmode < 0 ||
- chip->pwr_opmode == TYPEC_PWR_MODE_PD) {
- ret = chip->pwr_opmode < 0 ? chip->pwr_opmode : -EINVAL;
- dev_err(chip->dev, "bad power operation mode: %d\n",
- chip->pwr_opmode);
- return ret;
+ if (ret < 0 || ret == TYPEC_PWR_MODE_PD) {
+ dev_err(chip->dev, "bad power operation mode: %d\n", ret);
+ return -EINVAL;
}
+ chip->pwr_opmode = ret;
}
return 0;
@@ -632,6 +629,7 @@ static const struct of_device_id stusb160x_of_match[] = {
{ .compatible = "st,stusb1600", .data = &stusb1600_regmap_config},
{},
};
+MODULE_DEVICE_TABLE(of, stusb160x_of_match);
static int stusb160x_probe(struct i2c_client *client)
{
@@ -729,8 +727,8 @@ static int stusb160x_probe(struct i2c_client *client)
}
chip->port = typec_register_port(chip->dev, &chip->capability);
- if (!chip->port) {
- ret = -ENODEV;
+ if (IS_ERR(chip->port)) {
+ ret = PTR_ERR(chip->port);
goto all_reg_disable;
}
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 99562cc65ca6..ebc46b9f776c 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -343,12 +343,11 @@ static int fusb302_sw_reset(struct fusb302_chip *chip)
return ret;
}
-static int fusb302_enable_tx_auto_retries(struct fusb302_chip *chip)
+static int fusb302_enable_tx_auto_retries(struct fusb302_chip *chip, u8 retry_count)
{
int ret = 0;
- ret = fusb302_i2c_set_bits(chip, FUSB_REG_CONTROL3,
- FUSB_REG_CONTROL3_N_RETRIES_3 |
+ ret = fusb302_i2c_set_bits(chip, FUSB_REG_CONTROL3, retry_count |
FUSB_REG_CONTROL3_AUTO_RETRY);
return ret;
@@ -399,7 +398,7 @@ static int tcpm_init(struct tcpc_dev *dev)
ret = fusb302_sw_reset(chip);
if (ret < 0)
return ret;
- ret = fusb302_enable_tx_auto_retries(chip);
+ ret = fusb302_enable_tx_auto_retries(chip, FUSB_REG_CONTROL3_N_RETRIES_3);
if (ret < 0)
return ret;
ret = fusb302_init_interrupt(chip);
@@ -1017,7 +1016,7 @@ static const char * const transmit_type_name[] = {
};
static int tcpm_pd_transmit(struct tcpc_dev *dev, enum tcpm_transmit_type type,
- const struct pd_message *msg)
+ const struct pd_message *msg, unsigned int negotiated_rev)
{
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
tcpc_dev);
@@ -1026,6 +1025,13 @@ static int tcpm_pd_transmit(struct tcpc_dev *dev, enum tcpm_transmit_type type,
mutex_lock(&chip->lock);
switch (type) {
case TCPC_TX_SOP:
+ /* nRetryCount 3 in P2.0 spec, whereas 2 in PD3.0 spec */
+ ret = fusb302_enable_tx_auto_retries(chip, negotiated_rev > PD_REV20 ?
+ FUSB_REG_CONTROL3_N_RETRIES_2 :
+ FUSB_REG_CONTROL3_N_RETRIES_3);
+ if (ret < 0)
+ fusb302_log(chip, "Cannot update retry count ret=%d", ret);
+
ret = fusb302_pd_send_message(chip, msg);
if (ret < 0)
fusb302_log(chip,
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index f9f0af64da5f..f676abab044b 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -18,7 +18,11 @@
#include "tcpci.h"
-#define PD_RETRY_COUNT 3
+#define PD_RETRY_COUNT_DEFAULT 3
+#define PD_RETRY_COUNT_3_0_OR_HIGHER 2
+#define AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV 3500
+#define AUTO_DISCHARGE_PD_HEADROOM_MV 850
+#define AUTO_DISCHARGE_PPS_HEADROOM_MV 1250
struct tcpci {
struct device *dev;
@@ -268,6 +272,58 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
}
+static int tcpci_enable_auto_vbus_discharge(struct tcpc_dev *dev, bool enable)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(dev);
+ int ret;
+
+ ret = regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL, TCPC_POWER_CTRL_AUTO_DISCHARGE,
+ enable ? TCPC_POWER_CTRL_AUTO_DISCHARGE : 0);
+ return ret;
+}
+
+static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum typec_pwr_opmode mode,
+ bool pps_active, u32 requested_vbus_voltage_mv)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(dev);
+ unsigned int pwr_ctrl, threshold = 0;
+ int ret;
+
+ /*
+ * Indicates that vbus is going to go away due PR_SWAP, hard reset etc.
+ * Do not discharge vbus here.
+ */
+ if (requested_vbus_voltage_mv == 0)
+ goto write_thresh;
+
+ ret = regmap_read(tcpci->regmap, TCPC_POWER_CTRL, &pwr_ctrl);
+ if (ret < 0)
+ return ret;
+
+ if (pwr_ctrl & TCPC_FAST_ROLE_SWAP_EN) {
+ /* To prevent disconnect when the source is fast role swap is capable. */
+ threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
+ } else if (mode == TYPEC_PWR_MODE_PD) {
+ if (pps_active)
+ threshold = (95 * requested_vbus_voltage_mv / 100) -
+ AUTO_DISCHARGE_PD_HEADROOM_MV;
+ else
+ threshold = (95 * requested_vbus_voltage_mv / 100) -
+ AUTO_DISCHARGE_PPS_HEADROOM_MV;
+ } else {
+ /* 3.5V for non-pd sink */
+ threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
+ }
+
+ threshold = threshold / TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV;
+
+ if (threshold > TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX)
+ return -EINVAL;
+
+write_thresh:
+ return tcpci_write16(tcpci, TCPC_VBUS_SINK_DISCONNECT_THRESH, threshold);
+}
+
static int tcpci_enable_frs(struct tcpc_dev *dev, bool enable)
{
struct tcpci *tcpci = tcpc_to_tcpci(dev);
@@ -284,6 +340,14 @@ static int tcpci_enable_frs(struct tcpc_dev *dev, bool enable)
return ret;
}
+static void tcpci_frs_sourcing_vbus(struct tcpc_dev *dev)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(dev);
+
+ if (tcpci->data->frs_sourcing_vbus)
+ tcpci->data->frs_sourcing_vbus(tcpci, tcpci->data);
+}
+
static int tcpci_set_bist_data(struct tcpc_dev *tcpc, bool enable)
{
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -339,6 +403,19 @@ static int tcpci_get_vbus(struct tcpc_dev *tcpc)
return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
}
+static bool tcpci_is_vbus_vsafe0v(struct tcpc_dev *tcpc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, &reg);
+ if (ret < 0)
+ return false;
+
+ return !!(reg & TCPC_EXTENDED_STATUS_VSAFE0V);
+}
+
static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
{
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -384,9 +461,8 @@ static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
return 0;
}
-static int tcpci_pd_transmit(struct tcpc_dev *tcpc,
- enum tcpm_transmit_type type,
- const struct pd_message *msg)
+static int tcpci_pd_transmit(struct tcpc_dev *tcpc, enum tcpm_transmit_type type,
+ const struct pd_message *msg, unsigned int negotiated_rev)
{
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
u16 header = msg ? le16_to_cpu(msg->header) : 0;
@@ -434,7 +510,9 @@ static int tcpci_pd_transmit(struct tcpc_dev *tcpc,
}
}
- reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) | (type << TCPC_TRANSMIT_TYPE_SHIFT);
+ /* nRetryCount is 3 in PD2.0 spec where 2 in PD3.0 spec */
+ reg = ((negotiated_rev > PD_REV20 ? PD_RETRY_COUNT_3_0_OR_HIGHER : PD_RETRY_COUNT_DEFAULT)
+ << TCPC_TRANSMIT_RETRY_SHIFT) | (type << TCPC_TRANSMIT_TYPE_SHIFT);
ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg);
if (ret < 0)
return ret;
@@ -491,12 +569,22 @@ static int tcpci_init(struct tcpc_dev *tcpc)
TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
if (tcpci->controls_vbus)
reg |= TCPC_ALERT_POWER_STATUS;
+ /* Enable VSAFE0V status interrupt when detecting VSAFE0V is supported */
+ if (tcpci->data->vbus_vsafe0v) {
+ reg |= TCPC_ALERT_EXTENDED_STATUS;
+ ret = regmap_write(tcpci->regmap, TCPC_EXTENDED_STATUS_MASK,
+ TCPC_EXTENDED_STATUS_VSAFE0V);
+ if (ret < 0)
+ return ret;
+ }
return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
}
irqreturn_t tcpci_irq(struct tcpci *tcpci)
{
u16 status;
+ int ret;
+ unsigned int raw;
tcpci_read16(tcpci, TCPC_ALERT, &status);
@@ -512,15 +600,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
tcpm_cc_change(tcpci->port);
if (status & TCPC_ALERT_POWER_STATUS) {
- unsigned int reg;
-
- regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, &reg);
-
+ regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, &raw);
/*
* If power status mask has been reset, then the TCPC
* has reset.
*/
- if (reg == 0xff)
+ if (raw == 0xff)
tcpm_tcpc_reset(tcpci->port);
else
tcpm_vbus_change(tcpci->port);
@@ -559,6 +644,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
tcpm_pd_receive(tcpci->port, &msg);
}
+ if (status & TCPC_ALERT_EXTENDED_STATUS) {
+ ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, &raw);
+ if (!ret && (raw & TCPC_EXTENDED_STATUS_VSAFE0V))
+ tcpm_vbus_change(tcpci->port);
+ }
+
if (status & TCPC_ALERT_RX_HARD_RST)
tcpm_pd_hard_reset(tcpci->port);
@@ -628,6 +719,18 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
tcpci->tcpc.pd_transmit = tcpci_pd_transmit;
tcpci->tcpc.set_bist_data = tcpci_set_bist_data;
tcpci->tcpc.enable_frs = tcpci_enable_frs;
+ tcpci->tcpc.frs_sourcing_vbus = tcpci_frs_sourcing_vbus;
+
+ if (tcpci->data->auto_discharge_disconnect) {
+ tcpci->tcpc.enable_auto_vbus_discharge = tcpci_enable_auto_vbus_discharge;
+ tcpci->tcpc.set_auto_vbus_discharge_threshold =
+ tcpci_set_auto_vbus_discharge_threshold;
+ regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL, TCPC_POWER_CTRL_BLEED_DISCHARGE,
+ TCPC_POWER_CTRL_BLEED_DISCHARGE);
+ }
+
+ if (tcpci->data->vbus_vsafe0v)
+ tcpci->tcpc.is_vbus_vsafe0v = tcpci_is_vbus_vsafe0v;
err = tcpci_parse_config(tcpci);
if (err < 0)
diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h
index 5ef07a56d67a..c3c7d07d9b4e 100644
--- a/drivers/usb/typec/tcpm/tcpci.h
+++ b/drivers/usb/typec/tcpm/tcpci.h
@@ -8,6 +8,8 @@
#ifndef __LINUX_USB_TCPCI_H
#define __LINUX_USB_TCPCI_H
+#include <linux/usb/typec.h>
+
#define TCPC_VENDOR_ID 0x0
#define TCPC_PRODUCT_ID 0x2
#define TCPC_BCD_DEV 0x4
@@ -47,6 +49,9 @@
#define TCPC_TCPC_CTRL_ORIENTATION BIT(0)
#define TCPC_TCPC_CTRL_BIST_TM BIT(1)
+#define TCPC_EXTENDED_STATUS 0x20
+#define TCPC_EXTENDED_STATUS_VSAFE0V BIT(0)
+
#define TCPC_ROLE_CTRL 0x1a
#define TCPC_ROLE_CTRL_DRP BIT(6)
#define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4
@@ -67,6 +72,8 @@
#define TCPC_POWER_CTRL 0x1c
#define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
+#define TCPC_POWER_CTRL_BLEED_DISCHARGE BIT(3)
+#define TCPC_POWER_CTRL_AUTO_DISCHARGE BIT(4)
#define TCPC_FAST_ROLE_SWAP_EN BIT(7)
#define TCPC_CC_STATUS 0x1d
@@ -133,6 +140,8 @@
#define TCPC_VBUS_VOLTAGE 0x70
#define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72
+#define TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV 25
+#define TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX 0x3ff
#define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74
#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76
#define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78
@@ -140,20 +149,32 @@
/* I2C_WRITE_BYTE_COUNT + 1 when TX_BUF_BYTE_x is only accessible I2C_WRITE_BYTE_COUNT */
#define TCPC_TRANSMIT_BUFFER_MAX_LEN 31
+struct tcpci;
+
/*
- * @TX_BUF_BYTE_x_hidden
+ * @TX_BUF_BYTE_x_hidden:
* optional; Set when TX_BUF_BYTE_x can only be accessed through I2C_WRITE_BYTE_COUNT.
+ * @frs_sourcing_vbus:
+ * Optional; Callback to perform chip specific operations when FRS
+ * is sourcing vbus.
+ * @auto_discharge_disconnect:
+ * Optional; Enables TCPC to autonously discharge vbus on disconnect.
+ * @vbus_vsafe0v:
+ * optional; Set when TCPC can detect whether vbus is at VSAFE0V.
*/
-struct tcpci;
struct tcpci_data {
struct regmap *regmap;
unsigned char TX_BUF_BYTE_x_hidden:1;
+ unsigned char auto_discharge_disconnect:1;
+ unsigned char vbus_vsafe0v:1;
+
int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
bool enable);
int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data,
enum typec_cc_status cc);
int (*set_vbus)(struct tcpci *tcpci, struct tcpci_data *data, bool source, bool sink);
+ void (*frs_sourcing_vbus)(struct tcpci *tcpci, struct tcpci_data *data);
};
struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c
index 723d7dd38f75..319266329b42 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim.c
@@ -112,11 +112,18 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
return;
}
+ /* Enable VSAFE0V detection */
+ ret = max_tcpci_write8(chip, TCPC_EXTENDED_STATUS_MASK, TCPC_EXTENDED_STATUS_VSAFE0V);
+ if (ret < 0) {
+ dev_err(chip->dev, "Unable to unmask TCPC_EXTENDED_STATUS_VSAFE0V ret:%d\n", ret);
+ return;
+ }
+
alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
/* Enable Extended alert for detecting Fast Role Swap Signal */
- TCPC_ALERT_EXTND;
+ TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
if (ret < 0) {
@@ -238,23 +245,22 @@ static void process_power_status(struct max_tcpci_chip *chip)
if (ret < 0)
return;
- if (pwr_status == 0xff) {
+ if (pwr_status == 0xff)
max_tcpci_init_regs(chip);
- } else if (pwr_status & TCPC_POWER_STATUS_SOURCING_VBUS) {
+ else if (pwr_status & TCPC_POWER_STATUS_SOURCING_VBUS)
tcpm_sourcing_vbus(chip->port);
- /*
- * Alawys re-enable boost here.
- * In normal case, when say an headset is attached, TCPM would
- * have instructed to TCPC to enable boost, so the call is a
- * no-op.
- * But for Fast Role Swap case, Boost turns on autonomously without
- * AP intervention, but, needs AP to enable source mode explicitly
- * for AP to regain control.
- */
- max_tcpci_set_vbus(chip->tcpci, &chip->data, true, false);
- } else {
+ else
tcpm_vbus_change(chip->port);
- }
+}
+
+static void max_tcpci_frs_sourcing_vbus(struct tcpci *tcpci, struct tcpci_data *tdata)
+{
+ /*
+ * For Fast Role Swap case, Boost turns on autonomously without
+ * AP intervention, but, needs AP to enable source mode explicitly
+ * for AP to regain control.
+ */
+ max_tcpci_set_vbus(tcpci, tdata, true, false);
}
static void process_tx(struct max_tcpci_chip *chip, u16 status)
@@ -316,6 +322,12 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
}
}
+ if (status & TCPC_ALERT_EXTENDED_STATUS) {
+ ret = max_tcpci_read8(chip, TCPC_EXTENDED_STATUS, (u8 *)&reg_status);
+ if (ret >= 0 && (reg_status & TCPC_EXTENDED_STATUS_VSAFE0V))
+ tcpm_vbus_change(chip->port);
+ }
+
if (status & TCPC_ALERT_RX_STATUS)
process_rx(chip, status);
@@ -344,7 +356,7 @@ static irqreturn_t max_tcpci_irq(int irq, void *dev_id)
{
struct max_tcpci_chip *chip = dev_id;
u16 status;
- irqreturn_t irq_return;
+ irqreturn_t irq_return = IRQ_HANDLED;
int ret;
if (!chip->port)
@@ -441,10 +453,13 @@ static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id
chip->data.start_drp_toggling = max_tcpci_start_toggling;
chip->data.TX_BUF_BYTE_x_hidden = true;
chip->data.init = tcpci_init;
+ chip->data.frs_sourcing_vbus = max_tcpci_frs_sourcing_vbus;
+ chip->data.auto_discharge_disconnect = true;
+ chip->data.vbus_vsafe0v = true;
max_tcpci_init_regs(chip);
chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
- if (IS_ERR_OR_NULL(chip->tcpci)) {
+ if (IS_ERR(chip->tcpci)) {
dev_err(&client->dev, "TCPCI port registration failed");
ret = PTR_ERR(chip->tcpci);
return PTR_ERR(chip->tcpci);
@@ -481,7 +496,7 @@ MODULE_DEVICE_TABLE(i2c, max_tcpci_id);
#ifdef CONFIG_OF
static const struct of_device_id max_tcpci_of_match[] = {
- { .compatible = "maxim,tcpc", },
+ { .compatible = "maxim,max33359", },
{},
};
MODULE_DEVICE_TABLE(of, max_tcpci_of_match);
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 55535c4f66bf..22a85b396f69 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -258,7 +258,19 @@ struct tcpm_port {
bool attached;
bool connected;
enum typec_port_type port_type;
+
+ /*
+ * Set to true when vbus is greater than VSAFE5V min.
+ * Set to false when vbus falls below vSinkDisconnect max threshold.
+ */
bool vbus_present;
+
+ /*
+ * Set to true when vbus is less than VSAFE0V max.
+ * Set to false when vbus is greater than VSAFE0V max.
+ */
+ bool vbus_vsafe0v;
+
bool vbus_never_low;
bool vbus_source;
bool vbus_charge;
@@ -363,8 +375,8 @@ struct tcpm_port {
/* port belongs to a self powered device */
bool self_powered;
- /* FRS */
- enum frs_typec_current frs_current;
+ /* Sink FRS */
+ enum frs_typec_current new_source_frs_current;
/* Sink caps have been queried */
bool sink_cap_done;
@@ -667,7 +679,7 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
tcpm_log(port, "PD TX, type: %#x", type);
reinit_completion(&port->tx_complete);
- ret = port->tcpc->pd_transmit(port->tcpc, type, msg);
+ ret = port->tcpc->pd_transmit(port->tcpc, type, msg, port->negotiated_rev);
if (ret < 0)
return ret;
@@ -1706,6 +1718,24 @@ static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload,
}
}
+static int tcpm_set_auto_vbus_discharge_threshold(struct tcpm_port *port,
+ enum typec_pwr_opmode mode, bool pps_active,
+ u32 requested_vbus_voltage)
+{
+ int ret;
+
+ if (!port->tcpc->set_auto_vbus_discharge_threshold)
+ return 0;
+
+ ret = port->tcpc->set_auto_vbus_discharge_threshold(port->tcpc, mode, pps_active,
+ requested_vbus_voltage);
+ tcpm_log_force(port,
+ "set_auto_vbus_discharge_threshold mode:%d pps_active:%c vbus:%u ret:%d",
+ mode, pps_active ? 'y' : 'n', requested_vbus_voltage, ret);
+
+ return ret;
+}
+
static void tcpm_pd_data_request(struct tcpm_port *port,
const struct pd_message *msg)
{
@@ -1713,7 +1743,7 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
unsigned int cnt = pd_header_cnt_le(msg->header);
unsigned int rev = pd_header_rev_le(msg->header);
unsigned int i;
- enum frs_typec_current frs_current;
+ enum frs_typec_current partner_frs_current;
bool frs_enable;
int ret;
@@ -1786,12 +1816,13 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
for (i = 0; i < cnt; i++)
port->sink_caps[i] = le32_to_cpu(msg->payload[i]);
- frs_current = (port->sink_caps[0] & PDO_FIXED_FRS_CURR_MASK) >>
+ partner_frs_current = (port->sink_caps[0] & PDO_FIXED_FRS_CURR_MASK) >>
PDO_FIXED_FRS_CURR_SHIFT;
- frs_enable = frs_current && (frs_current <= port->frs_current);
+ frs_enable = partner_frs_current && (partner_frs_current <=
+ port->new_source_frs_current);
tcpm_log(port,
"Port partner FRS capable partner_frs_current:%u port_frs_current:%u enable:%c",
- frs_current, port->frs_current, frs_enable ? 'y' : 'n');
+ partner_frs_current, port->new_source_frs_current, frs_enable ? 'y' : 'n');
if (frs_enable) {
ret = port->tcpc->enable_frs(port->tcpc, true);
tcpm_log(port, "Enable FRS %s, ret:%d\n", ret ? "fail" : "success", ret);
@@ -1875,6 +1906,10 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
port->current_limit,
port->supply_voltage);
port->explicit_contract = true;
+ tcpm_set_auto_vbus_discharge_threshold(port,
+ TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
tcpm_set_state(port, SNK_READY, 0);
} else {
/*
@@ -2193,6 +2228,7 @@ static int tcpm_pd_send_control(struct tcpm_port *port,
static bool tcpm_send_queued_message(struct tcpm_port *port)
{
enum pd_msg_request queued_message;
+ int ret;
do {
queued_message = port->queued_message;
@@ -2212,7 +2248,16 @@ static bool tcpm_send_queued_message(struct tcpm_port *port)
tcpm_pd_send_sink_caps(port);
break;
case PD_MSG_DATA_SOURCE_CAP:
- tcpm_pd_send_source_caps(port);
+ ret = tcpm_pd_send_source_caps(port);
+ if (ret < 0) {
+ tcpm_log(port,
+ "Unable to send src caps, ret=%d",
+ ret);
+ tcpm_set_state(port, SOFT_RESET_SEND, 0);
+ } else if (port->pwr_role == TYPEC_SOURCE) {
+ tcpm_set_state(port, HARD_RESET_SEND,
+ PD_T_SENDER_RESPONSE);
+ }
break;
default:
break;
@@ -2789,8 +2834,12 @@ static int tcpm_src_attach(struct tcpm_port *port)
if (ret < 0)
return ret;
- ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
- tcpm_data_role_for_source(port));
+ if (port->tcpc->enable_auto_vbus_discharge) {
+ ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
+ tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
+ }
+
+ ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port));
if (ret < 0)
return ret;
@@ -2857,6 +2906,12 @@ static void tcpm_unregister_altmodes(struct tcpm_port *port)
static void tcpm_reset_port(struct tcpm_port *port)
{
+ int ret;
+
+ if (port->tcpc->enable_auto_vbus_discharge) {
+ ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false);
+ tcpm_log_force(port, "Disable vbus discharge ret:%d", ret);
+ }
tcpm_unregister_altmodes(port);
tcpm_typec_disconnect(port);
port->attached = false;
@@ -2890,6 +2945,9 @@ static void tcpm_reset_port(struct tcpm_port *port)
static void tcpm_detach(struct tcpm_port *port)
{
+ if (tcpm_port_is_disconnected(port))
+ port->hard_reset_count = 0;
+
if (!port->attached)
return;
@@ -2898,9 +2956,6 @@ static void tcpm_detach(struct tcpm_port *port)
port->tcpc->set_bist_data(port->tcpc, false);
}
- if (tcpm_port_is_disconnected(port))
- port->hard_reset_count = 0;
-
tcpm_reset_port(port);
}
@@ -2921,8 +2976,13 @@ static int tcpm_snk_attach(struct tcpm_port *port)
if (ret < 0)
return ret;
- ret = tcpm_set_roles(port, true, TYPEC_SINK,
- tcpm_data_role_for_sink(port));
+ if (port->tcpc->enable_auto_vbus_discharge) {
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
+ ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
+ tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
+ }
+
+ ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port));
if (ret < 0)
return ret;
@@ -2997,10 +3057,9 @@ static inline enum tcpm_state unattached_state(struct tcpm_port *port)
static void tcpm_check_send_discover(struct tcpm_port *port)
{
if (port->data_role == TYPEC_HOST && port->send_discover &&
- port->pd_capable) {
+ port->pd_capable)
tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0);
- port->send_discover = false;
- }
+ port->send_discover = false;
}
static void tcpm_swap_complete(struct tcpm_port *port, int result)
@@ -3056,7 +3115,7 @@ static void run_state_machine(struct tcpm_port *port)
else if (tcpm_port_is_audio(port))
tcpm_set_state(port, AUDIO_ACC_ATTACHED,
PD_T_CC_DEBOUNCE);
- else if (tcpm_port_is_source(port))
+ else if (tcpm_port_is_source(port) && port->vbus_vsafe0v)
tcpm_set_state(port,
tcpm_try_snk(port) ? SNK_TRY
: SRC_ATTACHED,
@@ -3086,15 +3145,13 @@ static void run_state_machine(struct tcpm_port *port)
break;
case SNK_TRY_WAIT_DEBOUNCE:
tcpm_set_state(port, SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS,
- PD_T_PD_DEBOUNCE);
+ PD_T_TRY_CC_DEBOUNCE);
break;
case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS:
- if (port->vbus_present && tcpm_port_is_sink(port)) {
+ if (port->vbus_present && tcpm_port_is_sink(port))
tcpm_set_state(port, SNK_ATTACHED, 0);
- } else {
- tcpm_set_state(port, SRC_TRYWAIT, 0);
+ else
port->max_wait = 0;
- }
break;
case SRC_TRYWAIT:
tcpm_set_cc(port, tcpm_rp_cc(port));
@@ -3506,6 +3563,8 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, SRC_UNATTACHED, PD_T_PS_SOURCE_ON);
break;
case SNK_HARD_RESET_SINK_OFF:
+ /* Do not discharge/disconnect during hard reseet */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
memset(&port->pps_data, 0, sizeof(port->pps_data));
tcpm_set_vconn(port, false);
if (port->pd_capable)
@@ -3548,6 +3607,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_charge(port, true);
}
tcpm_set_attached_state(port, true);
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
tcpm_set_state(port, SNK_STARTUP, 0);
break;
@@ -3649,6 +3709,10 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, PR_SWAP_SNK_SRC_SINK_OFF, 0);
break;
case PR_SWAP_SRC_SNK_TRANSITION_OFF:
+ /*
+ * Prevent vbus discharge circuit from turning on during PR_SWAP
+ * as this is not a disconnect.
+ */
tcpm_set_vbus(port, false);
port->explicit_contract = false;
/* allow time for Vbus discharge, must be < tSrcSwapStdby */
@@ -3674,12 +3738,20 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ERROR_RECOVERY, 0);
break;
}
- tcpm_set_state_cond(port, SNK_UNATTACHED, PD_T_PS_SOURCE_ON);
+ tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_ON_PRS);
break;
case PR_SWAP_SRC_SNK_SINK_ON:
+ /* Set the vbus disconnect threshold for implicit contract */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
tcpm_set_state(port, SNK_STARTUP, 0);
break;
case PR_SWAP_SNK_SRC_SINK_OFF:
+ /*
+ * Prevent vbus discharge circuit from turning on during PR_SWAP
+ * as this is not a disconnect.
+ */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB,
+ port->pps_data.active, 0);
tcpm_set_charge(port, false);
tcpm_set_state(port, hard_reset_state(port),
PD_T_PS_SOURCE_OFF);
@@ -4000,6 +4072,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
if (!tcpm_port_is_sink(port))
tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, 0);
break;
+ case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS:
+ if (!tcpm_port_is_sink(port))
+ tcpm_set_state(port, SRC_TRYWAIT, PD_T_TRY_CC_DEBOUNCE);
+ else
+ tcpm_set_state(port, SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS, 0);
+ break;
case SNK_TRYWAIT:
/* Do nothing, waiting for tCCDebounce */
break;
@@ -4040,6 +4118,12 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
{
tcpm_log_force(port, "VBUS on");
port->vbus_present = true;
+ /*
+ * When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
+ * states that vbus is not at VSAFE0V, hence clear the vbus_vsafe0v flag here.
+ */
+ port->vbus_vsafe0v = false;
+
switch (port->state) {
case SNK_TRANSITION_SINK_VBUS:
port->explicit_contract = true;
@@ -4086,11 +4170,24 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
case SNK_TRYWAIT_DEBOUNCE:
/* Do nothing, waiting for Rp */
break;
+ case SNK_TRY_WAIT_DEBOUNCE_CHECK_VBUS:
+ if (port->vbus_present && tcpm_port_is_sink(port))
+ tcpm_set_state(port, SNK_ATTACHED, 0);
+ break;
case SRC_TRY_WAIT:
case SRC_TRY_DEBOUNCE:
/* Do nothing, waiting for sink detection */
break;
+ case FR_SWAP_SEND:
+ case FR_SWAP_SEND_TIMEOUT:
+ case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF:
+ case FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED:
+ if (port->tcpc->frs_sourcing_vbus)
+ port->tcpc->frs_sourcing_vbus(port->tcpc);
+ break;
case FR_SWAP_SNK_SRC_NEW_SINK_READY:
+ if (port->tcpc->frs_sourcing_vbus)
+ port->tcpc->frs_sourcing_vbus(port->tcpc);
tcpm_set_state(port, FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED, 0);
break;
@@ -4116,16 +4213,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
case SNK_HARD_RESET_SINK_OFF:
tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
break;
- case SRC_HARD_RESET_VBUS_OFF:
- /*
- * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
- * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
- */
- tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
- break;
case HARD_RESET_SEND:
break;
-
case SNK_TRY:
/* Do nothing, waiting for timeout */
break;
@@ -4156,6 +4245,14 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
/* Do nothing, expected */
break;
+ case PR_SWAP_SNK_SRC_SOURCE_ON:
+ /*
+ * Do nothing when vbus off notification is received.
+ * TCPM can wait for PD_T_NEWSRC in PR_SWAP_SNK_SRC_SOURCE_ON
+ * for the vbus source to ramp up.
+ */
+ break;
+
case PORT_RESET_WAIT_OFF:
tcpm_set_state(port, tcpm_default_state(port), 0);
break;
@@ -4188,6 +4285,28 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
}
}
+static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
+{
+ tcpm_log_force(port, "VBUS VSAFE0V");
+ port->vbus_vsafe0v = true;
+ switch (port->state) {
+ case SRC_HARD_RESET_VBUS_OFF:
+ /*
+ * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
+ * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
+ */
+ tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
+ break;
+ case SRC_ATTACH_WAIT:
+ if (tcpm_port_is_source(port))
+ tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ break;
+ default:
+ break;
+ }
+}
+
static void _tcpm_pd_hard_reset(struct tcpm_port *port)
{
tcpm_log_force(port, "Received hard reset");
@@ -4223,10 +4342,19 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
bool vbus;
vbus = port->tcpc->get_vbus(port->tcpc);
- if (vbus)
+ if (vbus) {
_tcpm_pd_vbus_on(port);
- else
+ } else {
_tcpm_pd_vbus_off(port);
+ /*
+ * When TCPC does not support detecting vsafe0v voltage level,
+ * treat vbus absent as vsafe0v. Else invoke is_vbus_vsafe0v
+ * to see if vbus has discharge to VSAFE0V.
+ */
+ if (!port->tcpc->is_vbus_vsafe0v ||
+ port->tcpc->is_vbus_vsafe0v(port->tcpc))
+ _tcpm_pd_vbus_vsafe0v(port);
+ }
}
if (events & TCPM_CC_EVENT) {
enum typec_cc_status cc1, cc2;
@@ -4676,6 +4804,24 @@ static void tcpm_init(struct tcpm_port *port)
if (port->vbus_present)
port->vbus_never_low = true;
+ /*
+ * 1. When vbus_present is true, voltage on VBUS is already at VSAFE5V.
+ * So implicitly vbus_vsafe0v = false.
+ *
+ * 2. When vbus_present is false and TCPC does NOT support querying
+ * vsafe0v status, then, it's best to assume vbus is at VSAFE0V i.e.
+ * vbus_vsafe0v is true.
+ *
+ * 3. When vbus_present is false and TCPC does support querying vsafe0v,
+ * then, query tcpc for vsafe0v status.
+ */
+ if (port->vbus_present)
+ port->vbus_vsafe0v = false;
+ else if (!port->tcpc->is_vbus_vsafe0v)
+ port->vbus_vsafe0v = true;
+ else
+ port->vbus_vsafe0v = port->tcpc->is_vbus_vsafe0v(port->tcpc);
+
tcpm_set_state(port, tcpm_default_state(port), 0);
if (port->tcpc->get_cc(port->tcpc, &cc1, &cc2) == 0)
@@ -4808,9 +4954,10 @@ sink:
/* FRS can only be supported byb DRP ports */
if (port->port_type == TYPEC_PORT_DRP) {
- ret = fwnode_property_read_u32(fwnode, "frs-typec-current", &frs_current);
+ ret = fwnode_property_read_u32(fwnode, "new-source-frs-typec-current",
+ &frs_current);
if (ret >= 0 && frs_current <= FRS_5V_3A)
- port->frs_current = frs_current;
+ port->new_source_frs_current = frs_current;
}
return 0;
@@ -5024,14 +5171,14 @@ static int devm_tcpm_psy_register(struct tcpm_port *port)
snprintf(psy_name, psy_name_len, "%s%s", tcpm_psy_name_prefix,
port_dev_name);
port->psy_desc.name = psy_name;
- port->psy_desc.type = POWER_SUPPLY_TYPE_USB,
+ port->psy_desc.type = POWER_SUPPLY_TYPE_USB;
port->psy_desc.usb_types = tcpm_psy_usb_types;
port->psy_desc.num_usb_types = ARRAY_SIZE(tcpm_psy_usb_types);
- port->psy_desc.properties = tcpm_psy_props,
- port->psy_desc.num_properties = ARRAY_SIZE(tcpm_psy_props),
- port->psy_desc.get_property = tcpm_psy_get_prop,
- port->psy_desc.set_property = tcpm_psy_set_prop,
- port->psy_desc.property_is_writeable = tcpm_psy_prop_writeable,
+ port->psy_desc.properties = tcpm_psy_props;
+ port->psy_desc.num_properties = ARRAY_SIZE(tcpm_psy_props);
+ port->psy_desc.get_property = tcpm_psy_get_prop;
+ port->psy_desc.set_property = tcpm_psy_set_prop;
+ port->psy_desc.property_is_writeable = tcpm_psy_prop_writeable;
port->usb_type = POWER_SUPPLY_USB_TYPE_C;
diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c
index 9b745f432c91..79ae63950050 100644
--- a/drivers/usb/typec/tcpm/wcove.c
+++ b/drivers/usb/typec/tcpm/wcove.c
@@ -356,7 +356,8 @@ static int wcove_set_pd_rx(struct tcpc_dev *tcpc, bool on)
static int wcove_pd_transmit(struct tcpc_dev *tcpc,
enum tcpm_transmit_type type,
- const struct pd_message *msg)
+ const struct pd_message *msg,
+ unsigned int negotiated_rev)
{
struct wcove_typec *wcove = tcpc_to_wcove(tcpc);
unsigned int info = 0;
diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c
index 3db33bb622c3..6e6ef6317523 100644
--- a/drivers/usb/typec/tps6598x.c
+++ b/drivers/usb/typec/tps6598x.c
@@ -9,6 +9,7 @@
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/module.h>
+#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/usb/typec.h>
@@ -55,6 +56,7 @@ enum {
};
/* TPS_REG_POWER_STATUS bits */
+#define TPS_POWER_STATUS_CONNECTION BIT(0)
#define TPS_POWER_STATUS_SOURCESINK BIT(1)
#define TPS_POWER_STATUS_PWROPMODE(p) (((p) & GENMASK(3, 2)) >> 2)
@@ -96,8 +98,25 @@ struct tps6598x {
struct typec_partner *partner;
struct usb_pd_identity partner_identity;
struct usb_role_switch *role_sw;
+ struct typec_capability typec_cap;
+
+ struct power_supply *psy;
+ struct power_supply_desc psy_desc;
+ enum power_supply_usb_type usb_type;
+};
+
+static enum power_supply_property tps6598x_psy_props[] = {
+ POWER_SUPPLY_PROP_USB_TYPE,
+ POWER_SUPPLY_PROP_ONLINE,
};
+static enum power_supply_usb_type tps6598x_psy_usb_types[] = {
+ POWER_SUPPLY_USB_TYPE_C,
+ POWER_SUPPLY_USB_TYPE_PD,
+};
+
+static const char *tps6598x_psy_name_prefix = "tps6598x-source-psy-";
+
/*
* Max data bytes for Data1, Data2, and other registers. See ch 1.3.2:
* https://www.ti.com/lit/ug/slvuan1a/slvuan1a.pdf
@@ -248,6 +267,8 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)
if (desc.identity)
typec_partner_set_identity(tps->partner);
+ power_supply_changed(tps->psy);
+
return 0;
}
@@ -260,6 +281,7 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status));
typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status));
tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false);
+ power_supply_changed(tps->psy);
}
static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd,
@@ -467,6 +489,83 @@ static const struct regmap_config tps6598x_regmap_config = {
.max_register = 0x7F,
};
+static int tps6598x_psy_get_online(struct tps6598x *tps,
+ union power_supply_propval *val)
+{
+ int ret;
+ u16 pwr_status;
+
+ ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &pwr_status);
+ if (ret < 0)
+ return ret;
+
+ if ((pwr_status & TPS_POWER_STATUS_CONNECTION) &&
+ (pwr_status & TPS_POWER_STATUS_SOURCESINK)) {
+ val->intval = 1;
+ } else {
+ val->intval = 0;
+ }
+ return 0;
+}
+
+static int tps6598x_psy_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct tps6598x *tps = power_supply_get_drvdata(psy);
+ u16 pwr_status;
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &pwr_status);
+ if (ret < 0)
+ return ret;
+ if (TPS_POWER_STATUS_PWROPMODE(pwr_status) == TYPEC_PWR_MODE_PD)
+ val->intval = POWER_SUPPLY_USB_TYPE_PD;
+ else
+ val->intval = POWER_SUPPLY_USB_TYPE_C;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = tps6598x_psy_get_online(tps, val);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int devm_tps6598_psy_register(struct tps6598x *tps)
+{
+ struct power_supply_config psy_cfg = {};
+ const char *port_dev_name = dev_name(tps->dev);
+ char *psy_name;
+
+ psy_cfg.drv_data = tps;
+ psy_cfg.fwnode = dev_fwnode(tps->dev);
+
+ psy_name = devm_kasprintf(tps->dev, GFP_KERNEL, "%s%s", tps6598x_psy_name_prefix,
+ port_dev_name);
+ if (!psy_name)
+ return -ENOMEM;
+
+ tps->psy_desc.name = psy_name;
+ tps->psy_desc.type = POWER_SUPPLY_TYPE_USB;
+ tps->psy_desc.usb_types = tps6598x_psy_usb_types;
+ tps->psy_desc.num_usb_types = ARRAY_SIZE(tps6598x_psy_usb_types);
+ tps->psy_desc.properties = tps6598x_psy_props;
+ tps->psy_desc.num_properties = ARRAY_SIZE(tps6598x_psy_props);
+ tps->psy_desc.get_property = tps6598x_psy_get_prop;
+
+ tps->usb_type = POWER_SUPPLY_USB_TYPE_C;
+
+ tps->psy = devm_power_supply_register(tps->dev, &tps->psy_desc,
+ &psy_cfg);
+ return PTR_ERR_OR_ZERO(tps->psy);
+}
+
static int tps6598x_probe(struct i2c_client *client)
{
struct typec_capability typec_cap = { };
@@ -560,6 +659,10 @@ static int tps6598x_probe(struct i2c_client *client)
goto err_role_put;
}
+ ret = devm_tps6598_psy_register(tps);
+ if (ret)
+ return ret;
+
tps->port = typec_register_port(&client->dev, &typec_cap);
if (IS_ERR(tps->port)) {
ret = PTR_ERR(tps->port);
diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c
index 26ed0b520749..56bf56517f75 100644
--- a/drivers/usb/typec/ucsi/psy.c
+++ b/drivers/usb/typec/ucsi/psy.c
@@ -220,11 +220,11 @@ int ucsi_register_port_psy(struct ucsi_connector *con)
return -ENOMEM;
con->psy_desc.name = psy_name;
- con->psy_desc.type = POWER_SUPPLY_TYPE_USB,
+ con->psy_desc.type = POWER_SUPPLY_TYPE_USB;
con->psy_desc.usb_types = ucsi_psy_usb_types;
con->psy_desc.num_usb_types = ARRAY_SIZE(ucsi_psy_usb_types);
- con->psy_desc.properties = ucsi_psy_props,
- con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props),
+ con->psy_desc.properties = ucsi_psy_props;
+ con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props);
con->psy_desc.get_property = ucsi_psy_get_prop;
con->psy = power_supply_register(dev, &con->psy_desc, &psy_cfg);
@@ -238,4 +238,13 @@ void ucsi_unregister_port_psy(struct ucsi_connector *con)
return;
power_supply_unregister(con->psy);
+ con->psy = NULL;
+}
+
+void ucsi_port_psy_changed(struct ucsi_connector *con)
+{
+ if (IS_ERR_OR_NULL(con->psy))
+ return;
+
+ power_supply_changed(con->psy);
}
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 758b988ac518..f02958927cbd 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -53,7 +53,7 @@ static int ucsi_acknowledge_connector_change(struct ucsi *ucsi)
ctrl = UCSI_ACK_CC_CI;
ctrl |= UCSI_ACK_CONNECTOR_CHANGE;
- return ucsi->ops->async_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl));
+ return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl));
}
static int ucsi_exec_command(struct ucsi *ucsi, u64 command);
@@ -625,26 +625,120 @@ static void ucsi_handle_connector_change(struct work_struct *work)
struct ucsi_connector *con = container_of(work, struct ucsi_connector,
work);
struct ucsi *ucsi = con->ucsi;
+ struct ucsi_connector_status pre_ack_status;
+ struct ucsi_connector_status post_ack_status;
enum typec_role role;
+ u16 inferred_changes;
+ u16 changed_flags;
u64 command;
int ret;
mutex_lock(&con->lock);
+ /*
+ * Some/many PPMs have an issue where all fields in the change bitfield
+ * are cleared when an ACK is send. This will causes any change
+ * between GET_CONNECTOR_STATUS and ACK to be lost.
+ *
+ * We work around this by re-fetching the connector status afterwards.
+ * We then infer any changes that we see have happened but that may not
+ * be represented in the change bitfield.
+ *
+ * Also, even though we don't need to know the currently supported alt
+ * modes, we run the GET_CAM_SUPPORTED command to ensure the PPM does
+ * not get stuck in case it assumes we do.
+ * Always do this, rather than relying on UCSI_CONSTAT_CAM_CHANGE to be
+ * set in the change bitfield.
+ *
+ * We end up with the following actions:
+ * 1. UCSI_GET_CONNECTOR_STATUS, store result, update unprocessed_changes
+ * 2. UCSI_GET_CAM_SUPPORTED, discard result
+ * 3. ACK connector change
+ * 4. UCSI_GET_CONNECTOR_STATUS, store result
+ * 5. Infere lost changes by comparing UCSI_GET_CONNECTOR_STATUS results
+ * 6. If PPM reported a new change, then restart in order to ACK
+ * 7. Process everything as usual.
+ *
+ * We may end up seeing a change twice, but we can only miss extremely
+ * short transitional changes.
+ */
+
+ /* 1. First UCSI_GET_CONNECTOR_STATUS */
+ command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+ ret = ucsi_send_command(ucsi, command, &pre_ack_status,
+ sizeof(pre_ack_status));
+ if (ret < 0) {
+ dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
+ __func__, ret);
+ goto out_unlock;
+ }
+ con->unprocessed_changes |= pre_ack_status.change;
+
+ /* 2. Run UCSI_GET_CAM_SUPPORTED and discard the result. */
+ command = UCSI_GET_CAM_SUPPORTED;
+ command |= UCSI_CONNECTOR_NUMBER(con->num);
+ ucsi_send_command(con->ucsi, command, NULL, 0);
+
+ /* 3. ACK connector change */
+ clear_bit(EVENT_PENDING, &ucsi->flags);
+ ret = ucsi_acknowledge_connector_change(ucsi);
+ if (ret) {
+ dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret);
+ goto out_unlock;
+ }
+
+ /* 4. Second UCSI_GET_CONNECTOR_STATUS */
command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
- ret = ucsi_send_command(ucsi, command, &con->status,
- sizeof(con->status));
+ ret = ucsi_send_command(ucsi, command, &post_ack_status,
+ sizeof(post_ack_status));
if (ret < 0) {
dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
__func__, ret);
goto out_unlock;
}
+ /* 5. Inferre any missing changes */
+ changed_flags = pre_ack_status.flags ^ post_ack_status.flags;
+ inferred_changes = 0;
+ if (UCSI_CONSTAT_PWR_OPMODE(changed_flags) != 0)
+ inferred_changes |= UCSI_CONSTAT_POWER_OPMODE_CHANGE;
+
+ if (changed_flags & UCSI_CONSTAT_CONNECTED)
+ inferred_changes |= UCSI_CONSTAT_CONNECT_CHANGE;
+
+ if (changed_flags & UCSI_CONSTAT_PWR_DIR)
+ inferred_changes |= UCSI_CONSTAT_POWER_DIR_CHANGE;
+
+ if (UCSI_CONSTAT_PARTNER_FLAGS(changed_flags) != 0)
+ inferred_changes |= UCSI_CONSTAT_PARTNER_CHANGE;
+
+ if (UCSI_CONSTAT_PARTNER_TYPE(changed_flags) != 0)
+ inferred_changes |= UCSI_CONSTAT_PARTNER_CHANGE;
+
+ /* Mask out anything that was correctly notified in the later call. */
+ inferred_changes &= ~post_ack_status.change;
+ if (inferred_changes)
+ dev_dbg(ucsi->dev, "%s: Inferred changes that would have been lost: 0x%04x\n",
+ __func__, inferred_changes);
+
+ con->unprocessed_changes |= inferred_changes;
+
+ /* 6. If PPM reported a new change, then restart in order to ACK */
+ if (post_ack_status.change)
+ goto out_unlock;
+
+ /* 7. Continue as if nothing happened */
+ con->status = post_ack_status;
+ con->status.change = con->unprocessed_changes;
+ con->unprocessed_changes = 0;
+
role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR);
if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE ||
- con->status.change & UCSI_CONSTAT_POWER_LEVEL_CHANGE)
+ con->status.change & UCSI_CONSTAT_POWER_LEVEL_CHANGE) {
ucsi_pwr_opmode_change(con);
+ ucsi_port_psy_changed(con);
+ }
if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) {
typec_set_pwr_role(con->port, role);
@@ -674,30 +768,23 @@ static void ucsi_handle_connector_change(struct work_struct *work)
ucsi_register_partner(con);
else
ucsi_unregister_partner(con);
- }
- if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) {
- /*
- * We don't need to know the currently supported alt modes here.
- * Running GET_CAM_SUPPORTED command just to make sure the PPM
- * does not get stuck in case it assumes we do so.
- */
- command = UCSI_GET_CAM_SUPPORTED;
- command |= UCSI_CONNECTOR_NUMBER(con->num);
- ucsi_send_command(con->ucsi, command, NULL, 0);
+ ucsi_port_psy_changed(con);
}
if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE)
ucsi_partner_change(con);
- ret = ucsi_acknowledge_connector_change(ucsi);
- if (ret)
- dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret);
-
trace_ucsi_connector_change(con->num, &con->status);
out_unlock:
- clear_bit(EVENT_PENDING, &ucsi->flags);
+ if (test_and_clear_bit(EVENT_PENDING, &ucsi->flags)) {
+ schedule_work(&con->work);
+ mutex_unlock(&con->lock);
+ return;
+ }
+
+ clear_bit(EVENT_PROCESSING, &ucsi->flags);
mutex_unlock(&con->lock);
}
@@ -715,7 +802,9 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num)
return;
}
- if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags))
+ set_bit(EVENT_PENDING, &ucsi->flags);
+
+ if (!test_and_set_bit(EVENT_PROCESSING, &ucsi->flags))
schedule_work(&con->work);
}
EXPORT_SYMBOL_GPL(ucsi_connector_change);
@@ -994,6 +1083,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
!!(con->status.flags & UCSI_CONSTAT_PWR_DIR));
ucsi_pwr_opmode_change(con);
ucsi_register_partner(con);
+ ucsi_port_psy_changed(con);
}
if (con->partner) {
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index cba6f77bea61..dd9ba60ab4a3 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -296,6 +296,7 @@ struct ucsi {
#define EVENT_PENDING 0
#define COMMAND_PENDING 1
#define ACK_PENDING 2
+#define EVENT_PROCESSING 3
};
#define UCSI_MAX_SVID 5
@@ -322,6 +323,7 @@ struct ucsi_connector {
struct typec_capability typec_cap;
+ u16 unprocessed_changes;
struct ucsi_connector_status status;
struct ucsi_connector_capability cap;
struct power_supply *psy;
@@ -340,9 +342,11 @@ int ucsi_resume(struct ucsi *ucsi);
#if IS_ENABLED(CONFIG_POWER_SUPPLY)
int ucsi_register_port_psy(struct ucsi_connector *con);
void ucsi_unregister_port_psy(struct ucsi_connector *con);
+void ucsi_port_psy_changed(struct ucsi_connector *con);
#else
static inline int ucsi_register_port_psy(struct ucsi_connector *con) { return 0; }
static inline void ucsi_unregister_port_psy(struct ucsi_connector *con) { }
+static inline void ucsi_port_psy_changed(struct ucsi_connector *con) { }
#endif /* CONFIG_POWER_SUPPLY */
#if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index fbfe8f5933af..04976435ad73 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -103,11 +103,12 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
if (ret)
return;
+ if (UCSI_CCI_CONNECTOR(cci))
+ ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));
+
if (test_bit(COMMAND_PENDING, &ua->flags) &&
cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
complete(&ua->complete);
- else if (UCSI_CCI_CONNECTOR(cci))
- ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));
}
static int ucsi_acpi_probe(struct platform_device *pdev)
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
index 4ce6c6a45eb1..2ab99244bc31 100644
--- a/drivers/usb/usbip/usbip_common.c
+++ b/drivers/usb/usbip/usbip_common.c
@@ -324,11 +324,6 @@ int usbip_recv(struct socket *sock, void *buf, int size)
} while (msg_data_left(&msg));
if (usbip_dbg_flag_xmit) {
- if (!in_interrupt())
- pr_debug("%-10s:", current->comm);
- else
- pr_debug("interrupt :");
-
pr_debug("receiving....\n");
usbip_dump_buffer(buf, size);
pr_debug("received, osize %d ret %d size %zd total %d\n",