mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
USB patches for 4.4-rc1
Here is the big USB patchset for 4.4-rc1. As usual, most of the changes are in the gadget subsystem, and we removed a host controller for a device that is no longer in existance, and probably never was even made public. There is also other minor driver updates and new device ids, full details in the changelog. All of these have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <[email protected]> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlY6gVMACgkQMUfUDdst+ynLZgCePfhiDuwriaX7osq90HDu8JOc pTEAn2dBdw2VMPToUlxccR963YSfgu2A =mMgp -----END PGP SIGNATURE----- Merge tag 'usb-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB updates from Greg KH: "Here is the big USB patchset for 4.4-rc1. As usual, most of the changes are in the gadget subsystem, and we removed a host controller for a device that is no longer in existance, and probably never was even made public. There is also other minor driver updates and new device ids, full details in the changelog. All of these have been in linux-next for a while" * tag 'usb-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (233 commits) USB: core: Codestyle fix in urb.c usb: misc: usb3503: Use i2c_add_driver helper macro usb: host: lpc32xx: don't unregister phy device usb: host: lpc32xx: balance clk enable/disable on removal usb: host: lpc32xx: fix warnings caused by enabling unprepared clock uwb: drp: Use setup_timer uwb: neh: Use setup_timer uwb: rsv: Use setup_timer USB: qcserial: add Sierra Wireless MC74xx/EM74xx usb: chipidea: otg: don't wait vbus drops below BSV when starts host chipidea: ci_hdrc_pci: use PCI_VDEVICE() instead of PCI_DEVICE() doc: dt-binding: ci-hdrc-usb2: split vendor specific properties usb: chipidea: imx: add imx6ul usb support doc: dt-binding: ci-hdrc-usb2: improve property description usb: chipidea: imx: add usb support for imx7d Doc: usb: ci-hdrc-usb2: Add phy-clkgate-delay-us entry usb: chipidea: Add support for 'phy-clkgate-delay-us' property usb: chipidea: Use extcon framework for VBUS and ID detect usb: gadget: net2280: restore ep_cfg after defect7374 workaround usb: dwc2: host: Fix use after free w/ simultaneous irqs ...
This commit is contained in:
commit
3d6f47801c
144 changed files with 5964 additions and 10544 deletions
|
|
@ -27,7 +27,6 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
|||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
|
||||
obj-$(CONFIG_USB_FUSBH200_HCD) += host/
|
||||
obj-$(CONFIG_USB_FOTG210_HCD) += host/
|
||||
obj-$(CONFIG_USB_MAX3421_HCD) += host/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
config USB_CHIPIDEA
|
||||
tristate "ChipIdea Highspeed Dual Role Controller"
|
||||
depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA
|
||||
select EXTCON
|
||||
help
|
||||
Say Y here if your system has a dual role high speed USB
|
||||
controller based on ChipIdea silicon IP. Currently, only the
|
||||
|
|
|
|||
|
|
@ -56,12 +56,23 @@ static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
|
|||
CI_HDRC_DISABLE_HOST_STREAMING,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
|
||||
};
|
||||
|
||||
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
|
||||
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
|
||||
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
|
||||
{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
|
||||
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
|
||||
{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
|
||||
{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
|
||||
|
|
|
|||
|
|
@ -142,16 +142,16 @@ static const struct pci_device_id ci_hdrc_pci_id_table[] = {
|
|||
.driver_data = (kernel_ulong_t)&pci_platdata,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
|
||||
PCI_VDEVICE(INTEL, 0x0811),
|
||||
.driver_data = (kernel_ulong_t)&langwell_pci_platdata,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
|
||||
PCI_VDEVICE(INTEL, 0x0829),
|
||||
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
||||
},
|
||||
{
|
||||
/* Intel Clovertrail */
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006),
|
||||
PCI_VDEVICE(INTEL, 0xe006),
|
||||
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
||||
},
|
||||
{ 0 } /* end: all zeroes */
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -602,16 +603,52 @@ static irqreturn_t ci_irq(int irq, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb);
|
||||
struct ci_hdrc *ci = vbus->ci;
|
||||
|
||||
if (event)
|
||||
vbus->state = true;
|
||||
else
|
||||
vbus->state = false;
|
||||
|
||||
vbus->changed = true;
|
||||
|
||||
ci_irq(ci->irq, ci);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int ci_id_notifier(struct notifier_block *nb, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb);
|
||||
struct ci_hdrc *ci = id->ci;
|
||||
|
||||
if (event)
|
||||
id->state = false;
|
||||
else
|
||||
id->state = true;
|
||||
|
||||
id->changed = true;
|
||||
|
||||
ci_irq(ci->irq, ci);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int ci_get_platdata(struct device *dev,
|
||||
struct ci_hdrc_platform_data *platdata)
|
||||
{
|
||||
struct extcon_dev *ext_vbus, *ext_id;
|
||||
struct ci_hdrc_cable *cable;
|
||||
int ret;
|
||||
|
||||
if (!platdata->phy_mode)
|
||||
platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
|
||||
|
||||
if (!platdata->dr_mode)
|
||||
platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
|
||||
platdata->dr_mode = usb_get_dr_mode(dev);
|
||||
|
||||
if (platdata->dr_mode == USB_DR_MODE_UNKNOWN)
|
||||
platdata->dr_mode = USB_DR_MODE_OTG;
|
||||
|
|
@ -648,9 +685,13 @@ static int ci_get_platdata(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
|
||||
if (usb_get_maximum_speed(dev) == USB_SPEED_FULL)
|
||||
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
|
||||
|
||||
if (of_find_property(dev->of_node, "phy-clkgate-delay-us", NULL))
|
||||
of_property_read_u32(dev->of_node, "phy-clkgate-delay-us",
|
||||
&platdata->phy_clkgate_delay_us);
|
||||
|
||||
platdata->itc_setting = 1;
|
||||
if (of_find_property(dev->of_node, "itc-setting", NULL)) {
|
||||
ret = of_property_read_u32(dev->of_node, "itc-setting",
|
||||
|
|
@ -695,9 +736,91 @@ static int ci_get_platdata(struct device *dev,
|
|||
platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
|
||||
}
|
||||
|
||||
ext_id = ERR_PTR(-ENODEV);
|
||||
ext_vbus = ERR_PTR(-ENODEV);
|
||||
if (of_property_read_bool(dev->of_node, "extcon")) {
|
||||
/* Each one of them is not mandatory */
|
||||
ext_vbus = extcon_get_edev_by_phandle(dev, 0);
|
||||
if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
|
||||
return PTR_ERR(ext_vbus);
|
||||
|
||||
ext_id = extcon_get_edev_by_phandle(dev, 1);
|
||||
if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
|
||||
return PTR_ERR(ext_id);
|
||||
}
|
||||
|
||||
cable = &platdata->vbus_extcon;
|
||||
cable->nb.notifier_call = ci_vbus_notifier;
|
||||
cable->edev = ext_vbus;
|
||||
|
||||
if (!IS_ERR(ext_vbus)) {
|
||||
ret = extcon_get_cable_state_(cable->edev, EXTCON_USB);
|
||||
if (ret)
|
||||
cable->state = true;
|
||||
else
|
||||
cable->state = false;
|
||||
}
|
||||
|
||||
cable = &platdata->id_extcon;
|
||||
cable->nb.notifier_call = ci_id_notifier;
|
||||
cable->edev = ext_id;
|
||||
|
||||
if (!IS_ERR(ext_id)) {
|
||||
ret = extcon_get_cable_state_(cable->edev, EXTCON_USB_HOST);
|
||||
if (ret)
|
||||
cable->state = false;
|
||||
else
|
||||
cable->state = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_extcon_register(struct ci_hdrc *ci)
|
||||
{
|
||||
struct ci_hdrc_cable *id, *vbus;
|
||||
int ret;
|
||||
|
||||
id = &ci->platdata->id_extcon;
|
||||
id->ci = ci;
|
||||
if (!IS_ERR(id->edev)) {
|
||||
ret = extcon_register_notifier(id->edev, EXTCON_USB_HOST,
|
||||
&id->nb);
|
||||
if (ret < 0) {
|
||||
dev_err(ci->dev, "register ID failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
vbus = &ci->platdata->vbus_extcon;
|
||||
vbus->ci = ci;
|
||||
if (!IS_ERR(vbus->edev)) {
|
||||
ret = extcon_register_notifier(vbus->edev, EXTCON_USB,
|
||||
&vbus->nb);
|
||||
if (ret < 0) {
|
||||
extcon_unregister_notifier(id->edev, EXTCON_USB_HOST,
|
||||
&id->nb);
|
||||
dev_err(ci->dev, "register VBUS failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ci_extcon_unregister(struct ci_hdrc *ci)
|
||||
{
|
||||
struct ci_hdrc_cable *cable;
|
||||
|
||||
cable = &ci->platdata->id_extcon;
|
||||
if (!IS_ERR(cable->edev))
|
||||
extcon_unregister_notifier(cable->edev, EXTCON_USB_HOST,
|
||||
&cable->nb);
|
||||
|
||||
cable = &ci->platdata->vbus_extcon;
|
||||
if (!IS_ERR(cable->edev))
|
||||
extcon_unregister_notifier(cable->edev, EXTCON_USB, &cable->nb);
|
||||
}
|
||||
|
||||
static DEFINE_IDA(ci_ida);
|
||||
|
||||
struct platform_device *ci_hdrc_add_device(struct device *dev,
|
||||
|
|
@ -921,6 +1044,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto stop;
|
||||
|
||||
ret = ci_extcon_register(ci);
|
||||
if (ret)
|
||||
goto stop;
|
||||
|
||||
if (ci->supports_runtime_pm) {
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
|
@ -938,6 +1065,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||
if (!ret)
|
||||
return 0;
|
||||
|
||||
ci_extcon_unregister(ci);
|
||||
stop:
|
||||
ci_role_destroy(ci);
|
||||
deinit_phy:
|
||||
|
|
@ -957,6 +1085,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dbg_remove_files(ci);
|
||||
ci_extcon_unregister(ci);
|
||||
ci_role_destroy(ci);
|
||||
ci_hdrc_enter_lpm(ci, true);
|
||||
ci_usb_phy_exit(ci);
|
||||
|
|
@ -996,6 +1125,9 @@ static void ci_controller_suspend(struct ci_hdrc *ci)
|
|||
{
|
||||
disable_irq(ci->irq);
|
||||
ci_hdrc_enter_lpm(ci, true);
|
||||
if (ci->platdata->phy_clkgate_delay_us)
|
||||
usleep_range(ci->platdata->phy_clkgate_delay_us,
|
||||
ci->platdata->phy_clkgate_delay_us + 50);
|
||||
usb_phy_set_suspend(ci->usb_phy, 1);
|
||||
ci->in_lpm = true;
|
||||
enable_irq(ci->irq);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,44 @@
|
|||
*/
|
||||
u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
|
||||
{
|
||||
return hw_read(ci, OP_OTGSC, mask);
|
||||
struct ci_hdrc_cable *cable;
|
||||
u32 val = hw_read(ci, OP_OTGSC, mask);
|
||||
|
||||
/*
|
||||
* If using extcon framework for VBUS and/or ID signal
|
||||
* detection overwrite OTGSC register value
|
||||
*/
|
||||
cable = &ci->platdata->vbus_extcon;
|
||||
if (!IS_ERR(cable->edev)) {
|
||||
if (cable->changed)
|
||||
val |= OTGSC_BSVIS;
|
||||
else
|
||||
val &= ~OTGSC_BSVIS;
|
||||
|
||||
cable->changed = false;
|
||||
|
||||
if (cable->state)
|
||||
val |= OTGSC_BSV;
|
||||
else
|
||||
val &= ~OTGSC_BSV;
|
||||
}
|
||||
|
||||
cable = &ci->platdata->id_extcon;
|
||||
if (!IS_ERR(cable->edev)) {
|
||||
if (cable->changed)
|
||||
val |= OTGSC_IDIS;
|
||||
else
|
||||
val &= ~OTGSC_IDIS;
|
||||
|
||||
cable->changed = false;
|
||||
|
||||
if (cable->state)
|
||||
val |= OTGSC_ID;
|
||||
else
|
||||
val &= ~OTGSC_ID;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,9 +114,12 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
|
|||
ci_role(ci)->name, ci->roles[role]->name);
|
||||
|
||||
ci_role_stop(ci);
|
||||
/* wait vbus lower than OTGSC_BSV */
|
||||
hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
|
||||
CI_VBUS_STABLE_TIMEOUT_MS);
|
||||
|
||||
if (role == CI_ROLE_GADGET)
|
||||
/* wait vbus lower than OTGSC_BSV */
|
||||
hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
|
||||
CI_VBUS_STABLE_TIMEOUT_MS);
|
||||
|
||||
ci_role_start(ci, role);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,14 @@
|
|||
|
||||
#define VF610_OVER_CUR_DIS BIT(7)
|
||||
|
||||
#define MX7D_USBNC_USB_CTRL2 0x4
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0)
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0)
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
|
||||
#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
|
||||
|
||||
struct usbmisc_ops {
|
||||
/* It's called once when probe a usb device */
|
||||
int (*init)(struct imx_usbmisc_data *data);
|
||||
|
|
@ -324,6 +332,55 @@ static int usbmisc_vf610_init(struct imx_usbmisc_data *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int usbmisc_imx7d_set_wakeup
|
||||
(struct imx_usbmisc_data *data, bool enabled)
|
||||
{
|
||||
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
|
||||
MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val = readl(usbmisc->base);
|
||||
if (enabled) {
|
||||
writel(val | wakeup_setting, usbmisc->base);
|
||||
} else {
|
||||
if (val & MX6_BM_WAKEUP_INTR)
|
||||
dev_dbg(data->dev, "wakeup int\n");
|
||||
writel(val & ~wakeup_setting, usbmisc->base);
|
||||
}
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
|
||||
{
|
||||
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
if (data->index >= 1)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
if (data->disable_oc) {
|
||||
reg = readl(usbmisc->base);
|
||||
writel(reg | MX6_BM_OVER_CUR_DIS, usbmisc->base);
|
||||
}
|
||||
|
||||
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
|
||||
writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
|
||||
usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
|
||||
usbmisc_imx7d_set_wakeup(data, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usbmisc_ops imx25_usbmisc_ops = {
|
||||
.init = usbmisc_imx25_init,
|
||||
.post = usbmisc_imx25_post,
|
||||
|
|
@ -351,6 +408,11 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = {
|
|||
.init = usbmisc_imx6sx_init,
|
||||
};
|
||||
|
||||
static const struct usbmisc_ops imx7d_usbmisc_ops = {
|
||||
.init = usbmisc_imx7d_init,
|
||||
.set_wakeup = usbmisc_imx7d_set_wakeup,
|
||||
};
|
||||
|
||||
int imx_usbmisc_init(struct imx_usbmisc_data *data)
|
||||
{
|
||||
struct imx_usbmisc *usbmisc;
|
||||
|
|
@ -426,6 +488,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
|
|||
.compatible = "fsl,imx6sx-usbmisc",
|
||||
.data = &imx6sx_usbmisc_ops,
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,imx6ul-usbmisc",
|
||||
.data = &imx6sx_usbmisc_ops,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,24 @@ const char *usb_speed_string(enum usb_device_speed speed)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_speed_string);
|
||||
|
||||
enum usb_device_speed usb_get_maximum_speed(struct device *dev)
|
||||
{
|
||||
const char *maximum_speed;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = device_property_read_string(dev, "maximum-speed", &maximum_speed);
|
||||
if (err < 0)
|
||||
return USB_SPEED_UNKNOWN;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(speed_names); i++)
|
||||
if (strcmp(maximum_speed, speed_names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return USB_SPEED_UNKNOWN;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_get_maximum_speed);
|
||||
|
||||
const char *usb_state_string(enum usb_device_state state)
|
||||
{
|
||||
static const char *const names[] = {
|
||||
|
|
@ -81,7 +99,6 @@ const char *usb_state_string(enum usb_device_state state)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_state_string);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const char *const usb_dr_modes[] = {
|
||||
[USB_DR_MODE_UNKNOWN] = "",
|
||||
[USB_DR_MODE_HOST] = "host",
|
||||
|
|
@ -89,19 +106,12 @@ static const char *const usb_dr_modes[] = {
|
|||
[USB_DR_MODE_OTG] = "otg",
|
||||
};
|
||||
|
||||
/**
|
||||
* of_usb_get_dr_mode - Get dual role mode for given device_node
|
||||
* @np: Pointer to the given device_node
|
||||
*
|
||||
* The function gets phy interface string from property 'dr_mode',
|
||||
* and returns the correspondig enum usb_dr_mode
|
||||
*/
|
||||
enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
|
||||
enum usb_dr_mode usb_get_dr_mode(struct device *dev)
|
||||
{
|
||||
const char *dr_mode;
|
||||
int err, i;
|
||||
|
||||
err = of_property_read_string(np, "dr_mode", &dr_mode);
|
||||
err = device_property_read_string(dev, "dr_mode", &dr_mode);
|
||||
if (err < 0)
|
||||
return USB_DR_MODE_UNKNOWN;
|
||||
|
||||
|
|
@ -111,34 +121,9 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
|
|||
|
||||
return USB_DR_MODE_UNKNOWN;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
|
||||
|
||||
/**
|
||||
* of_usb_get_maximum_speed - Get maximum requested speed for a given USB
|
||||
* controller.
|
||||
* @np: Pointer to the given device_node
|
||||
*
|
||||
* The function gets the maximum speed string from property "maximum-speed",
|
||||
* and returns the corresponding enum usb_device_speed.
|
||||
*/
|
||||
enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
|
||||
{
|
||||
const char *maximum_speed;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = of_property_read_string(np, "maximum-speed", &maximum_speed);
|
||||
if (err < 0)
|
||||
return USB_SPEED_UNKNOWN;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(speed_names); i++)
|
||||
if (strcmp(maximum_speed, speed_names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return USB_SPEED_UNKNOWN;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
|
||||
EXPORT_SYMBOL_GPL(usb_get_dr_mode);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
|
||||
* for given targeted hosts (non-PC hosts)
|
||||
|
|
|
|||
|
|
@ -853,6 +853,10 @@ int usb_get_bos_descriptor(struct usb_device *dev)
|
|||
dev->bos->ss_cap =
|
||||
(struct usb_ss_cap_descriptor *)buffer;
|
||||
break;
|
||||
case USB_SSP_CAP_TYPE:
|
||||
dev->bos->ssp_cap =
|
||||
(struct usb_ssp_cap_descriptor *)buffer;
|
||||
break;
|
||||
case CONTAINER_ID_TYPE:
|
||||
dev->bos->ss_id =
|
||||
(struct usb_ss_container_id_descriptor *)buffer;
|
||||
|
|
|
|||
|
|
@ -296,6 +296,10 @@ static int usb_probe_interface(struct device *dev)
|
|||
if (udev->authorized == 0) {
|
||||
dev_err(&intf->dev, "Device is not authorized for usage\n");
|
||||
return error;
|
||||
} else if (intf->authorized == 0) {
|
||||
dev_err(&intf->dev, "Interface %d is not authorized for usage\n",
|
||||
intf->altsetting->desc.bInterfaceNumber);
|
||||
return error;
|
||||
}
|
||||
|
||||
id = usb_match_dynamic_id(intf, driver);
|
||||
|
|
@ -417,12 +421,10 @@ static int usb_unbind_interface(struct device *dev)
|
|||
if (ep->streams == 0)
|
||||
continue;
|
||||
if (j == 0) {
|
||||
eps = kmalloc(USB_MAXENDPOINTS * sizeof(void *),
|
||||
eps = kmalloc_array(USB_MAXENDPOINTS, sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
if (!eps) {
|
||||
dev_warn(dev, "oom, leaking streams\n");
|
||||
if (!eps)
|
||||
break;
|
||||
}
|
||||
}
|
||||
eps[j++] = ep;
|
||||
}
|
||||
|
|
@ -508,6 +510,10 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
|||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
|
||||
/* reject claim if interface is not authorized */
|
||||
if (!iface->authorized)
|
||||
return -ENODEV;
|
||||
|
||||
udev = interface_to_usbdev(iface);
|
||||
|
||||
dev->driver = &driver->drvwrap.driver;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ static inline int is_root_hub(struct usb_device *udev)
|
|||
/* usb 3.0 root hub device descriptor */
|
||||
static const u8 usb3_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
|
||||
0x00, 0x03, /* __le16 bcdUSB; v3.0 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
|
|
@ -152,7 +152,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
|
|||
/* usb 2.5 (wireless USB 1.0) root hub device descriptor */
|
||||
static const u8 usb25_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
|
||||
0x50, 0x02, /* __le16 bcdUSB; v2.5 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
|
|
@ -173,7 +173,7 @@ static const u8 usb25_rh_dev_descriptor[18] = {
|
|||
/* usb 2.0 root hub device descriptor */
|
||||
static const u8 usb2_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
|
||||
0x00, 0x02, /* __le16 bcdUSB; v2.0 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
|
|
@ -196,7 +196,7 @@ static const u8 usb2_rh_dev_descriptor[18] = {
|
|||
/* usb 1.1 root hub device descriptor */
|
||||
static const u8 usb11_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
|
||||
0x10, 0x01, /* __le16 bcdUSB; v1.1 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
|
|
@ -223,7 +223,7 @@ static const u8 fs_rh_config_descriptor[] = {
|
|||
|
||||
/* one configuration */
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */
|
||||
0x19, 0x00, /* __le16 wTotalLength; */
|
||||
0x01, /* __u8 bNumInterfaces; (1) */
|
||||
0x01, /* __u8 bConfigurationValue; */
|
||||
|
|
@ -248,7 +248,7 @@ static const u8 fs_rh_config_descriptor[] = {
|
|||
|
||||
/* one interface */
|
||||
0x09, /* __u8 if_bLength; */
|
||||
0x04, /* __u8 if_bDescriptorType; Interface */
|
||||
USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */
|
||||
0x00, /* __u8 if_bInterfaceNumber; */
|
||||
0x00, /* __u8 if_bAlternateSetting; */
|
||||
0x01, /* __u8 if_bNumEndpoints; */
|
||||
|
|
@ -259,7 +259,7 @@ static const u8 fs_rh_config_descriptor[] = {
|
|||
|
||||
/* one endpoint (status change endpoint) */
|
||||
0x07, /* __u8 ep_bLength; */
|
||||
0x05, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* __u8 ep_bmAttributes; Interrupt */
|
||||
0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
|
||||
|
|
@ -270,7 +270,7 @@ static const u8 hs_rh_config_descriptor[] = {
|
|||
|
||||
/* one configuration */
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */
|
||||
0x19, 0x00, /* __le16 wTotalLength; */
|
||||
0x01, /* __u8 bNumInterfaces; (1) */
|
||||
0x01, /* __u8 bConfigurationValue; */
|
||||
|
|
@ -295,7 +295,7 @@ static const u8 hs_rh_config_descriptor[] = {
|
|||
|
||||
/* one interface */
|
||||
0x09, /* __u8 if_bLength; */
|
||||
0x04, /* __u8 if_bDescriptorType; Interface */
|
||||
USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */
|
||||
0x00, /* __u8 if_bInterfaceNumber; */
|
||||
0x00, /* __u8 if_bAlternateSetting; */
|
||||
0x01, /* __u8 if_bNumEndpoints; */
|
||||
|
|
@ -306,7 +306,7 @@ static const u8 hs_rh_config_descriptor[] = {
|
|||
|
||||
/* one endpoint (status change endpoint) */
|
||||
0x07, /* __u8 ep_bLength; */
|
||||
0x05, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* __u8 ep_bmAttributes; Interrupt */
|
||||
/* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
|
||||
|
|
@ -318,7 +318,7 @@ static const u8 hs_rh_config_descriptor[] = {
|
|||
static const u8 ss_rh_config_descriptor[] = {
|
||||
/* one configuration */
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
USB_DT_CONFIG, /* __u8 bDescriptorType; Configuration */
|
||||
0x1f, 0x00, /* __le16 wTotalLength; */
|
||||
0x01, /* __u8 bNumInterfaces; (1) */
|
||||
0x01, /* __u8 bConfigurationValue; */
|
||||
|
|
@ -332,7 +332,7 @@ static const u8 ss_rh_config_descriptor[] = {
|
|||
|
||||
/* one interface */
|
||||
0x09, /* __u8 if_bLength; */
|
||||
0x04, /* __u8 if_bDescriptorType; Interface */
|
||||
USB_DT_INTERFACE, /* __u8 if_bDescriptorType; Interface */
|
||||
0x00, /* __u8 if_bInterfaceNumber; */
|
||||
0x00, /* __u8 if_bAlternateSetting; */
|
||||
0x01, /* __u8 if_bNumEndpoints; */
|
||||
|
|
@ -343,7 +343,7 @@ static const u8 ss_rh_config_descriptor[] = {
|
|||
|
||||
/* one endpoint (status change endpoint) */
|
||||
0x07, /* __u8 ep_bLength; */
|
||||
0x05, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
USB_DT_ENDPOINT, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* __u8 ep_bmAttributes; Interrupt */
|
||||
/* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
|
||||
|
|
@ -353,7 +353,8 @@ static const u8 ss_rh_config_descriptor[] = {
|
|||
|
||||
/* one SuperSpeed endpoint companion descriptor */
|
||||
0x06, /* __u8 ss_bLength */
|
||||
0x30, /* __u8 ss_bDescriptorType; SuperSpeed EP Companion */
|
||||
USB_DT_SS_ENDPOINT_COMP, /* __u8 ss_bDescriptorType; SuperSpeed EP */
|
||||
/* Companion */
|
||||
0x00, /* __u8 ss_bMaxBurst; allows 1 TX between ACKs */
|
||||
0x00, /* __u8 ss_bmAttributes; 1 packet per service interval */
|
||||
0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
|
||||
|
|
@ -555,6 +556,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
|||
switch (wValue & 0xff00) {
|
||||
case USB_DT_DEVICE << 8:
|
||||
switch (hcd->speed) {
|
||||
case HCD_USB31:
|
||||
case HCD_USB3:
|
||||
bufp = usb3_rh_dev_descriptor;
|
||||
break;
|
||||
|
|
@ -576,6 +578,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
|||
break;
|
||||
case USB_DT_CONFIG << 8:
|
||||
switch (hcd->speed) {
|
||||
case HCD_USB31:
|
||||
case HCD_USB3:
|
||||
bufp = ss_rh_config_descriptor;
|
||||
len = sizeof ss_rh_config_descriptor;
|
||||
|
|
@ -854,10 +857,10 @@ static ssize_t authorized_default_show(struct device *dev,
|
|||
{
|
||||
struct usb_device *rh_usb_dev = to_usb_device(dev);
|
||||
struct usb_bus *usb_bus = rh_usb_dev->bus;
|
||||
struct usb_hcd *usb_hcd;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
usb_hcd = bus_to_hcd(usb_bus);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd));
|
||||
}
|
||||
|
||||
static ssize_t authorized_default_store(struct device *dev,
|
||||
|
|
@ -868,12 +871,16 @@ static ssize_t authorized_default_store(struct device *dev,
|
|||
unsigned val;
|
||||
struct usb_device *rh_usb_dev = to_usb_device(dev);
|
||||
struct usb_bus *usb_bus = rh_usb_dev->bus;
|
||||
struct usb_hcd *usb_hcd;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
usb_hcd = bus_to_hcd(usb_bus);
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
result = sscanf(buf, "%u\n", &val);
|
||||
if (result == 1) {
|
||||
usb_hcd->authorized_default = val ? 1 : 0;
|
||||
if (val)
|
||||
set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
|
||||
result = size;
|
||||
} else {
|
||||
result = -EINVAL;
|
||||
|
|
@ -882,9 +889,53 @@ static ssize_t authorized_default_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RW(authorized_default);
|
||||
|
||||
/*
|
||||
* interface_authorized_default_show - show default authorization status
|
||||
* for USB interfaces
|
||||
*
|
||||
* note: interface_authorized_default is the default value
|
||||
* for initializing the authorized attribute of interfaces
|
||||
*/
|
||||
static ssize_t interface_authorized_default_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
|
||||
return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
|
||||
}
|
||||
|
||||
/*
|
||||
* interface_authorized_default_store - store default authorization status
|
||||
* for USB interfaces
|
||||
*
|
||||
* note: interface_authorized_default is the default value
|
||||
* for initializing the authorized attribute of interfaces
|
||||
*/
|
||||
static ssize_t interface_authorized_default_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
int rc = count;
|
||||
bool val;
|
||||
|
||||
if (strtobool(buf, &val) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val)
|
||||
set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RW(interface_authorized_default);
|
||||
|
||||
/* Group all the USB bus attributes */
|
||||
static struct attribute *usb_bus_attrs[] = {
|
||||
&dev_attr_authorized_default.attr,
|
||||
&dev_attr_interface_authorized_default.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
@ -2676,12 +2727,22 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
|
||||
|
||||
/* Keep old behaviour if authorized_default is not in [0, 1]. */
|
||||
if (authorized_default < 0 || authorized_default > 1)
|
||||
hcd->authorized_default = hcd->wireless ? 0 : 1;
|
||||
else
|
||||
hcd->authorized_default = authorized_default;
|
||||
if (authorized_default < 0 || authorized_default > 1) {
|
||||
if (hcd->wireless)
|
||||
clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
} else {
|
||||
if (authorized_default)
|
||||
set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
}
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* per default all interfaces are authorized */
|
||||
set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
|
||||
/* HC is in reset state, but accessible. Now do the one-time init,
|
||||
* bottom up so that hcds can customize the root hubs before hub_wq
|
||||
* starts talking to them. (Note, bus id is assigned early too.)
|
||||
|
|
@ -2717,6 +2778,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
rhdev->speed = USB_SPEED_WIRELESS;
|
||||
break;
|
||||
case HCD_USB3:
|
||||
case HCD_USB31:
|
||||
rhdev->speed = USB_SPEED_SUPER;
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -1070,7 +1070,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
* for HUB_POST_RESET, but it's easier not to.
|
||||
*/
|
||||
if (type == HUB_INIT) {
|
||||
unsigned delay = hub_power_on_good_delay(hub);
|
||||
delay = hub_power_on_good_delay(hub);
|
||||
|
||||
hub_power_on(hub, false);
|
||||
INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
|
||||
|
|
@ -1404,7 +1404,6 @@ static int hub_configure(struct usb_hub *hub,
|
|||
/* FIXME for USB 3.0, skip for now */
|
||||
if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
|
||||
!(hub_is_superspeed(hdev))) {
|
||||
int i;
|
||||
char portstr[USB_MAXCHILDREN + 1];
|
||||
|
||||
for (i = 0; i < maxchild; i++)
|
||||
|
|
@ -2240,39 +2239,49 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
|
|||
&& udev->parent == udev->bus->root_hub) {
|
||||
struct usb_otg_descriptor *desc = NULL;
|
||||
struct usb_bus *bus = udev->bus;
|
||||
unsigned port1 = udev->portnum;
|
||||
|
||||
/* descriptor may appear anywhere in config */
|
||||
if (__usb_get_extra_descriptor(udev->rawdescriptors[0],
|
||||
le16_to_cpu(udev->config[0].desc.wTotalLength),
|
||||
USB_DT_OTG, (void **) &desc) == 0) {
|
||||
if (desc->bmAttributes & USB_OTG_HNP) {
|
||||
unsigned port1 = udev->portnum;
|
||||
err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
|
||||
le16_to_cpu(udev->config[0].desc.wTotalLength),
|
||||
USB_DT_OTG, (void **) &desc);
|
||||
if (err || !(desc->bmAttributes & USB_OTG_HNP))
|
||||
return 0;
|
||||
|
||||
dev_info(&udev->dev,
|
||||
"Dual-Role OTG device on %sHNP port\n",
|
||||
(port1 == bus->otg_port)
|
||||
? "" : "non-");
|
||||
dev_info(&udev->dev, "Dual-Role OTG device on %sHNP port\n",
|
||||
(port1 == bus->otg_port) ? "" : "non-");
|
||||
|
||||
/* enable HNP before suspend, it's simpler */
|
||||
if (port1 == bus->otg_port)
|
||||
bus->b_hnp_enable = 1;
|
||||
err = usb_control_msg(udev,
|
||||
usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE, 0,
|
||||
bus->b_hnp_enable
|
||||
? USB_DEVICE_B_HNP_ENABLE
|
||||
: USB_DEVICE_A_ALT_HNP_SUPPORT,
|
||||
0, NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (err < 0) {
|
||||
/* OTG MESSAGE: report errors here,
|
||||
* customize to match your product.
|
||||
*/
|
||||
dev_info(&udev->dev,
|
||||
"can't set HNP mode: %d\n",
|
||||
err);
|
||||
bus->b_hnp_enable = 0;
|
||||
}
|
||||
/* enable HNP before suspend, it's simpler */
|
||||
if (port1 == bus->otg_port) {
|
||||
bus->b_hnp_enable = 1;
|
||||
err = usb_control_msg(udev,
|
||||
usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE, 0,
|
||||
USB_DEVICE_B_HNP_ENABLE,
|
||||
0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (err < 0) {
|
||||
/*
|
||||
* OTG MESSAGE: report errors here,
|
||||
* customize to match your product.
|
||||
*/
|
||||
dev_err(&udev->dev, "can't set HNP mode: %d\n",
|
||||
err);
|
||||
bus->b_hnp_enable = 0;
|
||||
}
|
||||
} else if (desc->bLength == sizeof
|
||||
(struct usb_otg_descriptor)) {
|
||||
/* Set a_alt_hnp_support for legacy otg device */
|
||||
err = usb_control_msg(udev,
|
||||
usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE, 0,
|
||||
USB_DEVICE_A_ALT_HNP_SUPPORT,
|
||||
0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (err < 0)
|
||||
dev_err(&udev->dev,
|
||||
"set a_alt_hnp_support failed: %d\n",
|
||||
err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -4222,7 +4231,7 @@ static int hub_enable_device(struct usb_device *udev)
|
|||
* but it is still necessary to lock the port.
|
||||
*/
|
||||
static int
|
||||
hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
int retry_counter)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
|
|
@ -4526,7 +4535,7 @@ fail:
|
|||
}
|
||||
|
||||
static void
|
||||
check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
|
||||
check_highspeed(struct usb_hub *hub, struct usb_device *udev, int port1)
|
||||
{
|
||||
struct usb_qualifier_descriptor *qual;
|
||||
int status;
|
||||
|
|
@ -4534,11 +4543,11 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
|
|||
if (udev->quirks & USB_QUIRK_DEVICE_QUALIFIER)
|
||||
return;
|
||||
|
||||
qual = kmalloc (sizeof *qual, GFP_KERNEL);
|
||||
qual = kmalloc(sizeof *qual, GFP_KERNEL);
|
||||
if (qual == NULL)
|
||||
return;
|
||||
|
||||
status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0,
|
||||
status = usb_get_descriptor(udev, USB_DT_DEVICE_QUALIFIER, 0,
|
||||
qual, sizeof *qual);
|
||||
if (status == sizeof *qual) {
|
||||
dev_info(&udev->dev, "not running at top speed; "
|
||||
|
|
@ -4554,7 +4563,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
|
|||
}
|
||||
|
||||
static unsigned
|
||||
hub_power_remaining (struct usb_hub *hub)
|
||||
hub_power_remaining(struct usb_hub *hub)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int remaining;
|
||||
|
|
@ -4741,7 +4750,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
|||
if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
|
||||
&& udev->speed == USB_SPEED_FULL
|
||||
&& highspeed_hubs != 0)
|
||||
check_highspeed (hub, udev, port1);
|
||||
check_highspeed(hub, udev, port1);
|
||||
|
||||
/* Store the parent's children[] pointer. At this point
|
||||
* udev becomes globally accessible, although presumably
|
||||
|
|
@ -5115,7 +5124,7 @@ static const struct usb_device_id hub_id_table[] = {
|
|||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, hub_id_table);
|
||||
MODULE_DEVICE_TABLE(usb, hub_id_table);
|
||||
|
||||
static struct usb_driver hub_driver = {
|
||||
.name = "hub",
|
||||
|
|
@ -5227,7 +5236,7 @@ static int descriptors_changed(struct usb_device *udev,
|
|||
changed = 1;
|
||||
break;
|
||||
}
|
||||
if (memcmp (buf, udev->rawdescriptors[index], old_length)
|
||||
if (memcmp(buf, udev->rawdescriptors[index], old_length)
|
||||
!= 0) {
|
||||
dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
|
||||
index,
|
||||
|
|
|
|||
|
|
@ -1387,8 +1387,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
|
|||
* new altsetting.
|
||||
*/
|
||||
if (manual) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < alt->desc.bNumEndpoints; i++) {
|
||||
epaddr = alt->endpoint[i].desc.bEndpointAddress;
|
||||
pipe = __create_pipe(dev,
|
||||
|
|
@ -1555,6 +1553,44 @@ static void usb_release_interface(struct device *dev)
|
|||
kfree(intf);
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_deauthorize_interface - deauthorize an USB interface
|
||||
*
|
||||
* @intf: USB interface structure
|
||||
*/
|
||||
void usb_deauthorize_interface(struct usb_interface *intf)
|
||||
{
|
||||
struct device *dev = &intf->dev;
|
||||
|
||||
device_lock(dev->parent);
|
||||
|
||||
if (intf->authorized) {
|
||||
device_lock(dev);
|
||||
intf->authorized = 0;
|
||||
device_unlock(dev);
|
||||
|
||||
usb_forced_unbind_intf(intf);
|
||||
}
|
||||
|
||||
device_unlock(dev->parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_authorize_interface - authorize an USB interface
|
||||
*
|
||||
* @intf: USB interface structure
|
||||
*/
|
||||
void usb_authorize_interface(struct usb_interface *intf)
|
||||
{
|
||||
struct device *dev = &intf->dev;
|
||||
|
||||
if (!intf->authorized) {
|
||||
device_lock(dev);
|
||||
intf->authorized = 1; /* authorize interface */
|
||||
device_unlock(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct usb_device *usb_dev;
|
||||
|
|
@ -1807,6 +1843,7 @@ free_interfaces:
|
|||
intfc = cp->intf_cache[i];
|
||||
intf->altsetting = intfc->altsetting;
|
||||
intf->num_altsetting = intfc->num_altsetting;
|
||||
intf->authorized = !!HCD_INTF_AUTHORIZED(hcd);
|
||||
kref_get(&intfc->ref);
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 0);
|
||||
|
|
|
|||
|
|
@ -957,6 +957,41 @@ static ssize_t supports_autosuspend_show(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RO(supports_autosuspend);
|
||||
|
||||
/*
|
||||
* interface_authorized_show - show authorization status of an USB interface
|
||||
* 1 is authorized, 0 is deauthorized
|
||||
*/
|
||||
static ssize_t interface_authorized_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", intf->authorized);
|
||||
}
|
||||
|
||||
/*
|
||||
* interface_authorized_store - authorize or deauthorize an USB interface
|
||||
*/
|
||||
static ssize_t interface_authorized_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
bool val;
|
||||
|
||||
if (strtobool(buf, &val) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val)
|
||||
usb_authorize_interface(intf);
|
||||
else
|
||||
usb_deauthorize_interface(intf);
|
||||
|
||||
return count;
|
||||
}
|
||||
static struct device_attribute dev_attr_interface_authorized =
|
||||
__ATTR(authorized, S_IRUGO | S_IWUSR,
|
||||
interface_authorized_show, interface_authorized_store);
|
||||
|
||||
static struct attribute *intf_attrs[] = {
|
||||
&dev_attr_bInterfaceNumber.attr,
|
||||
&dev_attr_bAlternateSetting.attr,
|
||||
|
|
@ -966,6 +1001,7 @@ static struct attribute *intf_attrs[] = {
|
|||
&dev_attr_bInterfaceProtocol.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_supports_autosuspend.attr,
|
||||
&dev_attr_interface_authorized.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group intf_attr_grp = {
|
||||
|
|
|
|||
|
|
@ -129,9 +129,8 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
|
|||
list_add_tail(&urb->anchor_list, &anchor->urb_list);
|
||||
urb->anchor = anchor;
|
||||
|
||||
if (unlikely(anchor->poisoned)) {
|
||||
if (unlikely(anchor->poisoned))
|
||||
atomic_inc(&urb->reject);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&anchor->lock, flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|||
if (root_hub) /* Root hub always ok [and always wired] */
|
||||
dev->authorized = 1;
|
||||
else {
|
||||
dev->authorized = usb_hcd->authorized_default;
|
||||
dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd);
|
||||
dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0;
|
||||
}
|
||||
return dev;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ extern void usb_release_interface_cache(struct kref *ref);
|
|||
extern void usb_disable_device(struct usb_device *dev, int skip_ep0);
|
||||
extern int usb_deauthorize_device(struct usb_device *);
|
||||
extern int usb_authorize_device(struct usb_device *);
|
||||
extern void usb_deauthorize_interface(struct usb_interface *);
|
||||
extern void usb_authorize_interface(struct usb_interface *);
|
||||
extern void usb_detect_quirks(struct usb_device *udev);
|
||||
extern void usb_detect_interface_quirks(struct usb_device *udev);
|
||||
extern int usb_remove_device(struct usb_device *udev);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -44,22 +44,38 @@
|
|||
#include <linux/usb/phy.h>
|
||||
#include "hw.h"
|
||||
|
||||
#ifdef DWC2_LOG_WRITES
|
||||
static inline void do_write(u32 value, void *addr)
|
||||
static inline u32 dwc2_readl(const void __iomem *addr)
|
||||
{
|
||||
writel(value, addr);
|
||||
pr_info("INFO:: wrote %08x to %p\n", value, addr);
|
||||
u32 value = __raw_readl(addr);
|
||||
|
||||
/* In order to preserve endianness __raw_* operation is used. Therefore
|
||||
* a barrier is needed to ensure IO access is not re-ordered across
|
||||
* reads or writes
|
||||
*/
|
||||
mb();
|
||||
return value;
|
||||
}
|
||||
|
||||
#undef writel
|
||||
#define writel(v, a) do_write(v, a)
|
||||
static inline void dwc2_writel(u32 value, void __iomem *addr)
|
||||
{
|
||||
__raw_writel(value, addr);
|
||||
|
||||
/*
|
||||
* In order to preserve endianness __raw_* operation is used. Therefore
|
||||
* a barrier is needed to ensure IO access is not re-ordered across
|
||||
* reads or writes
|
||||
*/
|
||||
mb();
|
||||
#ifdef DWC2_LOG_WRITES
|
||||
pr_info("INFO:: wrote %08x to %p\n", value, addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Maximum number of Endpoints/HostChannels */
|
||||
#define MAX_EPS_CHANNELS 16
|
||||
|
||||
/* s3c-hsotg declarations */
|
||||
static const char * const s3c_hsotg_supply_names[] = {
|
||||
/* dwc2-hsotg declarations */
|
||||
static const char * const dwc2_hsotg_supply_names[] = {
|
||||
"vusb_d", /* digital USB supply, 1.2V */
|
||||
"vusb_a", /* analog USB supply, 1.1V */
|
||||
};
|
||||
|
|
@ -85,10 +101,10 @@ static const char * const s3c_hsotg_supply_names[] = {
|
|||
#define EP0_MPS_LIMIT 64
|
||||
|
||||
struct dwc2_hsotg;
|
||||
struct s3c_hsotg_req;
|
||||
struct dwc2_hsotg_req;
|
||||
|
||||
/**
|
||||
* struct s3c_hsotg_ep - driver endpoint definition.
|
||||
* struct dwc2_hsotg_ep - driver endpoint definition.
|
||||
* @ep: The gadget layer representation of the endpoint.
|
||||
* @name: The driver generated name for the endpoint.
|
||||
* @queue: Queue of requests for this endpoint.
|
||||
|
|
@ -127,11 +143,11 @@ struct s3c_hsotg_req;
|
|||
* as in shared-fifo mode periodic in acts like a single-frame packet
|
||||
* buffer than a fifo)
|
||||
*/
|
||||
struct s3c_hsotg_ep {
|
||||
struct dwc2_hsotg_ep {
|
||||
struct usb_ep ep;
|
||||
struct list_head queue;
|
||||
struct dwc2_hsotg *parent;
|
||||
struct s3c_hsotg_req *req;
|
||||
struct dwc2_hsotg_req *req;
|
||||
struct dentry *debugfs;
|
||||
|
||||
unsigned long total_data;
|
||||
|
|
@ -150,17 +166,18 @@ struct s3c_hsotg_ep {
|
|||
unsigned int periodic:1;
|
||||
unsigned int isochronous:1;
|
||||
unsigned int send_zlp:1;
|
||||
unsigned int has_correct_parity:1;
|
||||
|
||||
char name[10];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s3c_hsotg_req - data transfer request
|
||||
* struct dwc2_hsotg_req - data transfer request
|
||||
* @req: The USB gadget request
|
||||
* @queue: The list of requests for the endpoint this is queued for.
|
||||
* @saved_req_buf: variable to save req.buf when bounce buffers are used.
|
||||
*/
|
||||
struct s3c_hsotg_req {
|
||||
struct dwc2_hsotg_req {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
void *saved_req_buf;
|
||||
|
|
@ -562,6 +579,15 @@ struct dwc2_hregs_backup {
|
|||
* - USB_DR_MODE_PERIPHERAL
|
||||
* - USB_DR_MODE_HOST
|
||||
* - USB_DR_MODE_OTG
|
||||
* @hcd_enabled Host mode sub-driver initialization indicator.
|
||||
* @gadget_enabled Peripheral mode sub-driver initialization indicator.
|
||||
* @ll_hw_enabled Status of low-level hardware resources.
|
||||
* @phy: The otg phy transceiver structure for phy control.
|
||||
* @uphy: The otg phy transceiver structure for old USB phy control.
|
||||
* @plat: The platform specific configuration data. This can be removed once
|
||||
* all SoCs support usb transceiver.
|
||||
* @supplies: Definition of USB power supplies
|
||||
* @phyif: PHY interface width
|
||||
* @lock: Spinlock that protects all the driver data structures
|
||||
* @priv: Stores a pointer to the struct usb_hcd
|
||||
* @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
|
||||
|
|
@ -654,12 +680,6 @@ struct dwc2_hregs_backup {
|
|||
* These are for peripheral mode:
|
||||
*
|
||||
* @driver: USB gadget driver
|
||||
* @phy: The otg phy transceiver structure for phy control.
|
||||
* @uphy: The otg phy transceiver structure for old USB phy control.
|
||||
* @plat: The platform specific configuration data. This can be removed once
|
||||
* all SoCs support usb transceiver.
|
||||
* @supplies: Definition of USB power supplies
|
||||
* @phyif: PHY interface width
|
||||
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
|
||||
* @num_of_eps: Number of available EPs (excluding EP0)
|
||||
* @debug_root: Root directrory for debugfs.
|
||||
|
|
@ -672,7 +692,6 @@ struct dwc2_hregs_backup {
|
|||
* @ctrl_req: Request for EP0 control packets.
|
||||
* @ep0_state: EP0 control transfers state
|
||||
* @test_mode: USB test mode requested by the host
|
||||
* @last_rst: Time of last reset
|
||||
* @eps: The endpoints being supplied to the gadget framework
|
||||
* @g_using_dma: Indicate if dma usage is enabled
|
||||
* @g_rx_fifo_sz: Contains rx fifo size value
|
||||
|
|
@ -690,13 +709,15 @@ struct dwc2_hsotg {
|
|||
enum usb_dr_mode dr_mode;
|
||||
unsigned int hcd_enabled:1;
|
||||
unsigned int gadget_enabled:1;
|
||||
unsigned int ll_hw_enabled:1;
|
||||
|
||||
struct phy *phy;
|
||||
struct usb_phy *uphy;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
|
||||
struct dwc2_hsotg_plat *plat;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(dwc2_hsotg_supply_names)];
|
||||
u32 phyif;
|
||||
|
||||
spinlock_t lock;
|
||||
struct mutex init_mutex;
|
||||
void *priv;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
|
|
@ -748,6 +769,7 @@ struct dwc2_hsotg {
|
|||
u16 frame_usecs[8];
|
||||
u16 frame_number;
|
||||
u16 periodic_qh_count;
|
||||
bool bus_suspended;
|
||||
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
#define FRAME_NUM_ARRAY_SIZE 1000
|
||||
|
|
@ -796,9 +818,6 @@ struct dwc2_hsotg {
|
|||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
/* Gadget structures */
|
||||
struct usb_gadget_driver *driver;
|
||||
struct s3c_hsotg_plat *plat;
|
||||
|
||||
u32 phyif;
|
||||
int fifo_mem;
|
||||
unsigned int dedicated_fifos:1;
|
||||
unsigned char num_of_eps;
|
||||
|
|
@ -814,9 +833,8 @@ struct dwc2_hsotg {
|
|||
struct usb_gadget gadget;
|
||||
unsigned int enabled:1;
|
||||
unsigned int connected:1;
|
||||
unsigned long last_rst;
|
||||
struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
|
||||
struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
|
||||
struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
|
||||
struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
|
||||
u32 g_using_dma;
|
||||
u32 g_rx_fifo_sz;
|
||||
u32 g_np_g_tx_fifo_sz;
|
||||
|
|
@ -1088,7 +1106,8 @@ extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
|
|||
|
||||
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
|
||||
|
||||
|
||||
extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/*
|
||||
* Dump core registers and SPRAM
|
||||
|
|
@ -1104,30 +1123,30 @@ extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
|
|||
|
||||
/* Gadget defines */
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
|
||||
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
|
||||
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
|
||||
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
extern void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
bool reset);
|
||||
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
|
||||
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
|
||||
extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
|
||||
extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
|
||||
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
|
||||
#else
|
||||
static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
|
||||
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
static inline int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2)
|
||||
static inline int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
|
||||
static inline int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
|
||||
{ return 0; }
|
||||
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
static inline void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
bool reset) {}
|
||||
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
|
||||
static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
|
||||
static inline void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
|
||||
static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
|
||||
int testmode)
|
||||
{ return 0; }
|
||||
#define dwc2_is_device_connected(hsotg) (0)
|
||||
|
|
|
|||
|
|
@ -80,15 +80,15 @@ static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 hprt0 = readl(hsotg->regs + HPRT0);
|
||||
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
||||
|
||||
if (hprt0 & HPRT0_ENACHG) {
|
||||
hprt0 &= ~HPRT0_ENA;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -102,7 +102,7 @@ static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
|
|||
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -117,8 +117,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
u32 gotgctl;
|
||||
u32 gintmsk;
|
||||
|
||||
gotgint = readl(hsotg->regs + GOTGINT);
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgint = dwc2_readl(hsotg->regs + GOTGINT);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
|
||||
dwc2_op_state_str(hsotg));
|
||||
|
||||
|
|
@ -126,10 +126,10 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
dev_dbg(hsotg->dev,
|
||||
" ++OTG Interrupt: Session End Detected++ (%s)\n",
|
||||
dwc2_op_state_str(hsotg));
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
|
||||
if (dwc2_is_device_mode(hsotg))
|
||||
s3c_hsotg_disconnect(hsotg);
|
||||
dwc2_hsotg_disconnect(hsotg);
|
||||
|
||||
if (hsotg->op_state == OTG_STATE_B_HOST) {
|
||||
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
|
|
@ -152,15 +152,15 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
hsotg->lx_state = DWC2_L0;
|
||||
}
|
||||
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl &= ~GOTGCTL_DEVHNPEN;
|
||||
writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
}
|
||||
|
||||
if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
|
||||
dev_dbg(hsotg->dev,
|
||||
" ++OTG Interrupt: Session Request Success Status Change++\n");
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
if (gotgctl & GOTGCTL_SESREQSCS) {
|
||||
if (hsotg->core_params->phy_type ==
|
||||
DWC2_PHY_TYPE_PARAM_FS
|
||||
|
|
@ -168,9 +168,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
hsotg->srp_success = 1;
|
||||
} else {
|
||||
/* Clear Session Request */
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl &= ~GOTGCTL_SESREQ;
|
||||
writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
* Print statements during the HNP interrupt handling
|
||||
* can cause it to fail
|
||||
*/
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
/*
|
||||
* WA for 3.00a- HW is not setting cur_mode, even sometimes
|
||||
* this does not help
|
||||
|
|
@ -200,9 +200,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
* interrupt does not get handled and Linux
|
||||
* complains loudly.
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk &= ~GINTSTS_SOF;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
|
||||
/*
|
||||
* Call callback function with spin lock
|
||||
|
|
@ -216,9 +216,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
hsotg->op_state = OTG_STATE_B_HOST;
|
||||
}
|
||||
} else {
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
|
||||
writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
dev_dbg(hsotg->dev, "HNP Failed\n");
|
||||
dev_err(hsotg->dev,
|
||||
"Device Not Connected/Responding\n");
|
||||
|
|
@ -244,9 +244,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
hsotg->op_state = OTG_STATE_A_PERIPHERAL;
|
||||
} else {
|
||||
/* Need to disable SOF interrupt immediately */
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk &= ~GINTSTS_SOF;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
spin_unlock(&hsotg->lock);
|
||||
dwc2_hcd_start(hsotg);
|
||||
spin_lock(&hsotg->lock);
|
||||
|
|
@ -261,7 +261,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
|
||||
|
||||
/* Clear GOTGINT */
|
||||
writel(gotgint, hsotg->regs + GOTGINT);
|
||||
dwc2_writel(gotgint, hsotg->regs + GOTGINT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -276,11 +276,11 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
u32 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
|
||||
/* Need to disable SOF interrupt immediately */
|
||||
gintmsk &= ~GINTSTS_SOF;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
|
||||
dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
|
||||
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
|
||||
|
|
@ -297,7 +297,7 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -313,16 +313,28 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
|
||||
int ret;
|
||||
|
||||
dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
|
||||
hsotg->lx_state);
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
|
||||
|
||||
/*
|
||||
* Report disconnect if there is any previous session established
|
||||
*/
|
||||
if (dwc2_is_device_mode(hsotg))
|
||||
s3c_hsotg_disconnect(hsotg);
|
||||
if (dwc2_is_device_mode(hsotg)) {
|
||||
if (hsotg->lx_state == DWC2_L2) {
|
||||
ret = dwc2_exit_hibernation(hsotg, true);
|
||||
if (ret && (ret != -ENOTSUPP))
|
||||
dev_err(hsotg->dev,
|
||||
"exit hibernation failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Report disconnect if there is any previous session
|
||||
* established
|
||||
*/
|
||||
dwc2_hsotg_disconnect(hsotg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -339,13 +351,14 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
|
||||
|
||||
if (dwc2_is_device_mode(hsotg)) {
|
||||
dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
|
||||
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
|
||||
dwc2_readl(hsotg->regs + DSTS));
|
||||
if (hsotg->lx_state == DWC2_L2) {
|
||||
u32 dctl = readl(hsotg->regs + DCTL);
|
||||
u32 dctl = dwc2_readl(hsotg->regs + DCTL);
|
||||
|
||||
/* Clear Remote Wakeup Signaling */
|
||||
dctl &= ~DCTL_RMTWKUPSIG;
|
||||
writel(dctl, hsotg->regs + DCTL);
|
||||
dwc2_writel(dctl, hsotg->regs + DCTL);
|
||||
ret = dwc2_exit_hibernation(hsotg, true);
|
||||
if (ret && (ret != -ENOTSUPP))
|
||||
dev_err(hsotg->dev, "exit hibernation failed\n");
|
||||
|
|
@ -355,12 +368,16 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||
/* Change to L0 state */
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
} else {
|
||||
if (hsotg->core_params->hibernation) {
|
||||
dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
|
||||
return;
|
||||
}
|
||||
if (hsotg->lx_state != DWC2_L1) {
|
||||
u32 pcgcctl = readl(hsotg->regs + PCGCTL);
|
||||
u32 pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
||||
|
||||
/* Restart the Phy Clock */
|
||||
pcgcctl &= ~PCGCTL_STOPPCLK;
|
||||
writel(pcgcctl, hsotg->regs + PCGCTL);
|
||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
||||
mod_timer(&hsotg->wkp_timer,
|
||||
jiffies + msecs_to_jiffies(71));
|
||||
} else {
|
||||
|
|
@ -370,7 +387,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -386,10 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
|
|||
if (hsotg->op_state == OTG_STATE_A_HOST)
|
||||
dwc2_hcd_disconnect(hsotg);
|
||||
|
||||
/* Change to L3 (OFF) state */
|
||||
hsotg->lx_state = DWC2_L3;
|
||||
|
||||
writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -412,7 +426,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|||
* Check the Device status register to determine if the Suspend
|
||||
* state is active
|
||||
*/
|
||||
dsts = readl(hsotg->regs + DSTS);
|
||||
dsts = dwc2_readl(hsotg->regs + DSTS);
|
||||
dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
|
||||
dev_dbg(hsotg->dev,
|
||||
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
|
||||
|
|
@ -465,7 +479,7 @@ skip_power_saving:
|
|||
|
||||
clear_int:
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
|
||||
|
|
@ -483,9 +497,9 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
|
|||
u32 gahbcfg;
|
||||
u32 gintmsk_common = GINTMSK_COMMON;
|
||||
|
||||
gintsts = readl(hsotg->regs + GINTSTS);
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gahbcfg = readl(hsotg->regs + GAHBCFG);
|
||||
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
|
||||
|
||||
/* If any common interrupts set */
|
||||
if (gintsts & gintmsk_common)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
|
|||
testmode = 0;
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
s3c_hsotg_set_test_mode(hsotg, testmode);
|
||||
dwc2_hsotg_set_test_mode(hsotg, testmode);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
return count;
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ static int testmode_show(struct seq_file *s, void *unused)
|
|||
int dctl;
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
dctl = readl(hsotg->regs + DCTL);
|
||||
dctl = dwc2_readl(hsotg->regs + DCTL);
|
||||
dctl &= DCTL_TSTCTL_MASK;
|
||||
dctl >>= DCTL_TSTCTL_SHIFT;
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
|
@ -137,38 +137,38 @@ static int state_show(struct seq_file *seq, void *v)
|
|||
int idx;
|
||||
|
||||
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
|
||||
readl(regs + DCFG),
|
||||
readl(regs + DCTL),
|
||||
readl(regs + DSTS));
|
||||
dwc2_readl(regs + DCFG),
|
||||
dwc2_readl(regs + DCTL),
|
||||
dwc2_readl(regs + DSTS));
|
||||
|
||||
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
|
||||
readl(regs + DIEPMSK), readl(regs + DOEPMSK));
|
||||
dwc2_readl(regs + DIEPMSK), dwc2_readl(regs + DOEPMSK));
|
||||
|
||||
seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
|
||||
readl(regs + GINTMSK),
|
||||
readl(regs + GINTSTS));
|
||||
dwc2_readl(regs + GINTMSK),
|
||||
dwc2_readl(regs + GINTSTS));
|
||||
|
||||
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
|
||||
readl(regs + DAINTMSK),
|
||||
readl(regs + DAINT));
|
||||
dwc2_readl(regs + DAINTMSK),
|
||||
dwc2_readl(regs + DAINT));
|
||||
|
||||
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
|
||||
readl(regs + GNPTXSTS),
|
||||
readl(regs + GRXSTSR));
|
||||
dwc2_readl(regs + GNPTXSTS),
|
||||
dwc2_readl(regs + GRXSTSR));
|
||||
|
||||
seq_puts(seq, "\nEndpoint status:\n");
|
||||
|
||||
for (idx = 0; idx < hsotg->num_of_eps; idx++) {
|
||||
u32 in, out;
|
||||
|
||||
in = readl(regs + DIEPCTL(idx));
|
||||
out = readl(regs + DOEPCTL(idx));
|
||||
in = dwc2_readl(regs + DIEPCTL(idx));
|
||||
out = dwc2_readl(regs + DOEPCTL(idx));
|
||||
|
||||
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
|
||||
idx, in, out);
|
||||
|
||||
in = readl(regs + DIEPTSIZ(idx));
|
||||
out = readl(regs + DOEPTSIZ(idx));
|
||||
in = dwc2_readl(regs + DIEPTSIZ(idx));
|
||||
out = dwc2_readl(regs + DOEPTSIZ(idx));
|
||||
|
||||
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
|
||||
in, out);
|
||||
|
|
@ -208,9 +208,9 @@ static int fifo_show(struct seq_file *seq, void *v)
|
|||
int idx;
|
||||
|
||||
seq_puts(seq, "Non-periodic FIFOs:\n");
|
||||
seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
|
||||
seq_printf(seq, "RXFIFO: Size %d\n", dwc2_readl(regs + GRXFSIZ));
|
||||
|
||||
val = readl(regs + GNPTXFSIZ);
|
||||
val = dwc2_readl(regs + GNPTXFSIZ);
|
||||
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
|
||||
val >> FIFOSIZE_DEPTH_SHIFT,
|
||||
val & FIFOSIZE_DEPTH_MASK);
|
||||
|
|
@ -218,7 +218,7 @@ static int fifo_show(struct seq_file *seq, void *v)
|
|||
seq_puts(seq, "\nPeriodic TXFIFOs:\n");
|
||||
|
||||
for (idx = 1; idx < hsotg->num_of_eps; idx++) {
|
||||
val = readl(regs + DPTXFSIZN(idx));
|
||||
val = dwc2_readl(regs + DPTXFSIZN(idx));
|
||||
|
||||
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
|
||||
val >> FIFOSIZE_DEPTH_SHIFT,
|
||||
|
|
@ -256,9 +256,9 @@ static const char *decode_direction(int is_in)
|
|||
*/
|
||||
static int ep_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct s3c_hsotg_ep *ep = seq->private;
|
||||
struct dwc2_hsotg_ep *ep = seq->private;
|
||||
struct dwc2_hsotg *hsotg = ep->parent;
|
||||
struct s3c_hsotg_req *req;
|
||||
struct dwc2_hsotg_req *req;
|
||||
void __iomem *regs = hsotg->regs;
|
||||
int index = ep->index;
|
||||
int show_limit = 15;
|
||||
|
|
@ -270,20 +270,20 @@ static int ep_show(struct seq_file *seq, void *v)
|
|||
/* first show the register state */
|
||||
|
||||
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
|
||||
readl(regs + DIEPCTL(index)),
|
||||
readl(regs + DOEPCTL(index)));
|
||||
dwc2_readl(regs + DIEPCTL(index)),
|
||||
dwc2_readl(regs + DOEPCTL(index)));
|
||||
|
||||
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
|
||||
readl(regs + DIEPDMA(index)),
|
||||
readl(regs + DOEPDMA(index)));
|
||||
dwc2_readl(regs + DIEPDMA(index)),
|
||||
dwc2_readl(regs + DOEPDMA(index)));
|
||||
|
||||
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
|
||||
readl(regs + DIEPINT(index)),
|
||||
readl(regs + DOEPINT(index)));
|
||||
dwc2_readl(regs + DIEPINT(index)),
|
||||
dwc2_readl(regs + DOEPINT(index)));
|
||||
|
||||
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
|
||||
readl(regs + DIEPTSIZ(index)),
|
||||
readl(regs + DOEPTSIZ(index)));
|
||||
dwc2_readl(regs + DIEPTSIZ(index)),
|
||||
dwc2_readl(regs + DOEPTSIZ(index)));
|
||||
|
||||
seq_puts(seq, "\n");
|
||||
seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
|
||||
|
|
@ -326,7 +326,7 @@ static const struct file_operations ep_fops = {
|
|||
};
|
||||
|
||||
/**
|
||||
* s3c_hsotg_create_debug - create debugfs directory and files
|
||||
* dwc2_hsotg_create_debug - create debugfs directory and files
|
||||
* @hsotg: The driver state
|
||||
*
|
||||
* Create the debugfs files to allow the user to get information
|
||||
|
|
@ -334,7 +334,7 @@ static const struct file_operations ep_fops = {
|
|||
* with the same name as the device itself, in case we end up
|
||||
* with multiple blocks in future systems.
|
||||
*/
|
||||
static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
|
||||
static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
|
|
@ -360,7 +360,7 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
|
|||
|
||||
/* Create one file for each out endpoint */
|
||||
for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
|
||||
struct s3c_hsotg_ep *ep;
|
||||
struct dwc2_hsotg_ep *ep;
|
||||
|
||||
ep = hsotg->eps_out[epidx];
|
||||
if (ep) {
|
||||
|
|
@ -373,7 +373,7 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
/* Create one file for each in endpoint. EP0 is handled with out eps */
|
||||
for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {
|
||||
struct s3c_hsotg_ep *ep;
|
||||
struct dwc2_hsotg_ep *ep;
|
||||
|
||||
ep = hsotg->eps_in[epidx];
|
||||
if (ep) {
|
||||
|
|
@ -386,10 +386,10 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
}
|
||||
#else
|
||||
static inline void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) {}
|
||||
#endif
|
||||
|
||||
/* s3c_hsotg_delete_debug is removed as cleanup in done in dwc2_debugfs_exit */
|
||||
/* dwc2_hsotg_delete_debug is removed as cleanup in done in dwc2_debugfs_exit */
|
||||
|
||||
#define dump_register(nm) \
|
||||
{ \
|
||||
|
|
@ -737,7 +737,7 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
|
||||
/* Add gadget debugfs nodes */
|
||||
s3c_hsotg_create_debug(hsotg);
|
||||
dwc2_hsotg_create_debug(hsotg);
|
||||
|
||||
hsotg->regset = devm_kzalloc(hsotg->dev, sizeof(*hsotg->regset),
|
||||
GFP_KERNEL);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -80,10 +80,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
|
|||
if (chan == NULL)
|
||||
return;
|
||||
|
||||
hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
|
||||
hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(chan->hc_num));
|
||||
hc_dma = readl(hsotg->regs + HCDMA(chan->hc_num));
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
|
||||
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chan->hc_num));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chan->hc_num));
|
||||
hc_dma = dwc2_readl(hsotg->regs + HCDMA(chan->hc_num));
|
||||
|
||||
dev_dbg(hsotg->dev, " Assigned to channel %p:\n", chan);
|
||||
dev_dbg(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n",
|
||||
|
|
@ -134,7 +134,7 @@ static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
|
|||
list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
|
||||
list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
|
||||
qtd_list_entry) {
|
||||
dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
|
||||
dwc2_host_complete(hsotg, qtd, -ECONNRESET);
|
||||
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
|
||||
}
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ void dwc2_hcd_start(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_RST;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
|
||||
|
|
@ -228,11 +228,11 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
|
|||
channel = hsotg->hc_ptr_array[i];
|
||||
if (!list_empty(&channel->hc_list_entry))
|
||||
continue;
|
||||
hcchar = readl(hsotg->regs + HCCHAR(i));
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
|
||||
if (hcchar & HCCHAR_CHENA) {
|
||||
hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
|
||||
hcchar |= HCCHAR_CHDIS;
|
||||
writel(hcchar, hsotg->regs + HCCHAR(i));
|
||||
dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -241,11 +241,11 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
|
|||
channel = hsotg->hc_ptr_array[i];
|
||||
if (!list_empty(&channel->hc_list_entry))
|
||||
continue;
|
||||
hcchar = readl(hsotg->regs + HCCHAR(i));
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
|
||||
if (hcchar & HCCHAR_CHENA) {
|
||||
/* Halt the channel */
|
||||
hcchar |= HCCHAR_CHDIS;
|
||||
writel(hcchar, hsotg->regs + HCCHAR(i));
|
||||
dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
|
||||
}
|
||||
|
||||
dwc2_hc_cleanup(hsotg, channel);
|
||||
|
|
@ -287,11 +287,11 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
|
|||
* interrupt mask and status bits and disabling subsequent host
|
||||
* channel interrupts.
|
||||
*/
|
||||
intr = readl(hsotg->regs + GINTMSK);
|
||||
intr = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
|
||||
writel(intr, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(intr, hsotg->regs + GINTMSK);
|
||||
intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
|
||||
writel(intr, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(intr, hsotg->regs + GINTSTS);
|
||||
|
||||
/*
|
||||
* Turn off the vbus power only if the core has transitioned to device
|
||||
|
|
@ -301,7 +301,7 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
|
|||
if (dwc2_is_device_mode(hsotg)) {
|
||||
if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
|
||||
dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
|
||||
writel(0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(0, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
dwc2_disable_host_interrupts(hsotg);
|
||||
|
|
@ -354,7 +354,7 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
|
|||
|
||||
/* Turn off the vbus power */
|
||||
dev_dbg(hsotg->dev, "PortPower off\n");
|
||||
writel(0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(0, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
/* Caller must hold driver lock */
|
||||
|
|
@ -378,7 +378,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
|
|||
if ((dev_speed == USB_SPEED_LOW) &&
|
||||
(hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
|
||||
(hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
|
||||
u32 hprt0 = readl(hsotg->regs + HPRT0);
|
||||
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
||||
u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
||||
|
||||
if (prtspd == HPRT0_SPD_FULL_SPEED)
|
||||
|
|
@ -397,7 +397,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
|
|||
return retval;
|
||||
}
|
||||
|
||||
intr_mask = readl(hsotg->regs + GINTMSK);
|
||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
if (!(intr_mask & GINTSTS_SOF)) {
|
||||
enum dwc2_transaction_type tr_type;
|
||||
|
||||
|
|
@ -1070,7 +1070,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
if (dbg_perio())
|
||||
dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
|
||||
|
||||
tx_status = readl(hsotg->regs + HPTXSTS);
|
||||
tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
|
||||
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
|
||||
TXSTS_QSPCAVAIL_SHIFT;
|
||||
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
|
||||
|
|
@ -1085,7 +1085,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
|
||||
qh_ptr = hsotg->periodic_sched_assigned.next;
|
||||
while (qh_ptr != &hsotg->periodic_sched_assigned) {
|
||||
tx_status = readl(hsotg->regs + HPTXSTS);
|
||||
tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
|
||||
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
|
||||
TXSTS_QSPCAVAIL_SHIFT;
|
||||
if (qspcavail == 0) {
|
||||
|
|
@ -1145,7 +1145,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
|
||||
if (hsotg->core_params->dma_enable <= 0) {
|
||||
tx_status = readl(hsotg->regs + HPTXSTS);
|
||||
tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
|
||||
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
|
||||
TXSTS_QSPCAVAIL_SHIFT;
|
||||
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
|
||||
|
|
@ -1168,9 +1168,9 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
* level to ensure that new requests are loaded as
|
||||
* soon as possible.)
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk |= GINTSTS_PTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
} else {
|
||||
/*
|
||||
* Disable the Tx FIFO empty interrupt since there are
|
||||
|
|
@ -1179,9 +1179,9 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
* handlers to queue more transactions as transfer
|
||||
* states change.
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk &= ~GINTSTS_PTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1210,7 +1210,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
|
||||
dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
|
||||
|
||||
tx_status = readl(hsotg->regs + GNPTXSTS);
|
||||
tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
|
||||
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
|
||||
TXSTS_QSPCAVAIL_SHIFT;
|
||||
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
|
||||
|
|
@ -1233,7 +1233,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
|
|||
* available in the request queue or the Tx FIFO
|
||||
*/
|
||||
do {
|
||||
tx_status = readl(hsotg->regs + GNPTXSTS);
|
||||
tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
|
||||
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
|
||||
TXSTS_QSPCAVAIL_SHIFT;
|
||||
if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
|
||||
|
|
@ -1270,7 +1270,7 @@ next:
|
|||
} while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
|
||||
|
||||
if (hsotg->core_params->dma_enable <= 0) {
|
||||
tx_status = readl(hsotg->regs + GNPTXSTS);
|
||||
tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
|
||||
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
|
||||
TXSTS_QSPCAVAIL_SHIFT;
|
||||
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
|
||||
|
|
@ -1290,9 +1290,9 @@ next:
|
|||
* level to ensure that new requests are loaded as
|
||||
* soon as possible.)
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk |= GINTSTS_NPTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
} else {
|
||||
/*
|
||||
* Disable the Tx FIFO empty interrupt since there are
|
||||
|
|
@ -1301,9 +1301,9 @@ next:
|
|||
* handlers to queue more transactions as transfer
|
||||
* states change.
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk &= ~GINTSTS_NPTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1341,10 +1341,10 @@ void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
|
|||
* Ensure NP Tx FIFO empty interrupt is disabled when
|
||||
* there are no non-periodic transfers to process
|
||||
*/
|
||||
u32 gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
u32 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
|
||||
gintmsk &= ~GINTSTS_NPTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1355,10 +1355,11 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
|
|||
wf_otg);
|
||||
u32 count = 0;
|
||||
u32 gotgctl;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s()\n", __func__);
|
||||
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
|
||||
dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
|
||||
!!(gotgctl & GOTGCTL_CONID_B));
|
||||
|
|
@ -1382,8 +1383,10 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
|
|||
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
dwc2_core_init(hsotg, false, -1);
|
||||
dwc2_enable_global_interrupts(hsotg);
|
||||
s3c_hsotg_core_init_disconnected(hsotg, false);
|
||||
s3c_hsotg_core_connect(hsotg);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
dwc2_hsotg_core_init_disconnected(hsotg, false);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
dwc2_hsotg_core_connect(hsotg);
|
||||
} else {
|
||||
/* A-Device connector (Host Mode) */
|
||||
dev_dbg(hsotg->dev, "connId A\n");
|
||||
|
|
@ -1421,10 +1424,11 @@ static void dwc2_wakeup_detected(unsigned long data)
|
|||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
|
||||
hprt0 &= ~HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
|
||||
readl(hsotg->regs + HPRT0));
|
||||
dwc2_readl(hsotg->regs + HPRT0));
|
||||
|
||||
hsotg->bus_suspended = 0;
|
||||
dwc2_hcd_rem_wakeup(hsotg);
|
||||
|
||||
/* Change to L0 state */
|
||||
|
|
@ -1451,30 +1455,35 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
|
|||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
|
||||
gotgctl = readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
||||
gotgctl |= GOTGCTL_HSTSETHNPEN;
|
||||
writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
||||
hsotg->op_state = OTG_STATE_A_SUSPEND;
|
||||
}
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_SUSP;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
|
||||
/* Update lx_state */
|
||||
hsotg->lx_state = DWC2_L2;
|
||||
hsotg->bus_suspended = 1;
|
||||
|
||||
/* Suspend the Phy Clock */
|
||||
pcgctl = readl(hsotg->regs + PCGCTL);
|
||||
pcgctl |= PCGCTL_STOPPCLK;
|
||||
writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
udelay(10);
|
||||
/*
|
||||
* If hibernation is supported, Phy clock will be suspended
|
||||
* after registers are backuped.
|
||||
*/
|
||||
if (!hsotg->core_params->hibernation) {
|
||||
/* Suspend the Phy Clock */
|
||||
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
|
||||
pcgctl |= PCGCTL_STOPPCLK;
|
||||
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/* For HNP the bus must be suspended for at least 200ms */
|
||||
if (dwc2_host_is_b_hnp_enabled(hsotg)) {
|
||||
pcgctl = readl(hsotg->regs + PCGCTL);
|
||||
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
|
||||
pcgctl &= ~PCGCTL_STOPPCLK;
|
||||
writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
|
|
@ -1484,6 +1493,44 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
|
|||
}
|
||||
}
|
||||
|
||||
/* Must NOT be called with interrupt disabled or spinlock held */
|
||||
static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 hprt0;
|
||||
u32 pcgctl;
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
/*
|
||||
* If hibernation is supported, Phy clock is already resumed
|
||||
* after registers restore.
|
||||
*/
|
||||
if (!hsotg->core_params->hibernation) {
|
||||
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
|
||||
pcgctl &= ~PCGCTL_STOPPCLK;
|
||||
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
usleep_range(20000, 40000);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
}
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_RES;
|
||||
hprt0 &= ~HPRT0_SUSP;
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
msleep(USB_RESUME_TIMEOUT);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
hsotg->bus_suspended = 0;
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
}
|
||||
|
||||
/* Handles hub class-specific requests */
|
||||
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||
u16 wvalue, u16 windex, char *buf, u16 wlength)
|
||||
|
|
@ -1523,23 +1570,15 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
"ClearPortFeature USB_PORT_FEAT_ENABLE\n");
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_ENA;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
break;
|
||||
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
dev_dbg(hsotg->dev,
|
||||
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
|
||||
writel(0, hsotg->regs + PCGCTL);
|
||||
usleep_range(20000, 40000);
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
hprt0 &= ~HPRT0_SUSP;
|
||||
msleep(USB_RESUME_TIMEOUT);
|
||||
|
||||
hprt0 &= ~HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
if (hsotg->bus_suspended)
|
||||
dwc2_port_resume(hsotg);
|
||||
break;
|
||||
|
||||
case USB_PORT_FEAT_POWER:
|
||||
|
|
@ -1547,7 +1586,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
"ClearPortFeature USB_PORT_FEAT_POWER\n");
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 &= ~HPRT0_PWR;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
break;
|
||||
|
||||
case USB_PORT_FEAT_INDICATOR:
|
||||
|
|
@ -1668,7 +1707,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
break;
|
||||
}
|
||||
|
||||
hprt0 = readl(hsotg->regs + HPRT0);
|
||||
hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
||||
dev_vdbg(hsotg->dev, " HPRT0: 0x%08x\n", hprt0);
|
||||
|
||||
if (hprt0 & HPRT0_CONNSTS)
|
||||
|
|
@ -1733,18 +1772,18 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
"SetPortFeature - USB_PORT_FEAT_POWER\n");
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_PWR;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
break;
|
||||
|
||||
case USB_PORT_FEAT_RESET:
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
dev_dbg(hsotg->dev,
|
||||
"SetPortFeature - USB_PORT_FEAT_RESET\n");
|
||||
pcgctl = readl(hsotg->regs + PCGCTL);
|
||||
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
|
||||
pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
|
||||
writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
/* ??? Original driver does this */
|
||||
writel(0, hsotg->regs + PCGCTL);
|
||||
dwc2_writel(0, hsotg->regs + PCGCTL);
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
/* Clear suspend bit if resetting from suspend state */
|
||||
|
|
@ -1759,13 +1798,13 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
hprt0 |= HPRT0_PWR | HPRT0_RST;
|
||||
dev_dbg(hsotg->dev,
|
||||
"In host mode, hprt0=%08x\n", hprt0);
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
|
||||
usleep_range(50000, 70000);
|
||||
hprt0 &= ~HPRT0_RST;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
hsotg->lx_state = DWC2_L0; /* Now back to On state */
|
||||
break;
|
||||
|
||||
|
|
@ -1781,7 +1820,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
"SetPortFeature - USB_PORT_FEAT_TEST\n");
|
||||
hprt0 &= ~HPRT0_TSTCTL_MASK;
|
||||
hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1838,7 +1877,7 @@ static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
|
|||
|
||||
int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 hfnum = readl(hsotg->regs + HFNUM);
|
||||
u32 hfnum = dwc2_readl(hsotg->regs + HFNUM);
|
||||
|
||||
#ifdef DWC2_DEBUG_SOF
|
||||
dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
|
||||
|
|
@ -1941,11 +1980,11 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
|
|||
if (chan->xfer_started) {
|
||||
u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
|
||||
|
||||
hfnum = readl(hsotg->regs + HFNUM);
|
||||
hcchar = readl(hsotg->regs + HCCHAR(i));
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(i));
|
||||
hcint = readl(hsotg->regs + HCINT(i));
|
||||
hcintmsk = readl(hsotg->regs + HCINTMSK(i));
|
||||
hfnum = dwc2_readl(hsotg->regs + HFNUM);
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(i));
|
||||
hcint = dwc2_readl(hsotg->regs + HCINT(i));
|
||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(i));
|
||||
dev_dbg(hsotg->dev, " hfnum: 0x%08x\n", hfnum);
|
||||
dev_dbg(hsotg->dev, " hcchar: 0x%08x\n", hcchar);
|
||||
dev_dbg(hsotg->dev, " hctsiz: 0x%08x\n", hctsiz);
|
||||
|
|
@ -1993,12 +2032,12 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
|
|||
dev_dbg(hsotg->dev, " periodic_channels: %d\n",
|
||||
hsotg->periodic_channels);
|
||||
dev_dbg(hsotg->dev, " periodic_usecs: %d\n", hsotg->periodic_usecs);
|
||||
np_tx_status = readl(hsotg->regs + GNPTXSTS);
|
||||
np_tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
|
||||
dev_dbg(hsotg->dev, " NP Tx Req Queue Space Avail: %d\n",
|
||||
(np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
|
||||
dev_dbg(hsotg->dev, " NP Tx FIFO Space Avail: %d\n",
|
||||
(np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
|
||||
p_tx_status = readl(hsotg->regs + HPTXSTS);
|
||||
p_tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
|
||||
dev_dbg(hsotg->dev, " P Tx Req Queue Space Avail: %d\n",
|
||||
(p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
|
||||
dev_dbg(hsotg->dev, " P Tx FIFO Space Avail: %d\n",
|
||||
|
|
@ -2194,11 +2233,6 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
|
|||
usb_pipein(urb->pipe) ? "IN" : "OUT", status,
|
||||
urb->actual_length);
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
|
||||
for (i = 0; i < urb->number_of_packets; i++)
|
||||
dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
|
||||
i, urb->iso_frame_desc[i].status);
|
||||
}
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
|
||||
urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
|
||||
|
|
@ -2211,6 +2245,12 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
|
|||
}
|
||||
}
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
|
||||
for (i = 0; i < urb->number_of_packets; i++)
|
||||
dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
|
||||
i, urb->iso_frame_desc[i].status);
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
if (!status) {
|
||||
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
|
||||
|
|
@ -2262,7 +2302,7 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
|
|||
dev_dbg(hsotg->dev, "USB RESET function called\n");
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 &= ~HPRT0_RST;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
hsotg->flags.b.port_reset_change = 1;
|
||||
}
|
||||
|
||||
|
|
@ -2286,8 +2326,9 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
|
|||
dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
if (dwc2_is_device_mode(hsotg)) {
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
|
@ -2316,8 +2357,19 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
|
|||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||
unsigned long flags;
|
||||
|
||||
/* Turn off all host-specific interrupts */
|
||||
dwc2_disable_host_interrupts(hsotg);
|
||||
|
||||
/* Wait for interrupt processing to finish */
|
||||
synchronize_irq(hcd->irq);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
/* Ensure hcd is disconnected */
|
||||
dwc2_hcd_disconnect(hsotg);
|
||||
dwc2_hcd_stop(hsotg);
|
||||
hsotg->lx_state = DWC2_L3;
|
||||
hcd->state = HC_STATE_HALT;
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
usleep_range(1000, 3000);
|
||||
|
|
@ -2326,17 +2378,125 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
|
|||
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
u32 hprt0;
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
if (hsotg->lx_state != DWC2_L0)
|
||||
goto unlock;
|
||||
|
||||
if (!HCD_HW_ACCESSIBLE(hcd))
|
||||
goto unlock;
|
||||
|
||||
if (!hsotg->core_params->hibernation)
|
||||
goto skip_power_saving;
|
||||
|
||||
/*
|
||||
* Drive USB suspend and disable port Power
|
||||
* if usb bus is not suspended.
|
||||
*/
|
||||
if (!hsotg->bus_suspended) {
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_SUSP;
|
||||
hprt0 &= ~HPRT0_PWR;
|
||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
/* Enter hibernation */
|
||||
ret = dwc2_enter_hibernation(hsotg);
|
||||
if (ret) {
|
||||
if (ret != -ENOTSUPP)
|
||||
dev_err(hsotg->dev,
|
||||
"enter hibernation failed\n");
|
||||
goto skip_power_saving;
|
||||
}
|
||||
|
||||
/* Ask phy to be suspended */
|
||||
if (!IS_ERR_OR_NULL(hsotg->uphy)) {
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
usb_phy_set_suspend(hsotg->uphy, true);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
}
|
||||
|
||||
/* After entering hibernation, hardware is no more accessible */
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
skip_power_saving:
|
||||
hsotg->lx_state = DWC2_L2;
|
||||
return 0;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
if (hsotg->lx_state != DWC2_L2)
|
||||
goto unlock;
|
||||
|
||||
if (!hsotg->core_params->hibernation) {
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set HW accessible bit before powering on the controller
|
||||
* since an interrupt may rise.
|
||||
*/
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/*
|
||||
* Enable power if not already done.
|
||||
* This must not be spinlocked since duration
|
||||
* of this call is unknown.
|
||||
*/
|
||||
if (!IS_ERR_OR_NULL(hsotg->uphy)) {
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
usb_phy_set_suspend(hsotg->uphy, false);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
}
|
||||
|
||||
/* Exit hibernation */
|
||||
ret = dwc2_exit_hibernation(hsotg, true);
|
||||
if (ret && (ret != -ENOTSUPP))
|
||||
dev_err(hsotg->dev, "exit hibernation failed\n");
|
||||
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
return 0;
|
||||
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
if (hsotg->bus_suspended) {
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
hsotg->flags.b.port_suspend_change = 1;
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
dwc2_port_resume(hsotg);
|
||||
} else {
|
||||
/* Wait for controller to correctly update D+/D- level */
|
||||
usleep_range(3000, 5000);
|
||||
|
||||
/*
|
||||
* Clear Port Enable and Port Status changes.
|
||||
* Enable Port Power.
|
||||
*/
|
||||
dwc2_writel(HPRT0_PWR | HPRT0_CONNDET |
|
||||
HPRT0_ENACHG, hsotg->regs + HPRT0);
|
||||
/* Wait for controller to detect Port Connect */
|
||||
usleep_range(5000, 7000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns the current frame number */
|
||||
|
|
@ -2790,17 +2950,17 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
|
|||
hsotg->status_buf = NULL;
|
||||
}
|
||||
|
||||
ahbcfg = readl(hsotg->regs + GAHBCFG);
|
||||
ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
|
||||
|
||||
/* Disable all interrupts */
|
||||
ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
|
||||
writel(ahbcfg, hsotg->regs + GAHBCFG);
|
||||
writel(0, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
|
||||
dwc2_writel(0, hsotg->regs + GINTMSK);
|
||||
|
||||
if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
|
||||
dctl = readl(hsotg->regs + DCTL);
|
||||
dctl = dwc2_readl(hsotg->regs + DCTL);
|
||||
dctl |= DCTL_SFTDISCON;
|
||||
writel(dctl, hsotg->regs + DCTL);
|
||||
dwc2_writel(dctl, hsotg->regs + DCTL);
|
||||
}
|
||||
|
||||
if (hsotg->wq_otg) {
|
||||
|
|
@ -2841,7 +3001,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
|
|||
|
||||
retval = -ENOMEM;
|
||||
|
||||
hcfg = readl(hsotg->regs + HCFG);
|
||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
||||
dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
|
||||
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
|
|
|
|||
|
|
@ -371,10 +371,10 @@ static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
|
||||
{
|
||||
u32 mask = readl(hsotg->regs + HCINTMSK(chnum));
|
||||
u32 mask = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
||||
|
||||
mask &= ~intr;
|
||||
writel(mask, hsotg->regs + HCINTMSK(chnum));
|
||||
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -382,11 +382,11 @@ static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
|
|||
*/
|
||||
static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
|
||||
return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
|
||||
}
|
||||
static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
|
||||
return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -395,7 +395,7 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 hprt0 = readl(hsotg->regs + HPRT0);
|
||||
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
||||
|
||||
hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
|
||||
return hprt0;
|
||||
|
|
@ -580,7 +580,8 @@ static inline u16 dwc2_micro_frame_num(u16 frame)
|
|||
*/
|
||||
static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
return readl(hsotg->regs + GINTSTS) & readl(hsotg->regs + GINTMSK);
|
||||
return dwc2_readl(hsotg->regs + GINTSTS) &
|
||||
dwc2_readl(hsotg->regs + GINTMSK);
|
||||
}
|
||||
|
||||
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
|
||||
|
|
@ -732,7 +733,7 @@ do { \
|
|||
qtd_list_entry); \
|
||||
if (usb_pipeint(_qtd_->urb->pipe) && \
|
||||
(_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
|
||||
_hfnum_.d32 = readl((_hcd_)->regs + HFNUM); \
|
||||
_hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
|
||||
switch (_hfnum_.b.frnum & 0x7) { \
|
||||
case 7: \
|
||||
(_hcd_)->hfnum_7_samples_##_letter_++; \
|
||||
|
|
|
|||
|
|
@ -169,19 +169,19 @@ static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
|
|||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
hcfg = readl(hsotg->regs + HCFG);
|
||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
||||
if (hcfg & HCFG_PERSCHEDENA) {
|
||||
/* already enabled */
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
|
||||
dwc2_writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
|
||||
|
||||
hcfg &= ~HCFG_FRLISTEN_MASK;
|
||||
hcfg |= fr_list_en | HCFG_PERSCHEDENA;
|
||||
dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
|
||||
writel(hcfg, hsotg->regs + HCFG);
|
||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
||||
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
|
|||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
hcfg = readl(hsotg->regs + HCFG);
|
||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
||||
if (!(hcfg & HCFG_PERSCHEDENA)) {
|
||||
/* already disabled */
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
|
@ -202,7 +202,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
|
|||
|
||||
hcfg &= ~HCFG_PERSCHEDENA;
|
||||
dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
|
||||
writel(hcfg, hsotg->regs + HCFG);
|
||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
||||
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
|
|||
dwc2_hcd_queue_transactions(hsotg, tr_type);
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
|
||||
dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -164,7 +164,7 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
|
|||
if (dbg_perio())
|
||||
dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
|
||||
|
||||
grxsts = readl(hsotg->regs + GRXSTSP);
|
||||
grxsts = dwc2_readl(hsotg->regs + GRXSTSP);
|
||||
chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
|
||||
chan = hsotg->hc_ptr_array[chnum];
|
||||
if (!chan) {
|
||||
|
|
@ -247,11 +247,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||
dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
|
||||
|
||||
/* Every time when port enables calculate HFIR.FrInterval */
|
||||
hfir = readl(hsotg->regs + HFIR);
|
||||
hfir = dwc2_readl(hsotg->regs + HFIR);
|
||||
hfir &= ~HFIR_FRINT_MASK;
|
||||
hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
|
||||
HFIR_FRINT_MASK;
|
||||
writel(hfir, hsotg->regs + HFIR);
|
||||
dwc2_writel(hfir, hsotg->regs + HFIR);
|
||||
|
||||
/* Check if we need to adjust the PHY clock speed for low power */
|
||||
if (!params->host_support_fs_ls_low_power) {
|
||||
|
|
@ -260,7 +260,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||
return;
|
||||
}
|
||||
|
||||
usbcfg = readl(hsotg->regs + GUSBCFG);
|
||||
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
|
||||
prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
||||
|
||||
if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
|
||||
|
|
@ -268,11 +268,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||
if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
|
||||
/* Set PHY low power clock select for FS/LS devices */
|
||||
usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
|
||||
writel(usbcfg, hsotg->regs + GUSBCFG);
|
||||
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
|
||||
do_reset = 1;
|
||||
}
|
||||
|
||||
hcfg = readl(hsotg->regs + HCFG);
|
||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
||||
fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
|
||||
HCFG_FSLSPCLKSEL_SHIFT;
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||
fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
|
||||
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
|
||||
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
|
||||
writel(hcfg, hsotg->regs + HCFG);
|
||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
||||
do_reset = 1;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -297,7 +297,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||
fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
|
||||
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
|
||||
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
|
||||
writel(hcfg, hsotg->regs + HCFG);
|
||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
||||
do_reset = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -305,7 +305,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||
/* Not low power */
|
||||
if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
|
||||
usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
|
||||
writel(usbcfg, hsotg->regs + GUSBCFG);
|
||||
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
|
||||
do_reset = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -332,7 +332,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
|||
|
||||
dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
|
||||
|
||||
hprt0 = readl(hsotg->regs + HPRT0);
|
||||
hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
||||
hprt0_modify = hprt0;
|
||||
|
||||
/*
|
||||
|
|
@ -388,7 +388,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
|||
}
|
||||
|
||||
/* Clear Port Interrupts */
|
||||
writel(hprt0_modify, hsotg->regs + HPRT0);
|
||||
dwc2_writel(hprt0_modify, hsotg->regs + HPRT0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -408,7 +408,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
|
|||
{
|
||||
u32 hctsiz, count, length;
|
||||
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
|
||||
if (halt_status == DWC2_HC_XFER_COMPLETE) {
|
||||
if (chan->ep_is_in) {
|
||||
|
|
@ -491,7 +491,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
|
|||
urb->status = 0;
|
||||
}
|
||||
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
|
||||
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
|
||||
dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len);
|
||||
|
|
@ -514,7 +514,7 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
|
|||
struct dwc2_host_chan *chan, int chnum,
|
||||
struct dwc2_qtd *qtd)
|
||||
{
|
||||
u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
|
||||
|
||||
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
|
||||
|
|
@ -771,9 +771,9 @@ cleanup:
|
|||
}
|
||||
}
|
||||
|
||||
haintmsk = readl(hsotg->regs + HAINTMSK);
|
||||
haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
|
||||
haintmsk &= ~(1 << chan->hc_num);
|
||||
writel(haintmsk, hsotg->regs + HAINTMSK);
|
||||
dwc2_writel(haintmsk, hsotg->regs + HAINTMSK);
|
||||
|
||||
/* Try to queue more transfers now that there's a free channel */
|
||||
tr_type = dwc2_hcd_select_transactions(hsotg);
|
||||
|
|
@ -820,9 +820,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
|
|||
* is enabled so that the non-periodic schedule will
|
||||
* be processed
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk |= GINTSTS_NPTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
} else {
|
||||
dev_vdbg(hsotg->dev, "isoc/intr\n");
|
||||
/*
|
||||
|
|
@ -839,9 +839,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
|
|||
* enabled so that the periodic schedule will be
|
||||
* processed
|
||||
*/
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
gintmsk |= GINTSTS_PTXFEMP;
|
||||
writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -906,7 +906,7 @@ static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
|
|||
struct dwc2_qtd *qtd,
|
||||
enum dwc2_halt_status halt_status)
|
||||
{
|
||||
u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
|
||||
qtd->error_count = 0;
|
||||
|
||||
|
|
@ -1184,7 +1184,7 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
|
|||
|
||||
urb->actual_length += xfer_length;
|
||||
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
|
||||
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
|
||||
dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n",
|
||||
|
|
@ -1505,10 +1505,10 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
|
|||
|
||||
dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
|
||||
|
||||
hcchar = readl(hsotg->regs + HCCHAR(chnum));
|
||||
hcsplt = readl(hsotg->regs + HCSPLT(chnum));
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hc_dma = readl(hsotg->regs + HCDMA(chnum));
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
|
||||
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hc_dma = dwc2_readl(hsotg->regs + HCDMA(chnum));
|
||||
|
||||
dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
|
||||
dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
|
||||
|
|
@ -1721,10 +1721,10 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
|
|||
* This code is here only as a check. This condition should
|
||||
* never happen. Ignore the halt if it does occur.
|
||||
*/
|
||||
hcchar = readl(hsotg->regs + HCCHAR(chnum));
|
||||
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
|
||||
hcsplt = readl(hsotg->regs + HCSPLT(chnum));
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
||||
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
|
||||
dev_dbg(hsotg->dev,
|
||||
"%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
|
||||
__func__);
|
||||
|
|
@ -1748,7 +1748,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
|
|||
* when the halt interrupt occurs. Halt the channel again if it does
|
||||
* occur.
|
||||
*/
|
||||
hcchar = readl(hsotg->regs + HCCHAR(chnum));
|
||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
|
||||
if (hcchar & HCCHAR_CHDIS) {
|
||||
dev_warn(hsotg->dev,
|
||||
"%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
|
||||
|
|
@ -1808,7 +1808,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
|
|||
return;
|
||||
}
|
||||
|
||||
hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
|
||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
||||
|
||||
if (chan->hcint & HCINTMSK_XFERCOMPL) {
|
||||
/*
|
||||
|
|
@ -1903,7 +1903,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
|
|||
dev_err(hsotg->dev,
|
||||
"hcint 0x%08x, intsts 0x%08x\n",
|
||||
chan->hcint,
|
||||
readl(hsotg->regs + GINTSTS));
|
||||
dwc2_readl(hsotg->regs + GINTSTS));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
|
@ -1949,6 +1949,24 @@ static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the given qtd is still the top of the list (and thus valid).
|
||||
*
|
||||
* If dwc2_hcd_qtd_unlink_and_free() has been called since we grabbed
|
||||
* the qtd from the top of the list, this will return false (otherwise true).
|
||||
*/
|
||||
static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh)
|
||||
{
|
||||
struct dwc2_qtd *cur_head;
|
||||
|
||||
if (qh == NULL)
|
||||
return false;
|
||||
|
||||
cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd,
|
||||
qtd_list_entry);
|
||||
return (cur_head == qtd);
|
||||
}
|
||||
|
||||
/* Handles interrupt for a specific Host Channel */
|
||||
static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
||||
{
|
||||
|
|
@ -1958,11 +1976,11 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|||
|
||||
chan = hsotg->hc_ptr_array[chnum];
|
||||
|
||||
hcint = readl(hsotg->regs + HCINT(chnum));
|
||||
hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
|
||||
hcint = dwc2_readl(hsotg->regs + HCINT(chnum));
|
||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
||||
if (!chan) {
|
||||
dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
|
||||
writel(hcint, hsotg->regs + HCINT(chnum));
|
||||
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1974,7 +1992,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|||
hcint, hcintmsk, hcint & hcintmsk);
|
||||
}
|
||||
|
||||
writel(hcint, hsotg->regs + HCINT(chnum));
|
||||
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
|
||||
chan->hcint = hcint;
|
||||
hcint &= hcintmsk;
|
||||
|
||||
|
|
@ -2031,27 +2049,59 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|||
*/
|
||||
hcint &= ~HCINTMSK_NYET;
|
||||
}
|
||||
if (hcint & HCINTMSK_CHHLTD)
|
||||
dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_AHBERR)
|
||||
dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_STALL)
|
||||
dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_NAK)
|
||||
dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_ACK)
|
||||
dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_NYET)
|
||||
dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_XACTERR)
|
||||
dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_BBLERR)
|
||||
dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_FRMOVRUN)
|
||||
dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
|
||||
if (hcint & HCINTMSK_DATATGLERR)
|
||||
dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
|
||||
|
||||
if (hcint & HCINTMSK_CHHLTD) {
|
||||
dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_AHBERR) {
|
||||
dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_STALL) {
|
||||
dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_NAK) {
|
||||
dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_ACK) {
|
||||
dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_NYET) {
|
||||
dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_XACTERR) {
|
||||
dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_BBLERR) {
|
||||
dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_FRMOVRUN) {
|
||||
dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
if (hcint & HCINTMSK_DATATGLERR) {
|
||||
dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
|
||||
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
chan->hcint = 0;
|
||||
}
|
||||
|
||||
|
|
@ -2066,7 +2116,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
|
|||
u32 haint;
|
||||
int i;
|
||||
|
||||
haint = readl(hsotg->regs + HAINT);
|
||||
haint = dwc2_readl(hsotg->regs + HAINT);
|
||||
if (dbg_perio()) {
|
||||
dev_vdbg(hsotg->dev, "%s()\n", __func__);
|
||||
|
||||
|
|
@ -2134,8 +2184,8 @@ irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
|
|||
"DWC OTG HCD Finished Servicing Interrupts\n");
|
||||
dev_vdbg(hsotg->dev,
|
||||
"DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
|
||||
readl(hsotg->regs + GINTSTS),
|
||||
readl(hsotg->regs + GINTMSK));
|
||||
dwc2_readl(hsotg->regs + GINTSTS),
|
||||
dwc2_readl(hsotg->regs + GINTMSK));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
|||
USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
|
||||
qh->ep_type == USB_ENDPOINT_XFER_ISOC,
|
||||
bytecount));
|
||||
|
||||
/* Ensure frame_number corresponds to the reality */
|
||||
hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
|
||||
/* Start in a slightly future (micro)frame */
|
||||
qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
|
||||
SCHEDULE_SLOP);
|
||||
|
|
@ -115,7 +118,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
|||
if (qh->ep_type == USB_ENDPOINT_XFER_INT)
|
||||
qh->interval = 8;
|
||||
#endif
|
||||
hprt = readl(hsotg->regs + HPRT0);
|
||||
hprt = dwc2_readl(hsotg->regs + HPRT0);
|
||||
prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
||||
if (prtspd == HPRT0_SPD_HIGH_SPEED &&
|
||||
(dev_speed == USB_SPEED_LOW ||
|
||||
|
|
@ -583,6 +586,14 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
|||
/* QH already in a schedule */
|
||||
return 0;
|
||||
|
||||
if (!dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number) &&
|
||||
!hsotg->frame_number) {
|
||||
dev_dbg(hsotg->dev,
|
||||
"reset frame number counter\n");
|
||||
qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
|
||||
SCHEDULE_SLOP);
|
||||
}
|
||||
|
||||
/* Add the new QH to the appropriate schedule */
|
||||
if (dwc2_qh_is_non_per(qh)) {
|
||||
/* Always start in inactive schedule */
|
||||
|
|
@ -595,9 +606,9 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
|||
if (status)
|
||||
return status;
|
||||
if (!hsotg->periodic_qh_count) {
|
||||
intr_mask = readl(hsotg->regs + GINTMSK);
|
||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
intr_mask |= GINTSTS_SOF;
|
||||
writel(intr_mask, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
|
||||
}
|
||||
hsotg->periodic_qh_count++;
|
||||
|
||||
|
|
@ -632,9 +643,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
|||
dwc2_deschedule_periodic(hsotg, qh);
|
||||
hsotg->periodic_qh_count--;
|
||||
if (!hsotg->periodic_qh_count) {
|
||||
intr_mask = readl(hsotg->regs + GINTMSK);
|
||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
intr_mask &= ~GINTSTS_SOF;
|
||||
writel(intr_mask, hsotg->regs + GINTMSK);
|
||||
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@
|
|||
#define GINTSTS_RESETDET (1 << 23)
|
||||
#define GINTSTS_FET_SUSP (1 << 22)
|
||||
#define GINTSTS_INCOMPL_IP (1 << 21)
|
||||
#define GINTSTS_INCOMPL_SOOUT (1 << 21)
|
||||
#define GINTSTS_INCOMPL_SOIN (1 << 20)
|
||||
#define GINTSTS_OEPINT (1 << 19)
|
||||
#define GINTSTS_IEPINT (1 << 18)
|
||||
|
|
|
|||
|
|
@ -37,11 +37,14 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_data/s3c-hsotg.h>
|
||||
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
|
|
@ -111,6 +114,145 @@ static const struct dwc2_core_params params_rk3066 = {
|
|||
.hibernation = -1,
|
||||
};
|
||||
|
||||
static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(hsotg->dev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
|
||||
hsotg->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(hsotg->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hsotg->uphy)
|
||||
ret = usb_phy_init(hsotg->uphy);
|
||||
else if (hsotg->plat && hsotg->plat->phy_init)
|
||||
ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
|
||||
else {
|
||||
ret = phy_power_on(hsotg->phy);
|
||||
if (ret == 0)
|
||||
ret = phy_init(hsotg->phy);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources
|
||||
* @hsotg: The driver state
|
||||
*
|
||||
* A wrapper for platform code responsible for controlling
|
||||
* low-level USB platform resources (phy, clock, regulators)
|
||||
*/
|
||||
int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
int ret = __dwc2_lowlevel_hw_enable(hsotg);
|
||||
|
||||
if (ret == 0)
|
||||
hsotg->ll_hw_enabled = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(hsotg->dev);
|
||||
int ret = 0;
|
||||
|
||||
if (hsotg->uphy)
|
||||
usb_phy_shutdown(hsotg->uphy);
|
||||
else if (hsotg->plat && hsotg->plat->phy_exit)
|
||||
ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
|
||||
else {
|
||||
ret = phy_exit(hsotg->phy);
|
||||
if (ret == 0)
|
||||
ret = phy_power_off(hsotg->phy);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_disable_unprepare(hsotg->clk);
|
||||
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
|
||||
hsotg->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources
|
||||
* @hsotg: The driver state
|
||||
*
|
||||
* A wrapper for platform code responsible for controlling
|
||||
* low-level USB platform resources (phy, clock, regulators)
|
||||
*/
|
||||
int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
int ret = __dwc2_lowlevel_hw_disable(hsotg);
|
||||
|
||||
if (ret == 0)
|
||||
hsotg->ll_hw_enabled = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/* Set default UTMI width */
|
||||
hsotg->phyif = GUSBCFG_PHYIF16;
|
||||
|
||||
/*
|
||||
* Attempt to find a generic PHY, then look for an old style
|
||||
* USB PHY and then fall back to pdata
|
||||
*/
|
||||
hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
|
||||
if (IS_ERR(hsotg->phy)) {
|
||||
hsotg->phy = NULL;
|
||||
hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR(hsotg->uphy))
|
||||
hsotg->uphy = NULL;
|
||||
else
|
||||
hsotg->plat = dev_get_platdata(hsotg->dev);
|
||||
}
|
||||
|
||||
if (hsotg->phy) {
|
||||
/*
|
||||
* If using the generic PHY framework, check if the PHY bus
|
||||
* width is 8-bit and set the phyif appropriately.
|
||||
*/
|
||||
if (phy_get_bus_width(hsotg->phy) == 8)
|
||||
hsotg->phyif = GUSBCFG_PHYIF8;
|
||||
}
|
||||
|
||||
if (!hsotg->phy && !hsotg->uphy && !hsotg->plat) {
|
||||
dev_err(hsotg->dev, "no platform data or transceiver defined\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
/* Clock */
|
||||
hsotg->clk = devm_clk_get(hsotg->dev, "otg");
|
||||
if (IS_ERR(hsotg->clk)) {
|
||||
hsotg->clk = NULL;
|
||||
dev_dbg(hsotg->dev, "cannot get otg clock\n");
|
||||
}
|
||||
|
||||
/* Regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
|
||||
hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
|
||||
hsotg->supplies);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
|
||||
* DWC_otg driver
|
||||
|
|
@ -130,7 +272,10 @@ static int dwc2_driver_remove(struct platform_device *dev)
|
|||
if (hsotg->hcd_enabled)
|
||||
dwc2_hcd_remove(hsotg);
|
||||
if (hsotg->gadget_enabled)
|
||||
s3c_hsotg_remove(hsotg);
|
||||
dwc2_hsotg_remove(hsotg);
|
||||
|
||||
if (hsotg->ll_hw_enabled)
|
||||
dwc2_lowlevel_hw_disable(hsotg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -163,8 +308,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
struct dwc2_core_params defparams;
|
||||
struct dwc2_hsotg *hsotg;
|
||||
struct resource *res;
|
||||
struct phy *phy;
|
||||
struct usb_phy *uphy;
|
||||
int retval;
|
||||
int irq;
|
||||
|
||||
|
|
@ -220,34 +363,25 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
|
||||
(unsigned long)res->start, hsotg->regs);
|
||||
|
||||
hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
|
||||
|
||||
/*
|
||||
* Attempt to find a generic PHY, then look for an old style
|
||||
* USB PHY
|
||||
*/
|
||||
phy = devm_phy_get(&dev->dev, "usb2-phy");
|
||||
if (IS_ERR(phy)) {
|
||||
hsotg->phy = NULL;
|
||||
uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR(uphy))
|
||||
hsotg->uphy = NULL;
|
||||
else
|
||||
hsotg->uphy = uphy;
|
||||
} else {
|
||||
hsotg->phy = phy;
|
||||
phy_power_on(hsotg->phy);
|
||||
phy_init(hsotg->phy);
|
||||
hsotg->dr_mode = usb_get_dr_mode(&dev->dev);
|
||||
if (IS_ENABLED(CONFIG_USB_DWC2_HOST) &&
|
||||
hsotg->dr_mode != USB_DR_MODE_HOST) {
|
||||
hsotg->dr_mode = USB_DR_MODE_HOST;
|
||||
dev_warn(hsotg->dev,
|
||||
"Configuration mismatch. Forcing host mode\n");
|
||||
} else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) &&
|
||||
hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
|
||||
hsotg->dr_mode = USB_DR_MODE_PERIPHERAL;
|
||||
dev_warn(hsotg->dev,
|
||||
"Configuration mismatch. Forcing peripheral mode\n");
|
||||
}
|
||||
|
||||
spin_lock_init(&hsotg->lock);
|
||||
mutex_init(&hsotg->init_mutex);
|
||||
|
||||
/* Detect config values from hardware */
|
||||
retval = dwc2_get_hwparams(hsotg);
|
||||
retval = dwc2_lowlevel_hw_init(hsotg);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
spin_lock_init(&hsotg->lock);
|
||||
|
||||
hsotg->core_params = devm_kzalloc(&dev->dev,
|
||||
sizeof(*hsotg->core_params), GFP_KERNEL);
|
||||
if (!hsotg->core_params)
|
||||
|
|
@ -255,13 +389,22 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
|
||||
dwc2_set_all_params(hsotg->core_params, -1);
|
||||
|
||||
retval = dwc2_lowlevel_hw_enable(hsotg);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Detect config values from hardware */
|
||||
retval = dwc2_get_hwparams(hsotg);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
/* Validate parameter values */
|
||||
dwc2_set_parameters(hsotg, params);
|
||||
|
||||
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
|
||||
retval = dwc2_gadget_init(hsotg, irq);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
hsotg->gadget_enabled = 1;
|
||||
}
|
||||
|
||||
|
|
@ -269,8 +412,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
retval = dwc2_hcd_init(hsotg, irq);
|
||||
if (retval) {
|
||||
if (hsotg->gadget_enabled)
|
||||
s3c_hsotg_remove(hsotg);
|
||||
return retval;
|
||||
dwc2_hsotg_remove(hsotg);
|
||||
goto error;
|
||||
}
|
||||
hsotg->hcd_enabled = 1;
|
||||
}
|
||||
|
|
@ -279,6 +422,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
|
||||
dwc2_debugfs_init(hsotg);
|
||||
|
||||
/* Gadget code manages lowlevel hw on its own */
|
||||
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
|
||||
dwc2_lowlevel_hw_disable(hsotg);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
dwc2_lowlevel_hw_disable(hsotg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -287,15 +438,12 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
|
|||
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (dwc2_is_device_mode(dwc2)) {
|
||||
ret = s3c_hsotg_suspend(dwc2);
|
||||
} else {
|
||||
if (dwc2->lx_state == DWC2_L0)
|
||||
return 0;
|
||||
phy_exit(dwc2->phy);
|
||||
phy_power_off(dwc2->phy);
|
||||
if (dwc2_is_device_mode(dwc2))
|
||||
dwc2_hsotg_suspend(dwc2);
|
||||
|
||||
if (dwc2->ll_hw_enabled)
|
||||
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -304,13 +452,15 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|||
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (dwc2_is_device_mode(dwc2)) {
|
||||
ret = s3c_hsotg_resume(dwc2);
|
||||
} else {
|
||||
phy_power_on(dwc2->phy);
|
||||
phy_init(dwc2->phy);
|
||||
|
||||
if (dwc2->ll_hw_enabled) {
|
||||
ret = __dwc2_lowlevel_hw_enable(dwc2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dwc2_is_device_mode(dwc2))
|
||||
ret = dwc2_hsotg_resume(dwc2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
|
@ -143,6 +144,32 @@ static int dwc3_soft_reset(struct dwc3 *dwc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc3_frame_length_adjustment - Adjusts frame length if required
|
||||
* @dwc3: Pointer to our controller context structure
|
||||
* @fladj: Value of GFLADJ_30MHZ to adjust frame length
|
||||
*/
|
||||
static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
|
||||
{
|
||||
u32 reg;
|
||||
u32 dft;
|
||||
|
||||
if (dwc->revision < DWC3_REVISION_250A)
|
||||
return;
|
||||
|
||||
if (fladj == 0)
|
||||
return;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
|
||||
dft = reg & DWC3_GFLADJ_30MHZ_MASK;
|
||||
if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
|
||||
"request value same as default, ignoring\n")) {
|
||||
reg &= ~DWC3_GFLADJ_30MHZ_MASK;
|
||||
reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
|
||||
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_free_one_event_buffer - Frees one event buffer
|
||||
* @dwc: Pointer to our controller context structure
|
||||
|
|
@ -488,6 +515,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
|||
if (dwc->dis_u2_susphy_quirk)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
if (dwc->dis_enblslpm_quirk)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
return 0;
|
||||
|
|
@ -507,12 +537,18 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
|
||||
/* This should read as U3 followed by revision number */
|
||||
if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
|
||||
if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
|
||||
/* Detected DWC_usb3 IP */
|
||||
dwc->revision = reg;
|
||||
} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
|
||||
/* Detected DWC_usb31 IP */
|
||||
dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
|
||||
dwc->revision |= DWC3_REVISION_IS_DWC31;
|
||||
} else {
|
||||
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
|
||||
ret = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
dwc->revision = reg;
|
||||
|
||||
/*
|
||||
* Write Linux Version Code to our GUID register so it's easy to figure
|
||||
|
|
@ -773,12 +809,12 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dwc3_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct device_node *node = dev->of_node;
|
||||
struct resource *res;
|
||||
struct dwc3 *dwc;
|
||||
u8 lpm_nyet_threshold;
|
||||
u8 tx_de_emphasis;
|
||||
u8 hird_threshold;
|
||||
u32 fladj = 0;
|
||||
|
||||
int ret;
|
||||
|
||||
|
|
@ -842,51 +878,56 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
*/
|
||||
hird_threshold = 12;
|
||||
|
||||
if (node) {
|
||||
dwc->maximum_speed = of_usb_get_maximum_speed(node);
|
||||
dwc->has_lpm_erratum = of_property_read_bool(node,
|
||||
dwc->maximum_speed = usb_get_maximum_speed(dev);
|
||||
dwc->dr_mode = usb_get_dr_mode(dev);
|
||||
|
||||
dwc->has_lpm_erratum = device_property_read_bool(dev,
|
||||
"snps,has-lpm-erratum");
|
||||
of_property_read_u8(node, "snps,lpm-nyet-threshold",
|
||||
device_property_read_u8(dev, "snps,lpm-nyet-threshold",
|
||||
&lpm_nyet_threshold);
|
||||
dwc->is_utmi_l1_suspend = of_property_read_bool(node,
|
||||
dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
|
||||
"snps,is-utmi-l1-suspend");
|
||||
of_property_read_u8(node, "snps,hird-threshold",
|
||||
device_property_read_u8(dev, "snps,hird-threshold",
|
||||
&hird_threshold);
|
||||
dwc->usb3_lpm_capable = of_property_read_bool(node,
|
||||
dwc->usb3_lpm_capable = device_property_read_bool(dev,
|
||||
"snps,usb3_lpm_capable");
|
||||
|
||||
dwc->needs_fifo_resize = of_property_read_bool(node,
|
||||
dwc->needs_fifo_resize = device_property_read_bool(dev,
|
||||
"tx-fifo-resize");
|
||||
dwc->dr_mode = of_usb_get_dr_mode(node);
|
||||
|
||||
dwc->disable_scramble_quirk = of_property_read_bool(node,
|
||||
dwc->disable_scramble_quirk = device_property_read_bool(dev,
|
||||
"snps,disable_scramble_quirk");
|
||||
dwc->u2exit_lfps_quirk = of_property_read_bool(node,
|
||||
dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
|
||||
"snps,u2exit_lfps_quirk");
|
||||
dwc->u2ss_inp3_quirk = of_property_read_bool(node,
|
||||
dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
|
||||
"snps,u2ss_inp3_quirk");
|
||||
dwc->req_p1p2p3_quirk = of_property_read_bool(node,
|
||||
dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
|
||||
"snps,req_p1p2p3_quirk");
|
||||
dwc->del_p1p2p3_quirk = of_property_read_bool(node,
|
||||
dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
|
||||
"snps,del_p1p2p3_quirk");
|
||||
dwc->del_phy_power_chg_quirk = of_property_read_bool(node,
|
||||
dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
|
||||
"snps,del_phy_power_chg_quirk");
|
||||
dwc->lfps_filter_quirk = of_property_read_bool(node,
|
||||
dwc->lfps_filter_quirk = device_property_read_bool(dev,
|
||||
"snps,lfps_filter_quirk");
|
||||
dwc->rx_detect_poll_quirk = of_property_read_bool(node,
|
||||
dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
|
||||
"snps,rx_detect_poll_quirk");
|
||||
dwc->dis_u3_susphy_quirk = of_property_read_bool(node,
|
||||
dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_u3_susphy_quirk");
|
||||
dwc->dis_u2_susphy_quirk = of_property_read_bool(node,
|
||||
dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_u2_susphy_quirk");
|
||||
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_enblslpm_quirk");
|
||||
|
||||
dwc->tx_de_emphasis_quirk = of_property_read_bool(node,
|
||||
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
||||
"snps,tx_de_emphasis_quirk");
|
||||
of_property_read_u8(node, "snps,tx_de_emphasis",
|
||||
device_property_read_u8(dev, "snps,tx_de_emphasis",
|
||||
&tx_de_emphasis);
|
||||
of_property_read_string(node, "snps,hsphy_interface",
|
||||
&dwc->hsphy_interface);
|
||||
} else if (pdata) {
|
||||
device_property_read_string(dev, "snps,hsphy_interface",
|
||||
&dwc->hsphy_interface);
|
||||
device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
|
||||
&fladj);
|
||||
|
||||
if (pdata) {
|
||||
dwc->maximum_speed = pdata->maximum_speed;
|
||||
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
|
||||
if (pdata->lpm_nyet_threshold)
|
||||
|
|
@ -909,12 +950,14 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
|
||||
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
|
||||
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
|
||||
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
|
||||
|
||||
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
|
||||
if (pdata->tx_de_emphasis)
|
||||
tx_de_emphasis = pdata->tx_de_emphasis;
|
||||
|
||||
dwc->hsphy_interface = pdata->hsphy_interface;
|
||||
fladj = pdata->fladj_value;
|
||||
}
|
||||
|
||||
/* default to superspeed if no maximum_speed passed */
|
||||
|
|
@ -971,6 +1014,9 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
/* Adjust Frame Length */
|
||||
dwc3_frame_length_adjustment(dwc, fladj);
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||
ret = phy_power_on(dwc->usb2_generic_phy);
|
||||
|
|
@ -1091,6 +1137,8 @@ static int dwc3_suspend(struct device *dev)
|
|||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1100,6 +1148,8 @@ static int dwc3_resume(struct device *dev)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
usb_phy_init(dwc->usb3_phy);
|
||||
usb_phy_init(dwc->usb2_phy);
|
||||
ret = phy_init(dwc->usb2_generic_phy);
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@
|
|||
#define DWC3_GPRTBIMAP_FS0 0xc188
|
||||
#define DWC3_GPRTBIMAP_FS1 0xc18c
|
||||
|
||||
#define DWC3_VER_NUMBER 0xc1a0
|
||||
#define DWC3_VER_TYPE 0xc1a4
|
||||
|
||||
#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
|
||||
#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
|
||||
|
||||
|
|
@ -124,6 +127,7 @@
|
|||
#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
|
||||
|
||||
#define DWC3_GHWPARAMS8 0xc600
|
||||
#define DWC3_GFLADJ 0xc630
|
||||
|
||||
/* Device Registers */
|
||||
#define DWC3_DCFG 0xc700
|
||||
|
|
@ -175,6 +179,7 @@
|
|||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
|
||||
#define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4)
|
||||
#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8)
|
||||
|
||||
/* Global USB2 PHY Vendor Control Register */
|
||||
#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25)
|
||||
|
|
@ -234,6 +239,10 @@
|
|||
/* Global HWPARAMS6 Register */
|
||||
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
|
||||
|
||||
/* Global Frame Length Adjustment Register */
|
||||
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
|
||||
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
|
||||
|
||||
/* Device Configuration Register */
|
||||
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
||||
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
|
||||
|
|
@ -712,6 +721,8 @@ struct dwc3_scratchpad_array {
|
|||
* @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk
|
||||
* @dis_u3_susphy_quirk: set if we disable usb3 suspend phy
|
||||
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
|
||||
* @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
|
||||
* disabling the suspend signal to the PHY.
|
||||
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
|
||||
* @tx_de_emphasis: Tx de-emphasis value
|
||||
* 0 - -6dB de-emphasis
|
||||
|
|
@ -766,6 +777,14 @@ struct dwc3 {
|
|||
u32 num_event_buffers;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
|
||||
/*
|
||||
* All 3.1 IP version constants are greater than the 3.0 IP
|
||||
* version constants. This works for most version checks in
|
||||
* dwc3. However, in the future, this may not apply as
|
||||
* features may be developed on newer versions of the 3.0 IP
|
||||
* that are not in the 3.1 IP.
|
||||
*/
|
||||
u32 revision;
|
||||
|
||||
#define DWC3_REVISION_173A 0x5533173a
|
||||
|
|
@ -788,6 +807,13 @@ struct dwc3 {
|
|||
#define DWC3_REVISION_270A 0x5533270a
|
||||
#define DWC3_REVISION_280A 0x5533280a
|
||||
|
||||
/*
|
||||
* NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
|
||||
* just so dwc31 revisions are always larger than dwc3.
|
||||
*/
|
||||
#define DWC3_REVISION_IS_DWC31 0x80000000
|
||||
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31)
|
||||
|
||||
enum dwc3_ep0_next ep0_next_event;
|
||||
enum dwc3_ep0_state ep0state;
|
||||
enum dwc3_link_state link_state;
|
||||
|
|
@ -841,6 +867,7 @@ struct dwc3 {
|
|||
unsigned rx_detect_poll_quirk:1;
|
||||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
|
|
|
|||
|
|
@ -26,12 +26,14 @@
|
|||
|
||||
#include "platform_data.h"
|
||||
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||||
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
||||
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
|
||||
#define PCI_DEVICE_ID_INTEL_BSW 0x22B7
|
||||
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
|
||||
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf
|
||||
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
||||
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
|
||||
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
|
||||
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
|
||||
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
|
||||
|
||||
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
|
||||
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
|
||||
|
|
@ -106,6 +108,22 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
|
||||
(pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
|
||||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
|
||||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
|
||||
|
||||
struct dwc3_platform_data pdata;
|
||||
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
pdata.usb3_lpm_capable = true;
|
||||
pdata.has_lpm_erratum = true;
|
||||
pdata.dis_enblslpm_quirk = true;
|
||||
|
||||
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
|
||||
sizeof(pdata));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +172,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||
goto err;
|
||||
|
||||
dwc3->dev.parent = dev;
|
||||
ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
|
|
@ -178,6 +197,14 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
|
|||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node, *child;
|
||||
struct platform_device *child_pdev;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
|
|
@ -253,8 +254,6 @@ static int st_dwc3_probe(struct platform_device *pdev)
|
|||
goto undo_softreset;
|
||||
}
|
||||
|
||||
dwc3_data->dr_mode = of_usb_get_dr_mode(child);
|
||||
|
||||
/* Allocate and initialize the core */
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
|
|
@ -262,6 +261,15 @@ static int st_dwc3_probe(struct platform_device *pdev)
|
|||
goto undo_softreset;
|
||||
}
|
||||
|
||||
child_pdev = of_find_device_by_node(child);
|
||||
if (!child_pdev) {
|
||||
dev_err(dev, "failed to find dwc3 core device\n");
|
||||
ret = -ENODEV;
|
||||
goto undo_softreset;
|
||||
}
|
||||
|
||||
dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev);
|
||||
|
||||
/*
|
||||
* Configure the USB port as device or host according to the static
|
||||
* configuration passed from DT.
|
||||
|
|
|
|||
|
|
@ -948,7 +948,6 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
|||
dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
|
||||
|
||||
/*
|
||||
* If we are getting here after a short-out-packet we don't enqueue any
|
||||
|
|
@ -1050,6 +1049,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
req->direction = dep->direction;
|
||||
req->epnum = dep->number;
|
||||
|
||||
trace_dwc3_ep_queue(req);
|
||||
|
||||
/*
|
||||
* We only add to our list of requests now and
|
||||
* start consuming the list once we get XferNotReady
|
||||
|
|
@ -1069,6 +1070,19 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
|
||||
/*
|
||||
* If there are no pending requests and the endpoint isn't already
|
||||
* busy, we will just start the request straight away.
|
||||
*
|
||||
* This will save one IRQ (XFER_NOT_READY) and possibly make it a
|
||||
* little bit faster.
|
||||
*/
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
!(dep->flags & DWC3_EP_BUSY)) {
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are a few special cases:
|
||||
*
|
||||
|
|
@ -1096,10 +1110,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
}
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
return ret;
|
||||
if (!ret)
|
||||
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1113,10 +1127,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
WARN_ON_ONCE(!dep->resource_index);
|
||||
ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
|
||||
false);
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1124,14 +1135,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
* right away, otherwise host will not know we have streams to be
|
||||
* handled.
|
||||
*/
|
||||
if (dep->stream_capable) {
|
||||
if (dep->stream_capable)
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
if (ret == -EBUSY)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
|
|
@ -1159,8 +1173,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
|||
goto out;
|
||||
}
|
||||
|
||||
trace_dwc3_ep_queue(req);
|
||||
|
||||
ret = __dwc3_gadget_ep_queue(dep, req);
|
||||
|
||||
out:
|
||||
|
|
@ -1872,27 +1884,32 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
req = next_request(&dep->req_queued);
|
||||
if (!req) {
|
||||
WARN_ON_ONCE(1);
|
||||
return 1;
|
||||
}
|
||||
i = 0;
|
||||
do {
|
||||
slot = req->start_slot + i;
|
||||
if ((slot == DWC3_TRB_NUM - 1) &&
|
||||
req = next_request(&dep->req_queued);
|
||||
if (!req) {
|
||||
WARN_ON_ONCE(1);
|
||||
return 1;
|
||||
}
|
||||
i = 0;
|
||||
do {
|
||||
slot = req->start_slot + i;
|
||||
if ((slot == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
slot++;
|
||||
slot %= DWC3_TRB_NUM;
|
||||
trb = &dep->trb_pool[slot];
|
||||
slot++;
|
||||
slot %= DWC3_TRB_NUM;
|
||||
trb = &dep->trb_pool[slot];
|
||||
|
||||
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
|
||||
event, status);
|
||||
if (ret)
|
||||
break;
|
||||
} while (++i < req->request.num_mapped_sgs);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, status);
|
||||
|
||||
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
|
||||
event, status);
|
||||
if (ret)
|
||||
break;
|
||||
} while (++i < req->request.num_mapped_sgs);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, status);
|
||||
} while (1);
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
list_empty(&dep->req_queued)) {
|
||||
|
|
@ -1955,6 +1972,14 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
|||
|
||||
dwc->u1u2 = 0;
|
||||
}
|
||||
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
int ret;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, is_xfer_complete);
|
||||
if (!ret || ret == -EBUSY)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
|
|
@ -1992,15 +2017,16 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
dwc3_gadget_start_isoc(dwc, dep, event);
|
||||
} else {
|
||||
int active;
|
||||
int ret;
|
||||
|
||||
active = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE;
|
||||
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
|
||||
dep->name, event->status &
|
||||
DEPEVT_STATUS_TRANSFER_ACTIVE
|
||||
? "Transfer Active"
|
||||
dep->name, active ? "Transfer Active"
|
||||
: "Transfer Not Active");
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, !active);
|
||||
if (!ret || ret == -EBUSY)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,9 +42,12 @@ struct dwc3_platform_data {
|
|||
unsigned rx_detect_poll_quirk:1;
|
||||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
|
||||
u32 fladj_value;
|
||||
|
||||
const char *hsphy_interface;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ config USB_GADGET_VBUS_DRAW
|
|||
|
||||
config USB_GADGET_STORAGE_NUM_BUFFERS
|
||||
int "Number of storage pipeline buffers"
|
||||
range 2 4
|
||||
range 2 32
|
||||
default 2
|
||||
help
|
||||
Usually 2 buffers are enough to establish a good buffering
|
||||
|
|
|
|||
|
|
@ -839,9 +839,7 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
|||
}
|
||||
}
|
||||
|
||||
/* set_alt(), or next bind(), sets up
|
||||
* ep->driver_data as needed.
|
||||
*/
|
||||
/* set_alt(), or next bind(), sets up ep->claimed as needed */
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
|
||||
done:
|
||||
|
|
@ -1506,6 +1504,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
} else {
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
|
||||
}
|
||||
} else {
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0200);
|
||||
}
|
||||
|
||||
value = min(w_length, (u16) sizeof cdev->desc);
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@
|
|||
* the restrictions that may apply. Some combinations of driver
|
||||
* and hardware won't be able to autoconfigure.
|
||||
*
|
||||
* On success, this returns an un-claimed usb_ep, and modifies the endpoint
|
||||
* On success, this returns an claimed usb_ep, and modifies the endpoint
|
||||
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
|
||||
* is initialized as if the endpoint were used at full speed and
|
||||
* the bmAttribute field in the ep companion descriptor is
|
||||
* updated with the assigned number of streams if it is
|
||||
* different from the original value. To prevent the endpoint
|
||||
* from being returned by a later autoconfig call, claim it by
|
||||
* from being returned by a later autoconfig call, claims it by
|
||||
* assigning ep->claimed to true.
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
|
|
@ -154,10 +154,10 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
|
|||
* USB controller, and it can't know all the restrictions that may apply.
|
||||
* Some combinations of driver and hardware won't be able to autoconfigure.
|
||||
*
|
||||
* On success, this returns an un-claimed usb_ep, and modifies the endpoint
|
||||
* On success, this returns an claimed usb_ep, and modifies the endpoint
|
||||
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
|
||||
* is initialized as if the endpoint were used at full speed. To prevent
|
||||
* the endpoint from being returned by a later autoconfig call, claim it
|
||||
* the endpoint from being returned by a later autoconfig call, claims it
|
||||
* by assigning ep->claimed to true.
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
|
|
@ -171,6 +171,23 @@ struct usb_ep *usb_ep_autoconfig(
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
|
||||
|
||||
/**
|
||||
* usb_ep_autoconfig_release - releases endpoint and set it to initial state
|
||||
* @ep: endpoint which should be released
|
||||
*
|
||||
* This function can be used during function bind for endpoints obtained
|
||||
* from usb_ep_autoconfig(). It unclaims endpoint claimed by
|
||||
* usb_ep_autoconfig() to make it available for other functions. Endpoint
|
||||
* which was released is no longer invalid and shouldn't be used in
|
||||
* context of function which released it.
|
||||
*/
|
||||
void usb_ep_autoconfig_release(struct usb_ep *ep)
|
||||
{
|
||||
ep->claimed = false;
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_ep_autoconfig_release);
|
||||
|
||||
/**
|
||||
* usb_ep_autoconfig_reset - reset endpoint autoconfig state
|
||||
* @gadget: device for which autoconfig state will be reset
|
||||
|
|
|
|||
|
|
@ -428,21 +428,18 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
/* we know alt == 0, so this is an activation or a reset */
|
||||
|
||||
if (intf == acm->ctrl_id) {
|
||||
if (acm->notify->driver_data) {
|
||||
dev_vdbg(&cdev->gadget->dev,
|
||||
"reset acm control interface %d\n", intf);
|
||||
usb_ep_disable(acm->notify);
|
||||
}
|
||||
dev_vdbg(&cdev->gadget->dev,
|
||||
"reset acm control interface %d\n", intf);
|
||||
usb_ep_disable(acm->notify);
|
||||
|
||||
if (!acm->notify->desc)
|
||||
if (config_ep_by_speed(cdev->gadget, f, acm->notify))
|
||||
return -EINVAL;
|
||||
|
||||
usb_ep_enable(acm->notify);
|
||||
acm->notify->driver_data = acm;
|
||||
|
||||
} else if (intf == acm->data_id) {
|
||||
if (acm->port.in->driver_data) {
|
||||
if (acm->notify->enabled) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"reset acm ttyGS%d\n", acm->port_num);
|
||||
gserial_disconnect(&acm->port);
|
||||
|
|
@ -475,7 +472,6 @@ static void acm_disable(struct usb_function *f)
|
|||
dev_dbg(&cdev->gadget->dev, "acm ttyGS%d deactivated\n", acm->port_num);
|
||||
gserial_disconnect(&acm->port);
|
||||
usb_ep_disable(acm->notify);
|
||||
acm->notify->driver_data = NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -655,19 +651,16 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
acm->port.in = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
acm->port.out = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
acm->notify = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* allocate notification */
|
||||
acm->notify_req = gs_alloc_req(ep,
|
||||
|
|
@ -709,14 +702,6 @@ fail:
|
|||
if (acm->notify_req)
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (acm->notify)
|
||||
acm->notify->driver_data = NULL;
|
||||
if (acm->port.out)
|
||||
acm->port.out->driver_data = NULL;
|
||||
if (acm->port.in)
|
||||
acm->port.in->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -541,24 +541,21 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
if (alt != 0)
|
||||
goto fail;
|
||||
|
||||
if (ecm->notify->driver_data) {
|
||||
VDBG(cdev, "reset ecm control %d\n", intf);
|
||||
usb_ep_disable(ecm->notify);
|
||||
}
|
||||
VDBG(cdev, "reset ecm control %d\n", intf);
|
||||
usb_ep_disable(ecm->notify);
|
||||
if (!(ecm->notify->desc)) {
|
||||
VDBG(cdev, "init ecm ctrl %d\n", intf);
|
||||
if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
|
||||
goto fail;
|
||||
}
|
||||
usb_ep_enable(ecm->notify);
|
||||
ecm->notify->driver_data = ecm;
|
||||
|
||||
/* Data interface has two altsettings, 0 and 1 */
|
||||
} else if (intf == ecm->data_id) {
|
||||
if (alt > 1)
|
||||
goto fail;
|
||||
|
||||
if (ecm->port.in_ep->driver_data) {
|
||||
if (ecm->port.in_ep->enabled) {
|
||||
DBG(cdev, "reset ecm\n");
|
||||
gether_disconnect(&ecm->port);
|
||||
}
|
||||
|
|
@ -618,7 +615,7 @@ static int ecm_get_alt(struct usb_function *f, unsigned intf)
|
|||
|
||||
if (intf == ecm->ctrl_id)
|
||||
return 0;
|
||||
return ecm->port.in_ep->driver_data ? 1 : 0;
|
||||
return ecm->port.in_ep->enabled ? 1 : 0;
|
||||
}
|
||||
|
||||
static void ecm_disable(struct usb_function *f)
|
||||
|
|
@ -628,14 +625,11 @@ static void ecm_disable(struct usb_function *f)
|
|||
|
||||
DBG(cdev, "ecm deactivated\n");
|
||||
|
||||
if (ecm->port.in_ep->driver_data)
|
||||
if (ecm->port.in_ep->enabled)
|
||||
gether_disconnect(&ecm->port);
|
||||
|
||||
if (ecm->notify->driver_data) {
|
||||
usb_ep_disable(ecm->notify);
|
||||
ecm->notify->driver_data = NULL;
|
||||
ecm->notify->desc = NULL;
|
||||
}
|
||||
usb_ep_disable(ecm->notify);
|
||||
ecm->notify->desc = NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -750,13 +744,11 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
ecm->port.in_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ecm->port.out_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* NOTE: a status/notification endpoint is *OPTIONAL* but we
|
||||
* don't treat it that way. It's simpler, and some newer CDC
|
||||
|
|
@ -766,7 +758,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
ecm->notify = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
status = -ENOMEM;
|
||||
|
||||
|
|
@ -820,14 +811,6 @@ fail:
|
|||
usb_ep_free_request(ecm->notify, ecm->notify_req);
|
||||
}
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (ecm->notify)
|
||||
ecm->notify->driver_data = NULL;
|
||||
if (ecm->port.out_ep)
|
||||
ecm->port.out_ep->driver_data = NULL;
|
||||
if (ecm->port.in_ep)
|
||||
ecm->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -195,11 +195,8 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
goto fail;
|
||||
|
||||
if (intf == eem->ctrl_id) {
|
||||
|
||||
if (eem->port.in_ep->driver_data) {
|
||||
DBG(cdev, "reset eem\n");
|
||||
gether_disconnect(&eem->port);
|
||||
}
|
||||
DBG(cdev, "reset eem\n");
|
||||
gether_disconnect(&eem->port);
|
||||
|
||||
if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
|
||||
DBG(cdev, "init eem\n");
|
||||
|
|
@ -237,7 +234,7 @@ static void eem_disable(struct usb_function *f)
|
|||
|
||||
DBG(cdev, "eem deactivated\n");
|
||||
|
||||
if (eem->port.in_ep->driver_data)
|
||||
if (eem->port.in_ep->enabled)
|
||||
gether_disconnect(&eem->port);
|
||||
}
|
||||
|
||||
|
|
@ -293,13 +290,11 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
eem->port.in_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
eem->port.out_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
status = -ENOMEM;
|
||||
|
||||
|
|
@ -325,11 +320,6 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (eem->port.out_ep)
|
||||
eem->port.out_ep->driver_data = NULL;
|
||||
if (eem->port.in_ep)
|
||||
eem->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -492,10 +492,7 @@ static void hidg_disable(struct usb_function *f)
|
|||
struct f_hidg_req_list *list, *next;
|
||||
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
hidg->in_ep->driver_data = NULL;
|
||||
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
hidg->out_ep->driver_data = NULL;
|
||||
|
||||
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
|
||||
list_del(&list->list);
|
||||
|
|
@ -513,8 +510,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
|
||||
if (hidg->in_ep != NULL) {
|
||||
/* restart endpoint */
|
||||
if (hidg->in_ep->driver_data != NULL)
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
|
||||
status = config_ep_by_speed(f->config->cdev->gadget, f,
|
||||
hidg->in_ep);
|
||||
|
|
@ -533,8 +529,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
|
||||
if (hidg->out_ep != NULL) {
|
||||
/* restart endpoint */
|
||||
if (hidg->out_ep->driver_data != NULL)
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
|
||||
status = config_ep_by_speed(f->config->cdev->gadget, f,
|
||||
hidg->out_ep);
|
||||
|
|
@ -566,7 +561,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
hidg->out_ep->name, status);
|
||||
} else {
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
hidg->out_ep->driver_data = NULL;
|
||||
status = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -614,13 +608,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ep->driver_data = c->cdev; /* claim */
|
||||
hidg->in_ep = ep;
|
||||
|
||||
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ep->driver_data = c->cdev; /* claim */
|
||||
hidg->out_ep = ep;
|
||||
|
||||
/* preallocate request and buffer */
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ struct f_loopback {
|
|||
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_ep *out_ep;
|
||||
|
||||
unsigned qlen;
|
||||
unsigned buflen;
|
||||
};
|
||||
|
||||
static inline struct f_loopback *func_to_loop(struct usb_function *f)
|
||||
|
|
@ -41,13 +44,10 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f)
|
|||
return container_of(f, struct f_loopback, function);
|
||||
}
|
||||
|
||||
static unsigned qlen;
|
||||
static unsigned buflen;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_interface_descriptor loopback_intf = {
|
||||
.bLength = sizeof loopback_intf,
|
||||
.bLength = sizeof(loopback_intf),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
.bNumEndpoints = 2,
|
||||
|
|
@ -195,12 +195,10 @@ autoconf_fail:
|
|||
f->name, cdev->gadget->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
loop->in_ep->driver_data = cdev; /* claim */
|
||||
|
||||
loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
|
||||
if (!loop->out_ep)
|
||||
goto autoconf_fail;
|
||||
loop->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* support high speed hardware */
|
||||
hs_loop_source_desc.bEndpointAddress =
|
||||
|
|
@ -245,22 +243,38 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
int status = req->status;
|
||||
|
||||
switch (status) {
|
||||
|
||||
case 0: /* normal completion? */
|
||||
if (ep == loop->out_ep) {
|
||||
req->zero = (req->actual < req->length);
|
||||
req->length = req->actual;
|
||||
/*
|
||||
* We received some data from the host so let's
|
||||
* queue it so host can read the from our in ep
|
||||
*/
|
||||
struct usb_request *in_req = req->context;
|
||||
|
||||
in_req->zero = (req->actual < req->length);
|
||||
in_req->length = req->actual;
|
||||
ep = loop->in_ep;
|
||||
req = in_req;
|
||||
} else {
|
||||
/*
|
||||
* We have just looped back a bunch of data
|
||||
* to host. Now let's wait for some more data.
|
||||
*/
|
||||
req = req->context;
|
||||
ep = loop->out_ep;
|
||||
}
|
||||
|
||||
/* queue the buffer for some later OUT packet */
|
||||
req->length = buflen;
|
||||
/* queue the buffer back to host or for next bunch of data */
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status == 0)
|
||||
if (status == 0) {
|
||||
return;
|
||||
} else {
|
||||
ERROR(cdev, "Unable to loop back buffer to %s: %d\n",
|
||||
ep->name, status);
|
||||
goto free_req;
|
||||
}
|
||||
|
||||
/* "should never get here" */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
default:
|
||||
ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
|
||||
status, req->actual, req->length);
|
||||
|
|
@ -274,6 +288,10 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNRESET: /* request dequeued */
|
||||
case -ESHUTDOWN: /* disconnect from host */
|
||||
free_req:
|
||||
usb_ep_free_request(ep == loop->in_ep ?
|
||||
loop->out_ep : loop->in_ep,
|
||||
req->context);
|
||||
free_ep_req(ep, req);
|
||||
return;
|
||||
}
|
||||
|
|
@ -290,53 +308,77 @@ static void disable_loopback(struct f_loopback *loop)
|
|||
|
||||
static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
|
||||
{
|
||||
return alloc_ep_req(ep, len, buflen);
|
||||
struct f_loopback *loop = ep->driver_data;
|
||||
|
||||
return alloc_ep_req(ep, len, loop->buflen);
|
||||
}
|
||||
|
||||
static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop,
|
||||
struct usb_ep *ep)
|
||||
static int alloc_requests(struct usb_composite_dev *cdev,
|
||||
struct f_loopback *loop)
|
||||
{
|
||||
struct usb_request *req;
|
||||
unsigned i;
|
||||
int result;
|
||||
|
||||
/*
|
||||
* one endpoint writes data back IN to the host while another endpoint
|
||||
* just reads OUT packets
|
||||
*/
|
||||
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
|
||||
if (result)
|
||||
goto fail0;
|
||||
result = usb_ep_enable(ep);
|
||||
if (result < 0)
|
||||
goto fail0;
|
||||
ep->driver_data = loop;
|
||||
struct usb_request *in_req, *out_req;
|
||||
int i;
|
||||
int result = 0;
|
||||
|
||||
/*
|
||||
* allocate a bunch of read buffers and queue them all at once.
|
||||
* we buffer at most 'qlen' transfers; fewer if any need more
|
||||
* than 'buflen' bytes each.
|
||||
* we buffer at most 'qlen' transfers; We allocate buffers only
|
||||
* for out transfer and reuse them in IN transfers to implement
|
||||
* our loopback functionality
|
||||
*/
|
||||
for (i = 0; i < qlen && result == 0; i++) {
|
||||
req = lb_alloc_ep_req(ep, 0);
|
||||
if (!req)
|
||||
goto fail1;
|
||||
for (i = 0; i < loop->qlen && result == 0; i++) {
|
||||
result = -ENOMEM;
|
||||
|
||||
req->complete = loopback_complete;
|
||||
result = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
in_req = usb_ep_alloc_request(loop->in_ep, GFP_KERNEL);
|
||||
if (!in_req)
|
||||
goto fail;
|
||||
|
||||
out_req = lb_alloc_ep_req(loop->out_ep, 0);
|
||||
if (!out_req)
|
||||
goto fail_in;
|
||||
|
||||
in_req->complete = loopback_complete;
|
||||
out_req->complete = loopback_complete;
|
||||
|
||||
in_req->buf = out_req->buf;
|
||||
/* length will be set in complete routine */
|
||||
in_req->context = out_req;
|
||||
out_req->context = in_req;
|
||||
|
||||
result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
|
||||
if (result) {
|
||||
ERROR(cdev, "%s queue req --> %d\n",
|
||||
ep->name, result);
|
||||
goto fail1;
|
||||
loop->out_ep->name, result);
|
||||
goto fail_out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail1:
|
||||
usb_ep_disable(ep);
|
||||
fail_out:
|
||||
free_ep_req(loop->out_ep, out_req);
|
||||
fail_in:
|
||||
usb_ep_free_request(loop->in_ep, in_req);
|
||||
fail:
|
||||
return result;
|
||||
}
|
||||
|
||||
fail0:
|
||||
static int enable_endpoint(struct usb_composite_dev *cdev,
|
||||
struct f_loopback *loop, struct usb_ep *ep)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
|
||||
if (result)
|
||||
goto out;
|
||||
|
||||
result = usb_ep_enable(ep);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
ep->driver_data = loop;
|
||||
result = 0;
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -347,13 +389,24 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
|
|||
|
||||
result = enable_endpoint(cdev, loop, loop->in_ep);
|
||||
if (result)
|
||||
return result;
|
||||
goto out;
|
||||
|
||||
result = enable_endpoint(cdev, loop, loop->out_ep);
|
||||
if (result)
|
||||
return result;
|
||||
goto disable_in;
|
||||
|
||||
result = alloc_requests(cdev, loop);
|
||||
if (result)
|
||||
goto disable_out;
|
||||
|
||||
DBG(cdev, "%s enabled\n", loop->function.name);
|
||||
return 0;
|
||||
|
||||
disable_out:
|
||||
usb_ep_disable(loop->out_ep);
|
||||
disable_in:
|
||||
usb_ep_disable(loop->in_ep);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -364,8 +417,7 @@ static int loopback_set_alt(struct usb_function *f,
|
|||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
/* we know alt is zero */
|
||||
if (loop->in_ep->driver_data)
|
||||
disable_loopback(loop);
|
||||
disable_loopback(loop);
|
||||
return enable_loopback(cdev, loop);
|
||||
}
|
||||
|
||||
|
|
@ -391,10 +443,10 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
|
|||
lb_opts->refcnt++;
|
||||
mutex_unlock(&lb_opts->lock);
|
||||
|
||||
buflen = lb_opts->bulk_buflen;
|
||||
qlen = lb_opts->qlen;
|
||||
if (!qlen)
|
||||
qlen = 32;
|
||||
loop->buflen = lb_opts->bulk_buflen;
|
||||
loop->qlen = lb_opts->qlen;
|
||||
if (!loop->qlen)
|
||||
loop->qlen = 32;
|
||||
|
||||
loop->function.name = "loopback";
|
||||
loop->function.bind = loopback_bind;
|
||||
|
|
@ -434,7 +486,7 @@ static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->qlen);
|
||||
result = sprintf(page, "%d\n", opts->qlen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -473,7 +525,7 @@ static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->bulk_buflen);
|
||||
result = sprintf(page, "%d\n", opts->bulk_buflen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -2258,12 +2258,10 @@ reset:
|
|||
/* Disable the endpoints */
|
||||
if (fsg->bulk_in_enabled) {
|
||||
usb_ep_disable(fsg->bulk_in);
|
||||
fsg->bulk_in->driver_data = NULL;
|
||||
fsg->bulk_in_enabled = 0;
|
||||
}
|
||||
if (fsg->bulk_out_enabled) {
|
||||
usb_ep_disable(fsg->bulk_out);
|
||||
fsg->bulk_out->driver_data = NULL;
|
||||
fsg->bulk_out_enabled = 0;
|
||||
}
|
||||
|
||||
|
|
@ -2662,10 +2660,12 @@ EXPORT_SYMBOL_GPL(fsg_common_put);
|
|||
/* check if fsg_num_buffers is within a valid range */
|
||||
static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)
|
||||
{
|
||||
if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
|
||||
#define FSG_MAX_NUM_BUFFERS 32
|
||||
|
||||
if (fsg_num_buffers >= 2 && fsg_num_buffers <= FSG_MAX_NUM_BUFFERS)
|
||||
return 0;
|
||||
pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
|
||||
fsg_num_buffers, 2, 4);
|
||||
fsg_num_buffers, 2, FSG_MAX_NUM_BUFFERS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -3070,13 +3070,11 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
|
||||
if (!ep)
|
||||
goto autoconf_fail;
|
||||
ep->driver_data = fsg->common; /* claim the endpoint */
|
||||
fsg->bulk_in = ep;
|
||||
|
||||
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
|
||||
if (!ep)
|
||||
goto autoconf_fail;
|
||||
ep->driver_data = fsg->common; /* claim the endpoint */
|
||||
fsg->bulk_out = ep;
|
||||
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
|
|
|
|||
|
|
@ -302,8 +302,7 @@ static int f_midi_start_ep(struct f_midi *midi,
|
|||
int err;
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
if (ep->driver_data)
|
||||
usb_ep_disable(ep);
|
||||
usb_ep_disable(ep);
|
||||
|
||||
err = config_ep_by_speed(midi->gadget, f, ep);
|
||||
if (err) {
|
||||
|
|
@ -341,8 +340,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (midi->out_ep->driver_data)
|
||||
usb_ep_disable(midi->out_ep);
|
||||
usb_ep_disable(midi->out_ep);
|
||||
|
||||
err = config_ep_by_speed(midi->gadget, f, midi->out_ep);
|
||||
if (err) {
|
||||
|
|
@ -547,10 +545,16 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
|
|||
}
|
||||
}
|
||||
|
||||
if (req->length > 0)
|
||||
usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
else
|
||||
if (req->length > 0) {
|
||||
int err;
|
||||
|
||||
err = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (err < 0)
|
||||
ERROR(midi, "%s queue req: %d\n",
|
||||
midi->in_ep->name, err);
|
||||
} else {
|
||||
free_ep_req(ep, req);
|
||||
}
|
||||
}
|
||||
|
||||
static void f_midi_in_tasklet(unsigned long data)
|
||||
|
|
@ -757,12 +761,10 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc);
|
||||
if (!midi->in_ep)
|
||||
goto fail;
|
||||
midi->in_ep->driver_data = cdev; /* claim */
|
||||
|
||||
midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc);
|
||||
if (!midi->out_ep)
|
||||
goto fail;
|
||||
midi->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* allocate temporary function list */
|
||||
midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
|
||||
|
|
@ -889,12 +891,6 @@ fail_f_midi:
|
|||
fail:
|
||||
f_midi_unregister_card(midi);
|
||||
fail_register:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (midi->out_ep)
|
||||
midi->out_ep->driver_data = NULL;
|
||||
if (midi->in_ep)
|
||||
midi->in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ static void ncm_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
unsigned in_size;
|
||||
struct usb_function *f = req->context;
|
||||
struct f_ncm *ncm = func_to_ncm(f);
|
||||
struct usb_composite_dev *cdev = ep->driver_data;
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
req->context = NULL;
|
||||
if (req->status || req->actual != req->length) {
|
||||
|
|
@ -803,10 +803,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
if (alt != 0)
|
||||
goto fail;
|
||||
|
||||
if (ncm->notify->driver_data) {
|
||||
DBG(cdev, "reset ncm control %d\n", intf);
|
||||
usb_ep_disable(ncm->notify);
|
||||
}
|
||||
DBG(cdev, "reset ncm control %d\n", intf);
|
||||
usb_ep_disable(ncm->notify);
|
||||
|
||||
if (!(ncm->notify->desc)) {
|
||||
DBG(cdev, "init ncm ctrl %d\n", intf);
|
||||
|
|
@ -814,14 +812,13 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
goto fail;
|
||||
}
|
||||
usb_ep_enable(ncm->notify);
|
||||
ncm->notify->driver_data = ncm;
|
||||
|
||||
/* Data interface has two altsettings, 0 and 1 */
|
||||
} else if (intf == ncm->data_id) {
|
||||
if (alt > 1)
|
||||
goto fail;
|
||||
|
||||
if (ncm->port.in_ep->driver_data) {
|
||||
if (ncm->port.in_ep->enabled) {
|
||||
DBG(cdev, "reset ncm\n");
|
||||
ncm->timer_stopping = true;
|
||||
ncm->netdev = NULL;
|
||||
|
|
@ -885,7 +882,7 @@ static int ncm_get_alt(struct usb_function *f, unsigned intf)
|
|||
|
||||
if (intf == ncm->ctrl_id)
|
||||
return 0;
|
||||
return ncm->port.in_ep->driver_data ? 1 : 0;
|
||||
return ncm->port.in_ep->enabled ? 1 : 0;
|
||||
}
|
||||
|
||||
static struct sk_buff *package_for_tx(struct f_ncm *ncm)
|
||||
|
|
@ -1276,15 +1273,14 @@ static void ncm_disable(struct usb_function *f)
|
|||
|
||||
DBG(cdev, "ncm deactivated\n");
|
||||
|
||||
if (ncm->port.in_ep->driver_data) {
|
||||
if (ncm->port.in_ep->enabled) {
|
||||
ncm->timer_stopping = true;
|
||||
ncm->netdev = NULL;
|
||||
gether_disconnect(&ncm->port);
|
||||
}
|
||||
|
||||
if (ncm->notify->driver_data) {
|
||||
if (ncm->notify->enabled) {
|
||||
usb_ep_disable(ncm->notify);
|
||||
ncm->notify->driver_data = NULL;
|
||||
ncm->notify->desc = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1402,19 +1398,16 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
ncm->port.in_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ncm->port.out_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ncm->notify = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
status = -ENOMEM;
|
||||
|
||||
|
|
@ -1468,14 +1461,6 @@ fail:
|
|||
usb_ep_free_request(ncm->notify, ncm->notify_req);
|
||||
}
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (ncm->notify)
|
||||
ncm->notify->driver_data = NULL;
|
||||
if (ncm->port.out_ep)
|
||||
ncm->port.out_ep->driver_data = NULL;
|
||||
if (ncm->port.in_ep)
|
||||
ncm->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
if (alt > 1)
|
||||
goto fail;
|
||||
|
||||
if (obex->port.in->driver_data) {
|
||||
if (obex->port.in->enabled) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"reset obex ttyGS%d\n", obex->port_num);
|
||||
gserial_disconnect(&obex->port);
|
||||
|
|
@ -348,13 +348,11 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
obex->port.in = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
obex->port.out = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
|
|
@ -378,12 +376,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (obex->port.out)
|
||||
obex->port.out->driver_data = NULL;
|
||||
if (obex->port.in)
|
||||
obex->port.in->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
if (fp->in_ep->driver_data)
|
||||
if (fp->in_ep->enabled)
|
||||
__pn_reset(f);
|
||||
|
||||
if (alt == 1) {
|
||||
|
|
@ -530,13 +530,11 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto err;
|
||||
fp->out_ep = ep;
|
||||
ep->driver_data = fp; /* Claim */
|
||||
|
||||
ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc);
|
||||
if (!ep)
|
||||
goto err;
|
||||
fp->in_ep = ep;
|
||||
ep->driver_data = fp; /* Claim */
|
||||
|
||||
pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress;
|
||||
pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress;
|
||||
|
|
@ -575,10 +573,6 @@ err_req:
|
|||
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
|
||||
usb_free_all_descriptors(f);
|
||||
err:
|
||||
if (fp->out_ep)
|
||||
fp->out_ep->driver_data = NULL;
|
||||
if (fp->in_ep)
|
||||
fp->in_ep->driver_data = NULL;
|
||||
ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n");
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1039,12 +1039,10 @@ autoconf_fail:
|
|||
cdev->gadget->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
in_ep->driver_data = in_ep; /* claim */
|
||||
|
||||
out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
|
||||
if (!out_ep)
|
||||
goto autoconf_fail;
|
||||
out_ep->driver_data = out_ep; /* claim */
|
||||
|
||||
/* assumes that all endpoints are dual-speed */
|
||||
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
|
||||
|
|
|
|||
|
|
@ -543,22 +543,20 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
/* we know alt == 0 */
|
||||
|
||||
if (intf == rndis->ctrl_id) {
|
||||
if (rndis->notify->driver_data) {
|
||||
VDBG(cdev, "reset rndis control %d\n", intf);
|
||||
usb_ep_disable(rndis->notify);
|
||||
}
|
||||
VDBG(cdev, "reset rndis control %d\n", intf);
|
||||
usb_ep_disable(rndis->notify);
|
||||
|
||||
if (!rndis->notify->desc) {
|
||||
VDBG(cdev, "init rndis ctrl %d\n", intf);
|
||||
if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
|
||||
goto fail;
|
||||
}
|
||||
usb_ep_enable(rndis->notify);
|
||||
rndis->notify->driver_data = rndis;
|
||||
|
||||
} else if (intf == rndis->data_id) {
|
||||
struct net_device *net;
|
||||
|
||||
if (rndis->port.in_ep->driver_data) {
|
||||
if (rndis->port.in_ep->enabled) {
|
||||
DBG(cdev, "reset rndis\n");
|
||||
gether_disconnect(&rndis->port);
|
||||
}
|
||||
|
|
@ -612,7 +610,7 @@ static void rndis_disable(struct usb_function *f)
|
|||
struct f_rndis *rndis = func_to_rndis(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
if (!rndis->notify->driver_data)
|
||||
if (!rndis->notify->enabled)
|
||||
return;
|
||||
|
||||
DBG(cdev, "rndis deactivated\n");
|
||||
|
|
@ -621,7 +619,6 @@ static void rndis_disable(struct usb_function *f)
|
|||
gether_disconnect(&rndis->port);
|
||||
|
||||
usb_ep_disable(rndis->notify);
|
||||
rndis->notify->driver_data = NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -745,13 +742,11 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
rndis->port.in_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
rndis->port.out_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* NOTE: a status/notification endpoint is, strictly speaking,
|
||||
* optional. We don't treat it that way though! It's simpler,
|
||||
|
|
@ -761,7 +756,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
rndis->notify = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
status = -ENOMEM;
|
||||
|
||||
|
|
@ -829,14 +823,6 @@ fail:
|
|||
usb_ep_free_request(rndis->notify, rndis->notify_req);
|
||||
}
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (rndis->notify)
|
||||
rndis->notify->driver_data = NULL;
|
||||
if (rndis->port.out_ep)
|
||||
rndis->port.out_ep->driver_data = NULL;
|
||||
if (rndis->port.in_ep)
|
||||
rndis->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
|
||||
/* we know alt == 0, so this is an activation or a reset */
|
||||
|
||||
if (gser->port.in->driver_data) {
|
||||
if (gser->port.in->enabled) {
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"reset generic ttyGS%d\n", gser->port_num);
|
||||
gserial_disconnect(&gser->port);
|
||||
|
|
@ -219,13 +219,11 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
gser->port.in = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
gser->port.out = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
|
|
@ -249,12 +247,6 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (gser->port.out)
|
||||
gser->port.out->driver_data = NULL;
|
||||
if (gser->port.in)
|
||||
gser->port.in->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,13 @@ struct f_sourcesink {
|
|||
struct usb_ep *iso_in_ep;
|
||||
struct usb_ep *iso_out_ep;
|
||||
int cur_alt;
|
||||
|
||||
unsigned pattern;
|
||||
unsigned isoc_interval;
|
||||
unsigned isoc_maxpacket;
|
||||
unsigned isoc_mult;
|
||||
unsigned isoc_maxburst;
|
||||
unsigned buflen;
|
||||
};
|
||||
|
||||
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
|
||||
|
|
@ -57,13 +64,6 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
|
|||
return container_of(f, struct f_sourcesink, function);
|
||||
}
|
||||
|
||||
static unsigned pattern;
|
||||
static unsigned isoc_interval;
|
||||
static unsigned isoc_maxpacket;
|
||||
static unsigned isoc_mult;
|
||||
static unsigned isoc_maxburst;
|
||||
static unsigned buflen;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_interface_descriptor source_sink_intf_alt0 = {
|
||||
|
|
@ -298,7 +298,9 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
|
|||
|
||||
static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
|
||||
{
|
||||
return alloc_ep_req(ep, len, buflen);
|
||||
struct f_sourcesink *ss = ep->driver_data;
|
||||
|
||||
return alloc_ep_req(ep, len, ss->buflen);
|
||||
}
|
||||
|
||||
void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
|
|
@ -311,13 +313,9 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
|
|||
{
|
||||
int value;
|
||||
|
||||
if (ep->driver_data) {
|
||||
value = usb_ep_disable(ep);
|
||||
if (value < 0)
|
||||
DBG(cdev, "disable %s --> %d\n",
|
||||
ep->name, value);
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
value = usb_ep_disable(ep);
|
||||
if (value < 0)
|
||||
DBG(cdev, "disable %s --> %d\n", ep->name, value);
|
||||
}
|
||||
|
||||
void disable_endpoints(struct usb_composite_dev *cdev,
|
||||
|
|
@ -355,42 +353,37 @@ autoconf_fail:
|
|||
f->name, cdev->gadget->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
ss->in_ep->driver_data = cdev; /* claim */
|
||||
|
||||
ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
|
||||
if (!ss->out_ep)
|
||||
goto autoconf_fail;
|
||||
ss->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* sanity check the isoc module parameters */
|
||||
if (isoc_interval < 1)
|
||||
isoc_interval = 1;
|
||||
if (isoc_interval > 16)
|
||||
isoc_interval = 16;
|
||||
if (isoc_mult > 2)
|
||||
isoc_mult = 2;
|
||||
if (isoc_maxburst > 15)
|
||||
isoc_maxburst = 15;
|
||||
if (ss->isoc_interval < 1)
|
||||
ss->isoc_interval = 1;
|
||||
if (ss->isoc_interval > 16)
|
||||
ss->isoc_interval = 16;
|
||||
if (ss->isoc_mult > 2)
|
||||
ss->isoc_mult = 2;
|
||||
if (ss->isoc_maxburst > 15)
|
||||
ss->isoc_maxburst = 15;
|
||||
|
||||
/* fill in the FS isoc descriptors from the module parameters */
|
||||
fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
|
||||
1023 : isoc_maxpacket;
|
||||
fs_iso_source_desc.bInterval = isoc_interval;
|
||||
fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
|
||||
1023 : isoc_maxpacket;
|
||||
fs_iso_sink_desc.bInterval = isoc_interval;
|
||||
fs_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket > 1023 ?
|
||||
1023 : ss->isoc_maxpacket;
|
||||
fs_iso_source_desc.bInterval = ss->isoc_interval;
|
||||
fs_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket > 1023 ?
|
||||
1023 : ss->isoc_maxpacket;
|
||||
fs_iso_sink_desc.bInterval = ss->isoc_interval;
|
||||
|
||||
/* allocate iso endpoints */
|
||||
ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
|
||||
if (!ss->iso_in_ep)
|
||||
goto no_iso;
|
||||
ss->iso_in_ep->driver_data = cdev; /* claim */
|
||||
|
||||
ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
|
||||
if (ss->iso_out_ep) {
|
||||
ss->iso_out_ep->driver_data = cdev; /* claim */
|
||||
} else {
|
||||
ss->iso_in_ep->driver_data = NULL;
|
||||
if (!ss->iso_out_ep) {
|
||||
usb_ep_autoconfig_release(ss->iso_in_ep);
|
||||
ss->iso_in_ep = NULL;
|
||||
no_iso:
|
||||
/*
|
||||
|
|
@ -403,8 +396,8 @@ no_iso:
|
|||
ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
|
||||
}
|
||||
|
||||
if (isoc_maxpacket > 1024)
|
||||
isoc_maxpacket = 1024;
|
||||
if (ss->isoc_maxpacket > 1024)
|
||||
ss->isoc_maxpacket = 1024;
|
||||
|
||||
/* support high speed hardware */
|
||||
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
|
||||
|
|
@ -415,15 +408,15 @@ no_iso:
|
|||
* We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
|
||||
hs_iso_source_desc.bInterval = isoc_interval;
|
||||
hs_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket;
|
||||
hs_iso_source_desc.wMaxPacketSize |= ss->isoc_mult << 11;
|
||||
hs_iso_source_desc.bInterval = ss->isoc_interval;
|
||||
hs_iso_source_desc.bEndpointAddress =
|
||||
fs_iso_source_desc.bEndpointAddress;
|
||||
|
||||
hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
|
||||
hs_iso_sink_desc.bInterval = isoc_interval;
|
||||
hs_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
|
||||
hs_iso_sink_desc.wMaxPacketSize |= ss->isoc_mult << 11;
|
||||
hs_iso_sink_desc.bInterval = ss->isoc_interval;
|
||||
hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
|
||||
|
||||
/* support super speed hardware */
|
||||
|
|
@ -437,21 +430,21 @@ no_iso:
|
|||
* We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
ss_iso_source_desc.bInterval = isoc_interval;
|
||||
ss_iso_source_comp_desc.bmAttributes = isoc_mult;
|
||||
ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
|
||||
ss_iso_source_comp_desc.wBytesPerInterval =
|
||||
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
|
||||
ss_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket;
|
||||
ss_iso_source_desc.bInterval = ss->isoc_interval;
|
||||
ss_iso_source_comp_desc.bmAttributes = ss->isoc_mult;
|
||||
ss_iso_source_comp_desc.bMaxBurst = ss->isoc_maxburst;
|
||||
ss_iso_source_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
|
||||
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
|
||||
ss_iso_source_desc.bEndpointAddress =
|
||||
fs_iso_source_desc.bEndpointAddress;
|
||||
|
||||
ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
ss_iso_sink_desc.bInterval = isoc_interval;
|
||||
ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
|
||||
ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
|
||||
ss_iso_sink_comp_desc.wBytesPerInterval =
|
||||
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
|
||||
ss_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
|
||||
ss_iso_sink_desc.bInterval = ss->isoc_interval;
|
||||
ss_iso_sink_comp_desc.bmAttributes = ss->isoc_mult;
|
||||
ss_iso_sink_comp_desc.bMaxBurst = ss->isoc_maxburst;
|
||||
ss_iso_sink_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
|
||||
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
|
||||
ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(f, fs_source_sink_descs,
|
||||
|
|
@ -489,12 +482,13 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
|
|||
unsigned i;
|
||||
u8 *buf = req->buf;
|
||||
struct usb_composite_dev *cdev = ss->function.config->cdev;
|
||||
int max_packet_size = le16_to_cpu(ss->out_ep->desc->wMaxPacketSize);
|
||||
|
||||
if (pattern == 2)
|
||||
if (ss->pattern == 2)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < req->actual; i++, buf++) {
|
||||
switch (pattern) {
|
||||
switch (ss->pattern) {
|
||||
|
||||
/* all-zeroes has no synchronization issues */
|
||||
case 0:
|
||||
|
|
@ -510,7 +504,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
|
|||
* stutter for any reason, including buffer duplication...)
|
||||
*/
|
||||
case 1:
|
||||
if (*buf == (u8)(i % 63))
|
||||
if (*buf == (u8)((i % max_packet_size) % 63))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
|
@ -525,14 +519,16 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
|
|||
{
|
||||
unsigned i;
|
||||
u8 *buf = req->buf;
|
||||
int max_packet_size = le16_to_cpu(ep->desc->wMaxPacketSize);
|
||||
struct f_sourcesink *ss = ep->driver_data;
|
||||
|
||||
switch (pattern) {
|
||||
switch (ss->pattern) {
|
||||
case 0:
|
||||
memset(req->buf, 0, req->length);
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < req->length; i++)
|
||||
*buf++ = (u8) (i % 63);
|
||||
*buf++ = (u8) ((i % max_packet_size) % 63);
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
|
|
@ -556,7 +552,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
case 0: /* normal completion? */
|
||||
if (ep == ss->out_ep) {
|
||||
check_read_data(ss, req);
|
||||
if (pattern != 2)
|
||||
if (ss->pattern != 2)
|
||||
memset(req->buf, 0x55, req->length);
|
||||
}
|
||||
break;
|
||||
|
|
@ -605,15 +601,16 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
|
|||
if (is_iso) {
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
size = isoc_maxpacket * (isoc_mult + 1) *
|
||||
(isoc_maxburst + 1);
|
||||
size = ss->isoc_maxpacket *
|
||||
(ss->isoc_mult + 1) *
|
||||
(ss->isoc_maxburst + 1);
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
size = isoc_maxpacket * (isoc_mult + 1);
|
||||
size = ss->isoc_maxpacket * (ss->isoc_mult + 1);
|
||||
break;
|
||||
default:
|
||||
size = isoc_maxpacket > 1023 ?
|
||||
1023 : isoc_maxpacket;
|
||||
size = ss->isoc_maxpacket > 1023 ?
|
||||
1023 : ss->isoc_maxpacket;
|
||||
break;
|
||||
}
|
||||
ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
|
||||
|
|
@ -629,7 +626,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
|
|||
req->complete = source_sink_complete;
|
||||
if (is_in)
|
||||
reinit_write_data(ep, req);
|
||||
else if (pattern != 2)
|
||||
else if (ss->pattern != 2)
|
||||
memset(req->buf, 0x55, req->length);
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
|
|
@ -683,7 +680,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
|
|||
fail:
|
||||
ep = ss->in_ep;
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -702,7 +698,6 @@ fail:
|
|||
fail2:
|
||||
ep = ss->out_ep;
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -724,10 +719,8 @@ fail2:
|
|||
if (result < 0) {
|
||||
fail3:
|
||||
ep = ss->iso_in_ep;
|
||||
if (ep) {
|
||||
if (ep)
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
goto fail2;
|
||||
}
|
||||
}
|
||||
|
|
@ -746,7 +739,6 @@ fail3:
|
|||
result = source_sink_start_ep(ss, false, true, speed);
|
||||
if (result < 0) {
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
goto fail3;
|
||||
}
|
||||
}
|
||||
|
|
@ -763,8 +755,7 @@ static int sourcesink_set_alt(struct usb_function *f,
|
|||
struct f_sourcesink *ss = func_to_ss(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
if (ss->in_ep->driver_data)
|
||||
disable_source_sink(ss);
|
||||
disable_source_sink(ss);
|
||||
return enable_source_sink(cdev, ss, alt);
|
||||
}
|
||||
|
||||
|
|
@ -872,12 +863,12 @@ static struct usb_function *source_sink_alloc_func(
|
|||
ss_opts->refcnt++;
|
||||
mutex_unlock(&ss_opts->lock);
|
||||
|
||||
pattern = ss_opts->pattern;
|
||||
isoc_interval = ss_opts->isoc_interval;
|
||||
isoc_maxpacket = ss_opts->isoc_maxpacket;
|
||||
isoc_mult = ss_opts->isoc_mult;
|
||||
isoc_maxburst = ss_opts->isoc_maxburst;
|
||||
buflen = ss_opts->bulk_buflen;
|
||||
ss->pattern = ss_opts->pattern;
|
||||
ss->isoc_interval = ss_opts->isoc_interval;
|
||||
ss->isoc_maxpacket = ss_opts->isoc_maxpacket;
|
||||
ss->isoc_mult = ss_opts->isoc_mult;
|
||||
ss->isoc_maxburst = ss_opts->isoc_maxburst;
|
||||
ss->buflen = ss_opts->bulk_buflen;
|
||||
|
||||
ss->function.name = "source/sink";
|
||||
ss->function.bind = sourcesink_bind;
|
||||
|
|
@ -919,7 +910,7 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%u", opts->pattern);
|
||||
result = sprintf(page, "%u\n", opts->pattern);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -963,7 +954,7 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%u", opts->isoc_interval);
|
||||
result = sprintf(page, "%u\n", opts->isoc_interval);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1007,7 +998,7 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%u", opts->isoc_maxpacket);
|
||||
result = sprintf(page, "%u\n", opts->isoc_maxpacket);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1051,7 +1042,7 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%u", opts->isoc_mult);
|
||||
result = sprintf(page, "%u\n", opts->isoc_mult);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1095,7 +1086,7 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%u", opts->isoc_maxburst);
|
||||
result = sprintf(page, "%u\n", opts->isoc_maxburst);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1139,7 +1130,7 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%u", opts->bulk_buflen);
|
||||
result = sprintf(page, "%u\n", opts->bulk_buflen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
|
||||
/* we know alt == 0, so this is an activation or a reset */
|
||||
|
||||
if (geth->port.in_ep->driver_data) {
|
||||
if (geth->port.in_ep->enabled) {
|
||||
DBG(cdev, "reset cdc subset\n");
|
||||
gether_disconnect(&geth->port);
|
||||
}
|
||||
|
|
@ -343,13 +343,11 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (!ep)
|
||||
goto fail;
|
||||
geth->port.in_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
geth->port.out_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
|
|
@ -380,12 +378,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (geth->port.out_ep)
|
||||
geth->port.out_ep->driver_data = NULL;
|
||||
if (geth->port.in_ep)
|
||||
geth->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -593,7 +593,6 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
return err;
|
||||
|
||||
usb_ep_enable(out_ep);
|
||||
out_ep->driver_data = audio;
|
||||
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
|
||||
if (IS_ERR(audio->copy_buf))
|
||||
return -ENOMEM;
|
||||
|
|
@ -718,7 +717,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
goto fail;
|
||||
audio->out_ep = ep;
|
||||
audio->out_ep->desc = &as_out_ep_desc;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
status = -ENOMEM;
|
||||
|
||||
|
|
@ -730,8 +728,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
fail:
|
||||
gaudio_cleanup(&audio->card);
|
||||
if (ep)
|
||||
ep->driver_data = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1081,14 +1081,12 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
|
||||
goto err;
|
||||
}
|
||||
agdev->out_ep->driver_data = agdev;
|
||||
|
||||
agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
|
||||
if (!agdev->in_ep) {
|
||||
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
|
||||
goto err;
|
||||
}
|
||||
agdev->in_ep->driver_data = agdev;
|
||||
|
||||
uac2->p_prm.uac2 = uac2;
|
||||
uac2->c_prm.uac2 = uac2;
|
||||
|
|
@ -1132,10 +1130,6 @@ err_free_descs:
|
|||
err:
|
||||
kfree(agdev->uac2.p_prm.rbuf);
|
||||
kfree(agdev->uac2.c_prm.rbuf);
|
||||
if (agdev->in_ep)
|
||||
agdev->in_ep->driver_data = NULL;
|
||||
if (agdev->out_ep)
|
||||
agdev->out_ep->driver_data = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1583,11 +1577,6 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
prm = &agdev->uac2.c_prm;
|
||||
kfree(prm->rbuf);
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
if (agdev->in_ep)
|
||||
agdev->in_ep->driver_data = NULL;
|
||||
if (agdev->out_ep)
|
||||
agdev->out_ep->driver_data = NULL;
|
||||
}
|
||||
|
||||
static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface)
|
|||
else if (interface != uvc->streaming_intf)
|
||||
return -EINVAL;
|
||||
else
|
||||
return uvc->video.ep->driver_data ? 1 : 0;
|
||||
return uvc->video.ep->enabled ? 1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -298,18 +298,14 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
|||
if (alt)
|
||||
return -EINVAL;
|
||||
|
||||
if (uvc->control_ep->driver_data) {
|
||||
INFO(cdev, "reset UVC Control\n");
|
||||
usb_ep_disable(uvc->control_ep);
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
}
|
||||
INFO(cdev, "reset UVC Control\n");
|
||||
usb_ep_disable(uvc->control_ep);
|
||||
|
||||
if (!uvc->control_ep->desc)
|
||||
if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
|
||||
return -EINVAL;
|
||||
|
||||
usb_ep_enable(uvc->control_ep);
|
||||
uvc->control_ep->driver_data = uvc;
|
||||
|
||||
if (uvc->state == UVC_STATE_DISCONNECTED) {
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
|
|
@ -336,10 +332,8 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
|||
if (uvc->state != UVC_STATE_STREAMING)
|
||||
return 0;
|
||||
|
||||
if (uvc->video.ep) {
|
||||
if (uvc->video.ep)
|
||||
usb_ep_disable(uvc->video.ep);
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
}
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_STREAMOFF;
|
||||
|
|
@ -355,18 +349,14 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
|||
if (!uvc->video.ep)
|
||||
return -EINVAL;
|
||||
|
||||
if (uvc->video.ep->driver_data) {
|
||||
INFO(cdev, "reset UVC\n");
|
||||
usb_ep_disable(uvc->video.ep);
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
}
|
||||
INFO(cdev, "reset UVC\n");
|
||||
usb_ep_disable(uvc->video.ep);
|
||||
|
||||
ret = config_ep_by_speed(f->config->cdev->gadget,
|
||||
&(uvc->func), uvc->video.ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
usb_ep_enable(uvc->video.ep);
|
||||
uvc->video.ep->driver_data = uvc;
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_STREAMON;
|
||||
|
|
@ -392,15 +382,8 @@ uvc_function_disable(struct usb_function *f)
|
|||
|
||||
uvc->state = UVC_STATE_DISCONNECTED;
|
||||
|
||||
if (uvc->video.ep->driver_data) {
|
||||
usb_ep_disable(uvc->video.ep);
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
}
|
||||
|
||||
if (uvc->control_ep->driver_data) {
|
||||
usb_ep_disable(uvc->control_ep);
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
}
|
||||
usb_ep_disable(uvc->video.ep);
|
||||
usb_ep_disable(uvc->control_ep);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
|
|
@ -651,7 +634,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
goto error;
|
||||
}
|
||||
uvc->control_ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
|
||||
|
|
@ -666,7 +648,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
goto error;
|
||||
}
|
||||
uvc->video.ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
|
|
@ -755,11 +736,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
error:
|
||||
v4l2_device_unregister(&uvc->v4l2_dev);
|
||||
|
||||
if (uvc->control_ep)
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
if (uvc->video.ep)
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
|
||||
if (uvc->control_req)
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
|
|
@ -886,8 +862,6 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
video_unregister_device(&uvc->vdev);
|
||||
v4l2_device_unregister(&uvc->v4l2_dev);
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@
|
|||
|
||||
#define UETH__VERSION "29-May-2008"
|
||||
|
||||
/* Experiments show that both Linux and Windows hosts allow up to 16k
|
||||
* frame sizes. Set the max size to 15k+52 to prevent allocating 32k
|
||||
* blocks and still have efficient handling. */
|
||||
#define GETHER_MAX_ETH_FRAME_LEN 15412
|
||||
|
||||
struct eth_dev {
|
||||
/* lock is held while accessing port_usb
|
||||
*/
|
||||
|
|
@ -146,7 +151,7 @@ static int ueth_change_mtu(struct net_device *net, int new_mtu)
|
|||
spin_lock_irqsave(&dev->lock, flags);
|
||||
if (dev->port_usb)
|
||||
status = -EBUSY;
|
||||
else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
|
||||
else if (new_mtu <= ETH_HLEN || new_mtu > GETHER_MAX_ETH_FRAME_LEN)
|
||||
status = -ERANGE;
|
||||
else
|
||||
net->mtu = new_mtu;
|
||||
|
|
@ -294,7 +299,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
while (skb2) {
|
||||
if (status < 0
|
||||
|| ETH_HLEN > skb2->len
|
||||
|| skb2->len > VLAN_ETH_FRAME_LEN) {
|
||||
|| skb2->len > GETHER_MAX_ETH_FRAME_LEN) {
|
||||
dev->net->stats.rx_errors++;
|
||||
dev->net->stats.rx_length_errors++;
|
||||
DBG(dev, "rx length %d\n", skb2->len);
|
||||
|
|
@ -1144,7 +1149,6 @@ void gether_disconnect(struct gether *link)
|
|||
spin_lock(&dev->req_lock);
|
||||
}
|
||||
spin_unlock(&dev->req_lock);
|
||||
link->in_ep->driver_data = NULL;
|
||||
link->in_ep->desc = NULL;
|
||||
|
||||
usb_ep_disable(link->out_ep);
|
||||
|
|
@ -1159,7 +1163,6 @@ void gether_disconnect(struct gether *link)
|
|||
spin_lock(&dev->req_lock);
|
||||
}
|
||||
spin_unlock(&dev->req_lock);
|
||||
link->out_ep->driver_data = NULL;
|
||||
link->out_ep->desc = NULL;
|
||||
|
||||
/* finish forgetting about this USB link episode */
|
||||
|
|
|
|||
|
|
@ -876,7 +876,6 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
|||
else
|
||||
gs_buf_clear(&port->port_write_buf);
|
||||
|
||||
tty->driver_data = NULL;
|
||||
port->port.tty = NULL;
|
||||
|
||||
port->openclose = false;
|
||||
|
|
@ -1224,7 +1223,6 @@ int gserial_connect(struct gserial *gser, u8 port_num)
|
|||
|
||||
fail_out:
|
||||
usb_ep_disable(gser->in);
|
||||
gser->in->driver_data = NULL;
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gserial_connect);
|
||||
|
|
@ -1264,10 +1262,7 @@ void gserial_disconnect(struct gserial *gser)
|
|||
|
||||
/* disable endpoints, aborting down any active I/O */
|
||||
usb_ep_disable(gser->out);
|
||||
gser->out->driver_data = NULL;
|
||||
|
||||
usb_ep_disable(gser->in);
|
||||
gser->in->driver_data = NULL;
|
||||
|
||||
/* finally, free any unused/unusable I/O buffers */
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
|
|
|
|||
|
|
@ -79,10 +79,7 @@ static int dbgp_consume(char *buf, unsigned len)
|
|||
|
||||
static void __disable_ep(struct usb_ep *ep)
|
||||
{
|
||||
if (ep && ep->driver_data == dbgp.gadget) {
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
usb_ep_disable(ep);
|
||||
}
|
||||
|
||||
static void dbgp_disable_ep(void)
|
||||
|
|
@ -171,7 +168,6 @@ static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
|
|||
int err;
|
||||
ep->desc = desc;
|
||||
err = usb_ep_enable(ep);
|
||||
ep->driver_data = dbgp.gadget;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -229,8 +225,6 @@ static void dbgp_unbind(struct usb_gadget *gadget)
|
|||
usb_ep_free_request(gadget->ep0, dbgp.req);
|
||||
dbgp.req = NULL;
|
||||
}
|
||||
|
||||
gadget->ep0->driver_data = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
|
|
@ -249,18 +243,15 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget)
|
|||
goto fail_1;
|
||||
}
|
||||
|
||||
dbgp.i_ep->driver_data = gadget;
|
||||
i_desc.wMaxPacketSize =
|
||||
cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
|
||||
|
||||
dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
|
||||
if (!dbgp.o_ep) {
|
||||
dbgp.i_ep->driver_data = NULL;
|
||||
stp = 2;
|
||||
goto fail_2;
|
||||
goto fail_1;
|
||||
}
|
||||
|
||||
dbgp.o_ep->driver_data = gadget;
|
||||
o_desc.wMaxPacketSize =
|
||||
cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
|
||||
|
||||
|
|
@ -277,8 +268,6 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget)
|
|||
|
||||
return 0;
|
||||
|
||||
fail_2:
|
||||
dbgp.i_ep->driver_data = NULL;
|
||||
fail_1:
|
||||
dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
|
||||
return -ENODEV;
|
||||
|
|
@ -306,7 +295,6 @@ static int dbgp_bind(struct usb_gadget *gadget,
|
|||
}
|
||||
|
||||
dbgp.req->length = DBGP_REQ_EP0_LEN;
|
||||
gadget->ep0->driver_data = gadget;
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
|
||||
|
|
@ -356,8 +344,6 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
void *data = NULL;
|
||||
u16 len = 0;
|
||||
|
||||
gadget->ep0->driver_data = gadget;
|
||||
|
||||
if (request == USB_REQ_GET_DESCRIPTOR) {
|
||||
switch (value>>8) {
|
||||
case USB_DT_DEVICE:
|
||||
|
|
|
|||
|
|
@ -2018,14 +2018,6 @@ static struct usb_configuration usbg_config_driver = {
|
|||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
|
||||
static void give_back_ep(struct usb_ep **pep)
|
||||
{
|
||||
struct usb_ep *ep = *pep;
|
||||
if (!ep)
|
||||
return;
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
|
||||
static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_uas *fu = to_f_uas(f);
|
||||
|
|
@ -2045,29 +2037,24 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
&uasp_bi_ep_comp_desc);
|
||||
if (!ep)
|
||||
goto ep_fail;
|
||||
|
||||
ep->driver_data = fu;
|
||||
fu->ep_in = ep;
|
||||
|
||||
ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
|
||||
&uasp_bo_ep_comp_desc);
|
||||
if (!ep)
|
||||
goto ep_fail;
|
||||
ep->driver_data = fu;
|
||||
fu->ep_out = ep;
|
||||
|
||||
ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
|
||||
&uasp_status_in_ep_comp_desc);
|
||||
if (!ep)
|
||||
goto ep_fail;
|
||||
ep->driver_data = fu;
|
||||
fu->ep_status = ep;
|
||||
|
||||
ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
|
||||
&uasp_cmd_comp_desc);
|
||||
if (!ep)
|
||||
goto ep_fail;
|
||||
ep->driver_data = fu;
|
||||
fu->ep_cmd = ep;
|
||||
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
|
|
@ -2091,11 +2078,6 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
ep_fail:
|
||||
pr_err("Can't claim all required eps\n");
|
||||
|
||||
give_back_ep(&fu->ep_in);
|
||||
give_back_ep(&fu->ep_out);
|
||||
give_back_ep(&fu->ep_status);
|
||||
give_back_ep(&fu->ep_cmd);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ config USB_LPC32XX
|
|||
|
||||
config USB_ATMEL_USBA
|
||||
tristate "Atmel USBA"
|
||||
depends on AVR32 || ARCH_AT91
|
||||
depends on ((AVR32 && !OF) || ARCH_AT91)
|
||||
help
|
||||
USBA is the integrated high-speed USB Device controller on
|
||||
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
|
||||
|
|
|
|||
|
|
@ -65,18 +65,10 @@
|
|||
|
||||
static void udc_tasklet_disconnect(unsigned long);
|
||||
static void empty_req_queue(struct udc_ep *);
|
||||
static int udc_probe(struct udc *dev);
|
||||
static void udc_basic_init(struct udc *dev);
|
||||
static void udc_setup_endpoints(struct udc *dev);
|
||||
static void udc_soft_reset(struct udc *dev);
|
||||
static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
|
||||
static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
|
||||
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
|
||||
static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
|
||||
unsigned long buf_len, gfp_t gfp_flags);
|
||||
static int udc_remote_wakeup(struct udc *dev);
|
||||
static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
|
||||
static void udc_pci_remove(struct pci_dev *pdev);
|
||||
|
||||
/* description */
|
||||
static const char mod_desc[] = UDC_MOD_DESCRIPTION;
|
||||
|
|
@ -615,6 +607,30 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
|
|||
return &req->req;
|
||||
}
|
||||
|
||||
/* frees pci pool descriptors of a DMA chain */
|
||||
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct udc_data_dma *td;
|
||||
struct udc_data_dma *td_last = NULL;
|
||||
unsigned int i;
|
||||
|
||||
DBG(dev, "free chain req = %p\n", req);
|
||||
|
||||
/* do not free first desc., will be done by free for request */
|
||||
td_last = req->td_data;
|
||||
td = phys_to_virt(td_last->next);
|
||||
|
||||
for (i = 1; i < req->chain_len; i++) {
|
||||
pci_pool_free(dev->data_requests, td,
|
||||
(dma_addr_t)td_last->next);
|
||||
td_last = td;
|
||||
td = phys_to_virt(td_last->next);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Frees request packet, called by gadget driver */
|
||||
static void
|
||||
udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
|
||||
|
|
@ -789,6 +805,123 @@ udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
|
|||
return finished;
|
||||
}
|
||||
|
||||
/* Creates or re-inits a DMA chain */
|
||||
static int udc_create_dma_chain(
|
||||
struct udc_ep *ep,
|
||||
struct udc_request *req,
|
||||
unsigned long buf_len, gfp_t gfp_flags
|
||||
)
|
||||
{
|
||||
unsigned long bytes = req->req.length;
|
||||
unsigned int i;
|
||||
dma_addr_t dma_addr;
|
||||
struct udc_data_dma *td = NULL;
|
||||
struct udc_data_dma *last = NULL;
|
||||
unsigned long txbytes;
|
||||
unsigned create_new_chain = 0;
|
||||
unsigned len;
|
||||
|
||||
VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
|
||||
bytes, buf_len);
|
||||
dma_addr = DMA_DONT_USE;
|
||||
|
||||
/* unset L bit in first desc for OUT */
|
||||
if (!ep->in)
|
||||
req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
|
||||
|
||||
/* alloc only new desc's if not already available */
|
||||
len = req->req.length / ep->ep.maxpacket;
|
||||
if (req->req.length % ep->ep.maxpacket)
|
||||
len++;
|
||||
|
||||
if (len > req->chain_len) {
|
||||
/* shorter chain already allocated before */
|
||||
if (req->chain_len > 1)
|
||||
udc_free_dma_chain(ep->dev, req);
|
||||
req->chain_len = len;
|
||||
create_new_chain = 1;
|
||||
}
|
||||
|
||||
td = req->td_data;
|
||||
/* gen. required number of descriptors and buffers */
|
||||
for (i = buf_len; i < bytes; i += buf_len) {
|
||||
/* create or determine next desc. */
|
||||
if (create_new_chain) {
|
||||
td = pci_pool_alloc(ep->dev->data_requests,
|
||||
gfp_flags, &dma_addr);
|
||||
if (!td)
|
||||
return -ENOMEM;
|
||||
|
||||
td->status = 0;
|
||||
} else if (i == buf_len) {
|
||||
/* first td */
|
||||
td = (struct udc_data_dma *)phys_to_virt(
|
||||
req->td_data->next);
|
||||
td->status = 0;
|
||||
} else {
|
||||
td = (struct udc_data_dma *)phys_to_virt(last->next);
|
||||
td->status = 0;
|
||||
}
|
||||
|
||||
if (td)
|
||||
td->bufptr = req->req.dma + i; /* assign buffer */
|
||||
else
|
||||
break;
|
||||
|
||||
/* short packet ? */
|
||||
if ((bytes - i) >= buf_len) {
|
||||
txbytes = buf_len;
|
||||
} else {
|
||||
/* short packet */
|
||||
txbytes = bytes - i;
|
||||
}
|
||||
|
||||
/* link td and assign tx bytes */
|
||||
if (i == buf_len) {
|
||||
if (create_new_chain)
|
||||
req->td_data->next = dma_addr;
|
||||
/*
|
||||
* else
|
||||
* req->td_data->next = virt_to_phys(td);
|
||||
*/
|
||||
/* write tx bytes */
|
||||
if (ep->in) {
|
||||
/* first desc */
|
||||
req->td_data->status =
|
||||
AMD_ADDBITS(req->td_data->status,
|
||||
ep->ep.maxpacket,
|
||||
UDC_DMA_IN_STS_TXBYTES);
|
||||
/* second desc */
|
||||
td->status = AMD_ADDBITS(td->status,
|
||||
txbytes,
|
||||
UDC_DMA_IN_STS_TXBYTES);
|
||||
}
|
||||
} else {
|
||||
if (create_new_chain)
|
||||
last->next = dma_addr;
|
||||
/*
|
||||
* else
|
||||
* last->next = virt_to_phys(td);
|
||||
*/
|
||||
if (ep->in) {
|
||||
/* write tx bytes */
|
||||
td->status = AMD_ADDBITS(td->status,
|
||||
txbytes,
|
||||
UDC_DMA_IN_STS_TXBYTES);
|
||||
}
|
||||
}
|
||||
last = td;
|
||||
}
|
||||
/* set last bit */
|
||||
if (td) {
|
||||
td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
|
||||
/* last desc. points to itself */
|
||||
req->td_data_last = td;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create/re-init a DMA descriptor or a DMA descriptor chain */
|
||||
static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
|
||||
{
|
||||
|
|
@ -913,32 +1046,6 @@ __acquires(ep->dev->lock)
|
|||
ep->halted = halted;
|
||||
}
|
||||
|
||||
/* frees pci pool descriptors of a DMA chain */
|
||||
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
|
||||
{
|
||||
|
||||
int ret_val = 0;
|
||||
struct udc_data_dma *td;
|
||||
struct udc_data_dma *td_last = NULL;
|
||||
unsigned int i;
|
||||
|
||||
DBG(dev, "free chain req = %p\n", req);
|
||||
|
||||
/* do not free first desc., will be done by free for request */
|
||||
td_last = req->td_data;
|
||||
td = phys_to_virt(td_last->next);
|
||||
|
||||
for (i = 1; i < req->chain_len; i++) {
|
||||
|
||||
pci_pool_free(dev->data_requests, td,
|
||||
(dma_addr_t) td_last->next);
|
||||
td_last = td;
|
||||
td = phys_to_virt(td_last->next);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Iterates to the end of a DMA chain and returns last descriptor */
|
||||
static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
|
||||
{
|
||||
|
|
@ -975,125 +1082,6 @@ static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
|
|||
|
||||
}
|
||||
|
||||
/* Creates or re-inits a DMA chain */
|
||||
static int udc_create_dma_chain(
|
||||
struct udc_ep *ep,
|
||||
struct udc_request *req,
|
||||
unsigned long buf_len, gfp_t gfp_flags
|
||||
)
|
||||
{
|
||||
unsigned long bytes = req->req.length;
|
||||
unsigned int i;
|
||||
dma_addr_t dma_addr;
|
||||
struct udc_data_dma *td = NULL;
|
||||
struct udc_data_dma *last = NULL;
|
||||
unsigned long txbytes;
|
||||
unsigned create_new_chain = 0;
|
||||
unsigned len;
|
||||
|
||||
VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
|
||||
bytes, buf_len);
|
||||
dma_addr = DMA_DONT_USE;
|
||||
|
||||
/* unset L bit in first desc for OUT */
|
||||
if (!ep->in)
|
||||
req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
|
||||
|
||||
/* alloc only new desc's if not already available */
|
||||
len = req->req.length / ep->ep.maxpacket;
|
||||
if (req->req.length % ep->ep.maxpacket)
|
||||
len++;
|
||||
|
||||
if (len > req->chain_len) {
|
||||
/* shorter chain already allocated before */
|
||||
if (req->chain_len > 1)
|
||||
udc_free_dma_chain(ep->dev, req);
|
||||
req->chain_len = len;
|
||||
create_new_chain = 1;
|
||||
}
|
||||
|
||||
td = req->td_data;
|
||||
/* gen. required number of descriptors and buffers */
|
||||
for (i = buf_len; i < bytes; i += buf_len) {
|
||||
/* create or determine next desc. */
|
||||
if (create_new_chain) {
|
||||
|
||||
td = pci_pool_alloc(ep->dev->data_requests,
|
||||
gfp_flags, &dma_addr);
|
||||
if (!td)
|
||||
return -ENOMEM;
|
||||
|
||||
td->status = 0;
|
||||
} else if (i == buf_len) {
|
||||
/* first td */
|
||||
td = (struct udc_data_dma *) phys_to_virt(
|
||||
req->td_data->next);
|
||||
td->status = 0;
|
||||
} else {
|
||||
td = (struct udc_data_dma *) phys_to_virt(last->next);
|
||||
td->status = 0;
|
||||
}
|
||||
|
||||
|
||||
if (td)
|
||||
td->bufptr = req->req.dma + i; /* assign buffer */
|
||||
else
|
||||
break;
|
||||
|
||||
/* short packet ? */
|
||||
if ((bytes - i) >= buf_len) {
|
||||
txbytes = buf_len;
|
||||
} else {
|
||||
/* short packet */
|
||||
txbytes = bytes - i;
|
||||
}
|
||||
|
||||
/* link td and assign tx bytes */
|
||||
if (i == buf_len) {
|
||||
if (create_new_chain)
|
||||
req->td_data->next = dma_addr;
|
||||
/*
|
||||
else
|
||||
req->td_data->next = virt_to_phys(td);
|
||||
*/
|
||||
/* write tx bytes */
|
||||
if (ep->in) {
|
||||
/* first desc */
|
||||
req->td_data->status =
|
||||
AMD_ADDBITS(req->td_data->status,
|
||||
ep->ep.maxpacket,
|
||||
UDC_DMA_IN_STS_TXBYTES);
|
||||
/* second desc */
|
||||
td->status = AMD_ADDBITS(td->status,
|
||||
txbytes,
|
||||
UDC_DMA_IN_STS_TXBYTES);
|
||||
}
|
||||
} else {
|
||||
if (create_new_chain)
|
||||
last->next = dma_addr;
|
||||
/*
|
||||
else
|
||||
last->next = virt_to_phys(td);
|
||||
*/
|
||||
if (ep->in) {
|
||||
/* write tx bytes */
|
||||
td->status = AMD_ADDBITS(td->status,
|
||||
txbytes,
|
||||
UDC_DMA_IN_STS_TXBYTES);
|
||||
}
|
||||
}
|
||||
last = td;
|
||||
}
|
||||
/* set last bit */
|
||||
if (td) {
|
||||
td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
|
||||
/* last desc. points to itself */
|
||||
req->td_data_last = td;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enabling RX DMA */
|
||||
static void udc_set_rde(struct udc *dev)
|
||||
{
|
||||
|
|
@ -1453,6 +1441,26 @@ static int udc_get_frame(struct usb_gadget *gadget)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Initiates a remote wakeup */
|
||||
static int udc_remote_wakeup(struct udc *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
DBG(dev, "UDC initiates remote wakeup\n");
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
tmp = readl(&dev->regs->ctl);
|
||||
tmp |= AMD_BIT(UDC_DEVCTL_RES);
|
||||
writel(tmp, &dev->regs->ctl);
|
||||
tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
|
||||
writel(tmp, &dev->regs->ctl);
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remote wakeup gadget interface */
|
||||
static int udc_wakeup(struct usb_gadget *gadget)
|
||||
{
|
||||
|
|
@ -1498,33 +1506,6 @@ static void make_ep_lists(struct udc *dev)
|
|||
dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
|
||||
}
|
||||
|
||||
/* init registers at driver load time */
|
||||
static int startup_registers(struct udc *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* init controller by soft reset */
|
||||
udc_soft_reset(dev);
|
||||
|
||||
/* mask not needed interrupts */
|
||||
udc_mask_unused_interrupts(dev);
|
||||
|
||||
/* put into initial config */
|
||||
udc_basic_init(dev);
|
||||
/* link up all endpoints */
|
||||
udc_setup_endpoints(dev);
|
||||
|
||||
/* program speed */
|
||||
tmp = readl(&dev->regs->cfg);
|
||||
if (use_fullspeed)
|
||||
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
|
||||
else
|
||||
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
|
||||
writel(tmp, &dev->regs->cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Inits UDC context */
|
||||
static void udc_basic_init(struct udc *dev)
|
||||
{
|
||||
|
|
@ -1563,6 +1544,33 @@ static void udc_basic_init(struct udc *dev)
|
|||
dev->data_ep_queued = 0;
|
||||
}
|
||||
|
||||
/* init registers at driver load time */
|
||||
static int startup_registers(struct udc *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* init controller by soft reset */
|
||||
udc_soft_reset(dev);
|
||||
|
||||
/* mask not needed interrupts */
|
||||
udc_mask_unused_interrupts(dev);
|
||||
|
||||
/* put into initial config */
|
||||
udc_basic_init(dev);
|
||||
/* link up all endpoints */
|
||||
udc_setup_endpoints(dev);
|
||||
|
||||
/* program speed */
|
||||
tmp = readl(&dev->regs->cfg);
|
||||
if (use_fullspeed)
|
||||
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
|
||||
else
|
||||
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
|
||||
writel(tmp, &dev->regs->cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sets initial endpoint parameters */
|
||||
static void udc_setup_endpoints(struct udc *dev)
|
||||
{
|
||||
|
|
@ -2177,7 +2185,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
|
|||
}
|
||||
|
||||
/* DMA */
|
||||
} else if (!ep->cancel_transfer && req != NULL) {
|
||||
} else if (!ep->cancel_transfer && req) {
|
||||
ret_val = IRQ_HANDLED;
|
||||
|
||||
/* check for DMA done */
|
||||
|
|
@ -3107,6 +3115,17 @@ static void udc_remove(struct udc *dev)
|
|||
udc = NULL;
|
||||
}
|
||||
|
||||
/* free all the dma pools */
|
||||
static void free_dma_pools(struct udc *dev)
|
||||
{
|
||||
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td,
|
||||
dev->ep[UDC_EP0OUT_IX].td_phys);
|
||||
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
|
||||
dev->ep[UDC_EP0OUT_IX].td_stp_dma);
|
||||
dma_pool_destroy(dev->stp_requests);
|
||||
dma_pool_destroy(dev->data_requests);
|
||||
}
|
||||
|
||||
/* Reset all pci context */
|
||||
static void udc_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
|
|
@ -3116,35 +3135,19 @@ static void udc_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
/* gadget driver must not be registered */
|
||||
BUG_ON(dev->driver != NULL);
|
||||
if (WARN_ON(dev->driver))
|
||||
return;
|
||||
|
||||
/* dma pool cleanup */
|
||||
if (dev->data_requests)
|
||||
pci_pool_destroy(dev->data_requests);
|
||||
|
||||
if (dev->stp_requests) {
|
||||
/* cleanup DMA desc's for ep0in */
|
||||
pci_pool_free(dev->stp_requests,
|
||||
dev->ep[UDC_EP0OUT_IX].td_stp,
|
||||
dev->ep[UDC_EP0OUT_IX].td_stp_dma);
|
||||
pci_pool_free(dev->stp_requests,
|
||||
dev->ep[UDC_EP0OUT_IX].td,
|
||||
dev->ep[UDC_EP0OUT_IX].td_phys);
|
||||
|
||||
pci_pool_destroy(dev->stp_requests);
|
||||
}
|
||||
free_dma_pools(dev);
|
||||
|
||||
/* reset controller */
|
||||
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
|
||||
if (dev->irq_registered)
|
||||
free_irq(pdev->irq, dev);
|
||||
if (dev->virt_addr)
|
||||
iounmap(dev->virt_addr);
|
||||
if (dev->mem_region)
|
||||
release_mem_region(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
if (dev->active)
|
||||
pci_disable_device(pdev);
|
||||
free_irq(pdev->irq, dev);
|
||||
iounmap(dev->virt_addr);
|
||||
release_mem_region(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
pci_disable_device(pdev);
|
||||
|
||||
udc_remove(dev);
|
||||
}
|
||||
|
|
@ -3169,8 +3172,7 @@ static int init_dma_pools(struct udc *dev)
|
|||
sizeof(struct udc_data_dma), 0, 0);
|
||||
if (!dev->data_requests) {
|
||||
DBG(dev, "can't get request data pool\n");
|
||||
retval = -ENOMEM;
|
||||
goto finished;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* EP0 in dma regs = dev control regs */
|
||||
|
|
@ -3182,27 +3184,101 @@ static int init_dma_pools(struct udc *dev)
|
|||
if (!dev->stp_requests) {
|
||||
DBG(dev, "can't get stp request pool\n");
|
||||
retval = -ENOMEM;
|
||||
goto finished;
|
||||
goto err_create_dma_pool;
|
||||
}
|
||||
/* setup */
|
||||
td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
|
||||
&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
|
||||
if (td_stp == NULL) {
|
||||
if (!td_stp) {
|
||||
retval = -ENOMEM;
|
||||
goto finished;
|
||||
goto err_alloc_dma;
|
||||
}
|
||||
dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
|
||||
|
||||
/* data: 0 packets !? */
|
||||
td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
|
||||
&dev->ep[UDC_EP0OUT_IX].td_phys);
|
||||
if (td_data == NULL) {
|
||||
if (!td_data) {
|
||||
retval = -ENOMEM;
|
||||
goto finished;
|
||||
goto err_alloc_phys;
|
||||
}
|
||||
dev->ep[UDC_EP0OUT_IX].td = td_data;
|
||||
return 0;
|
||||
|
||||
err_alloc_phys:
|
||||
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
|
||||
dev->ep[UDC_EP0OUT_IX].td_stp_dma);
|
||||
err_alloc_dma:
|
||||
dma_pool_destroy(dev->stp_requests);
|
||||
dev->stp_requests = NULL;
|
||||
err_create_dma_pool:
|
||||
dma_pool_destroy(dev->data_requests);
|
||||
dev->data_requests = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* general probe */
|
||||
static int udc_probe(struct udc *dev)
|
||||
{
|
||||
char tmp[128];
|
||||
u32 reg;
|
||||
int retval;
|
||||
|
||||
/* mark timer as not initialized */
|
||||
udc_timer.data = 0;
|
||||
udc_pollstall_timer.data = 0;
|
||||
|
||||
/* device struct setup */
|
||||
dev->gadget.ops = &udc_ops;
|
||||
|
||||
dev_set_name(&dev->gadget.dev, "gadget");
|
||||
dev->gadget.name = name;
|
||||
dev->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
||||
/* init registers, interrupts, ... */
|
||||
startup_registers(dev);
|
||||
|
||||
dev_info(&dev->pdev->dev, "%s\n", mod_desc);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%d", dev->irq);
|
||||
dev_info(&dev->pdev->dev,
|
||||
"irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
|
||||
tmp, dev->phys_addr, dev->chiprev,
|
||||
(dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
|
||||
strcpy(tmp, UDC_DRIVER_VERSION_STRING);
|
||||
if (dev->chiprev == UDC_HSA0_REV) {
|
||||
dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
dev_info(&dev->pdev->dev,
|
||||
"driver version: %s(for Geode5536 B1)\n", tmp);
|
||||
udc = dev;
|
||||
|
||||
retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto finished;
|
||||
|
||||
/* timer init */
|
||||
init_timer(&udc_timer);
|
||||
udc_timer.function = udc_timer_function;
|
||||
udc_timer.data = 1;
|
||||
/* timer pollstall init */
|
||||
init_timer(&udc_pollstall_timer);
|
||||
udc_pollstall_timer.function = udc_pollstall_timer_function;
|
||||
udc_pollstall_timer.data = 1;
|
||||
|
||||
/* set SD */
|
||||
reg = readl(&dev->regs->ctl);
|
||||
reg |= AMD_BIT(UDC_DEVCTL_SD);
|
||||
writel(reg, &dev->regs->ctl);
|
||||
|
||||
/* print dev register info */
|
||||
print_regs(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
finished:
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -3234,7 +3310,6 @@ static int udc_pci_probe(
|
|||
retval = -ENODEV;
|
||||
goto err_pcidev;
|
||||
}
|
||||
dev->active = 1;
|
||||
|
||||
/* PCI resource allocation */
|
||||
resource = pci_resource_start(pdev, 0);
|
||||
|
|
@ -3245,10 +3320,9 @@ static int udc_pci_probe(
|
|||
retval = -EBUSY;
|
||||
goto err_memreg;
|
||||
}
|
||||
dev->mem_region = 1;
|
||||
|
||||
dev->virt_addr = ioremap_nocache(resource, len);
|
||||
if (dev->virt_addr == NULL) {
|
||||
if (!dev->virt_addr) {
|
||||
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
|
||||
retval = -EFAULT;
|
||||
goto err_ioremap;
|
||||
|
|
@ -3276,7 +3350,6 @@ static int udc_pci_probe(
|
|||
retval = -EBUSY;
|
||||
goto err_irq;
|
||||
}
|
||||
dev->irq_registered = 1;
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
|
|
@ -3290,7 +3363,7 @@ static int udc_pci_probe(
|
|||
if (use_dma) {
|
||||
retval = init_dma_pools(dev);
|
||||
if (retval != 0)
|
||||
goto finished;
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
dev->phys_addr = resource;
|
||||
|
|
@ -3298,13 +3371,17 @@ static int udc_pci_probe(
|
|||
dev->pdev = pdev;
|
||||
|
||||
/* general probing */
|
||||
if (udc_probe(dev) == 0)
|
||||
return 0;
|
||||
|
||||
finished:
|
||||
udc_pci_remove(pdev);
|
||||
return retval;
|
||||
if (udc_probe(dev)) {
|
||||
retval = -ENODEV;
|
||||
goto err_probe;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_probe:
|
||||
if (use_dma)
|
||||
free_dma_pools(dev);
|
||||
err_dma:
|
||||
free_irq(pdev->irq, dev);
|
||||
err_irq:
|
||||
iounmap(dev->virt_addr);
|
||||
err_ioremap:
|
||||
|
|
@ -3316,92 +3393,6 @@ err_pcidev:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/* general probe */
|
||||
static int udc_probe(struct udc *dev)
|
||||
{
|
||||
char tmp[128];
|
||||
u32 reg;
|
||||
int retval;
|
||||
|
||||
/* mark timer as not initialized */
|
||||
udc_timer.data = 0;
|
||||
udc_pollstall_timer.data = 0;
|
||||
|
||||
/* device struct setup */
|
||||
dev->gadget.ops = &udc_ops;
|
||||
|
||||
dev_set_name(&dev->gadget.dev, "gadget");
|
||||
dev->gadget.name = name;
|
||||
dev->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
||||
/* init registers, interrupts, ... */
|
||||
startup_registers(dev);
|
||||
|
||||
dev_info(&dev->pdev->dev, "%s\n", mod_desc);
|
||||
|
||||
snprintf(tmp, sizeof tmp, "%d", dev->irq);
|
||||
dev_info(&dev->pdev->dev,
|
||||
"irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
|
||||
tmp, dev->phys_addr, dev->chiprev,
|
||||
(dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
|
||||
strcpy(tmp, UDC_DRIVER_VERSION_STRING);
|
||||
if (dev->chiprev == UDC_HSA0_REV) {
|
||||
dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
dev_info(&dev->pdev->dev,
|
||||
"driver version: %s(for Geode5536 B1)\n", tmp);
|
||||
udc = dev;
|
||||
|
||||
retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto finished;
|
||||
|
||||
/* timer init */
|
||||
init_timer(&udc_timer);
|
||||
udc_timer.function = udc_timer_function;
|
||||
udc_timer.data = 1;
|
||||
/* timer pollstall init */
|
||||
init_timer(&udc_pollstall_timer);
|
||||
udc_pollstall_timer.function = udc_pollstall_timer_function;
|
||||
udc_pollstall_timer.data = 1;
|
||||
|
||||
/* set SD */
|
||||
reg = readl(&dev->regs->ctl);
|
||||
reg |= AMD_BIT(UDC_DEVCTL_SD);
|
||||
writel(reg, &dev->regs->ctl);
|
||||
|
||||
/* print dev register info */
|
||||
print_regs(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
finished:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Initiates a remote wakeup */
|
||||
static int udc_remote_wakeup(struct udc *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
DBG(dev, "UDC initiates remote wakeup\n");
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
tmp = readl(&dev->regs->ctl);
|
||||
tmp |= AMD_BIT(UDC_DEVCTL_RES);
|
||||
writel(tmp, &dev->regs->ctl);
|
||||
tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
|
||||
writel(tmp, &dev->regs->ctl);
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCI device parameters */
|
||||
static const struct pci_device_id pci_id[] = {
|
||||
{
|
||||
|
|
|
|||
|
|
@ -526,14 +526,11 @@ struct udc {
|
|||
struct udc_ep ep[UDC_EP_NUM];
|
||||
struct usb_gadget_driver *driver;
|
||||
/* operational flags */
|
||||
unsigned active : 1,
|
||||
stall_ep0in : 1,
|
||||
unsigned stall_ep0in : 1,
|
||||
waiting_zlp_ack_ep0in : 1,
|
||||
set_cfg_not_acked : 1,
|
||||
irq_registered : 1,
|
||||
data_ep_enabled : 1,
|
||||
data_ep_queued : 1,
|
||||
mem_region : 1,
|
||||
sys_suspended : 1,
|
||||
connected;
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,14 @@ struct at91_udc_caps {
|
|||
void (*pullup)(struct at91_udc *udc, int is_on);
|
||||
};
|
||||
|
||||
struct at91_udc_data {
|
||||
int vbus_pin; /* high == host powering us */
|
||||
u8 vbus_active_low; /* vbus polarity */
|
||||
u8 vbus_polled; /* Use polling, not interrupt */
|
||||
int pullup_pin; /* active == D+ pulled up */
|
||||
u8 pullup_active_low; /* true == pullup_pin is active low */
|
||||
};
|
||||
|
||||
/*
|
||||
* driver is non-SMP, and just blocks IRQs whenever it needs
|
||||
* access protection for chip registers or driver state
|
||||
|
|
|
|||
|
|
@ -833,10 +833,10 @@ static const struct usb_ep_ops dummy_ep_ops = {
|
|||
/* there are both host and device side versions of this call ... */
|
||||
static int dummy_g_get_frame(struct usb_gadget *_gadget)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timespec64 ts64;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
return tv.tv_usec / 1000;
|
||||
ktime_get_ts64(&ts64);
|
||||
return ts64.tv_nsec / NSEC_PER_MSEC;
|
||||
}
|
||||
|
||||
static int dummy_wakeup(struct usb_gadget *_gadget)
|
||||
|
|
|
|||
|
|
@ -1913,7 +1913,7 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
|
|||
|
||||
for (i = 1; i < 5; i++) {
|
||||
ep = &dev->ep[i];
|
||||
writel(0, &ep->cfg->ep_cfg);
|
||||
writel(i, &ep->cfg->ep_cfg);
|
||||
}
|
||||
|
||||
/* CSROUT, CSRIN, PCIOUT, PCIIN, STATIN, RCIN */
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ struct pch_vbus_gpio_data {
|
|||
* @prot_stall: protcol stall requested
|
||||
* @irq_registered: irq registered with system
|
||||
* @mem_region: device memory mapped
|
||||
* @registered: driver regsitered with system
|
||||
* @registered: driver registered with system
|
||||
* @suspended: driver in suspended state
|
||||
* @connected: gadget driver associated
|
||||
* @vbus_session: required vbus_session state
|
||||
|
|
@ -2747,18 +2747,18 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
|
|||
if (dev_intr & UDC_DEVINT_US) {
|
||||
if (dev->driver
|
||||
&& dev->driver->suspend) {
|
||||
spin_lock(&dev->lock);
|
||||
dev->driver->suspend(&dev->gadget);
|
||||
spin_unlock(&dev->lock);
|
||||
dev->driver->suspend(&dev->gadget);
|
||||
spin_lock(&dev->lock);
|
||||
}
|
||||
|
||||
vbus = pch_vbus_gpio_get_value(dev);
|
||||
if ((dev->vbus_session == 0)
|
||||
&& (vbus != 1)) {
|
||||
if (dev->driver && dev->driver->disconnect) {
|
||||
spin_lock(&dev->lock);
|
||||
dev->driver->disconnect(&dev->gadget);
|
||||
spin_unlock(&dev->lock);
|
||||
dev->driver->disconnect(&dev->gadget);
|
||||
spin_lock(&dev->lock);
|
||||
}
|
||||
pch_udc_reconnect(dev);
|
||||
} else if ((dev->vbus_session == 0)
|
||||
|
|
|
|||
|
|
@ -348,16 +348,6 @@ config USB_ISP1362_HCD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called isp1362-hcd.
|
||||
|
||||
config USB_FUSBH200_HCD
|
||||
tristate "FUSBH200 HCD support"
|
||||
depends on USB
|
||||
---help---
|
||||
Faraday FUSBH200 is designed to meet USB2.0 EHCI specification
|
||||
with minor modification.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called fusbh200-hcd.
|
||||
|
||||
config USB_FOTG210_HCD
|
||||
tristate "FOTG210 HCD support"
|
||||
depends on USB
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ ifneq ($(CONFIG_USB), )
|
|||
obj-$(CONFIG_PCI) += pci-quirks.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
|
||||
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.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
|
||||
|
|
@ -65,6 +62,8 @@ obj-$(CONFIG_USB_OHCI_HCD_PXA27X) += ohci-pxa27x.o
|
|||
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
|
||||
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
|
||||
obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o
|
||||
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
|
||||
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
|
||||
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
|
||||
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
|
||||
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
|
||||
|
|
@ -75,6 +74,5 @@ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
|
|||
obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
|
||||
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
|
||||
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
|
||||
obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o
|
||||
obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
|
||||
obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o
|
||||
|
|
|
|||
|
|
@ -80,12 +80,12 @@ static int ehci_msm_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hcd->irq = platform_get_irq(pdev, 0);
|
||||
if (hcd->irq < 0) {
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
|
||||
ret = hcd->irq;
|
||||
goto put_hcd;
|
||||
}
|
||||
hcd->irq = ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
|
|
|
|||
|
|
@ -224,7 +224,8 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
|
|||
priv->phy = devm_phy_optional_get(&pdev->dev, "usb");
|
||||
if (IS_ERR(priv->phy)) {
|
||||
err = PTR_ERR(priv->phy);
|
||||
goto err_phy_get;
|
||||
if (err != -ENOSYS)
|
||||
goto err_phy_get;
|
||||
} else {
|
||||
err = phy_init(priv->phy);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -162,8 +163,10 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
|
||||
err = dma_coerce_mask_and_coherent(&dev->dev,
|
||||
pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
|
||||
if (err)
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Error: DMA mask configuration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(dev, 0);
|
||||
if (irq < 0) {
|
||||
|
|
@ -385,6 +388,12 @@ static const struct of_device_id vt8500_ehci_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
|
||||
|
||||
static const struct acpi_device_id ehci_acpi_match[] = {
|
||||
{ "PNP0D20", 0 }, /* EHCI controller without debug */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ehci_acpi_match);
|
||||
|
||||
static const struct platform_device_id ehci_platform_table[] = {
|
||||
{ "ehci-platform", 0 },
|
||||
{ }
|
||||
|
|
@ -403,6 +412,7 @@ static struct platform_driver ehci_platform_driver = {
|
|||
.name = "ehci-platform",
|
||||
.pm = &ehci_platform_pm_ops,
|
||||
.of_match_table = vt8500_ehci_ids,
|
||||
.acpi_match_table = ACPI_PTR(ehci_acpi_match),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ static const struct of_device_id spear_ehci_id_table[] = {
|
|||
{ .compatible = "st,spear600-ehci", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spear_ehci_id_table);
|
||||
|
||||
static struct platform_driver spear_ehci_hcd_driver = {
|
||||
.probe = spear_ehci_hcd_drv_probe,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -137,19 +137,25 @@ struct fotg210_hcd { /* one per controller */
|
|||
/* per root hub port */
|
||||
unsigned long reset_done[FOTG210_MAX_ROOT_PORTS];
|
||||
|
||||
/* bit vectors (one bit per port) */
|
||||
unsigned long bus_suspended; /* which ports were
|
||||
already suspended at the start of a bus suspend */
|
||||
unsigned long companion_ports; /* which ports are
|
||||
dedicated to the companion controller */
|
||||
unsigned long owned_ports; /* which ports are
|
||||
owned by the companion during a bus suspend */
|
||||
unsigned long port_c_suspend; /* which ports have
|
||||
the change-suspend feature turned on */
|
||||
unsigned long suspended_ports; /* which ports are
|
||||
suspended */
|
||||
unsigned long resuming_ports; /* which ports have
|
||||
started to resume */
|
||||
/* bit vectors (one bit per port)
|
||||
* which ports were already suspended at the start of a bus suspend
|
||||
*/
|
||||
unsigned long bus_suspended;
|
||||
|
||||
/* which ports are edicated to the companion controller */
|
||||
unsigned long companion_ports;
|
||||
|
||||
/* which ports are owned by the companion during a bus suspend */
|
||||
unsigned long owned_ports;
|
||||
|
||||
/* which ports have the change-suspend feature turned on */
|
||||
unsigned long port_c_suspend;
|
||||
|
||||
/* which ports are suspended */
|
||||
unsigned long suspended_ports;
|
||||
|
||||
/* which ports have started to resume */
|
||||
unsigned long resuming_ports;
|
||||
|
||||
/* per-HC memory pools (could be per-bus, but ...) */
|
||||
struct dma_pool *qh_pool; /* qh per active urb */
|
||||
|
|
@ -585,10 +591,10 @@ struct fotg210_fstn {
|
|||
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
|
||||
|
||||
#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \
|
||||
fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup);
|
||||
fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup)
|
||||
|
||||
#define fotg210_prepare_ports_for_controller_resume(fotg210) \
|
||||
fotg210_adjust_port_wakeup_flags(fotg210, false, false);
|
||||
fotg210_adjust_port_wakeup_flags(fotg210, false, false)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
|
|||
#endif
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsl_usb2_mph_dr_of_match);
|
||||
|
||||
static struct platform_driver fsl_usb2_mph_dr_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,675 +0,0 @@
|
|||
#ifndef __LINUX_FUSBH200_H
|
||||
#define __LINUX_FUSBH200_H
|
||||
|
||||
#include <linux/usb/ehci-dbgp.h>
|
||||
|
||||
/* definitions used for the EHCI driver */
|
||||
|
||||
/*
|
||||
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
|
||||
* __leXX (normally) or __beXX (given FUSBH200_BIG_ENDIAN_DESC), depending on
|
||||
* the host controller implementation.
|
||||
*
|
||||
* To facilitate the strongest possible byte-order checking from "sparse"
|
||||
* and so on, we use __leXX unless that's not practical.
|
||||
*/
|
||||
#define __hc32 __le32
|
||||
#define __hc16 __le16
|
||||
|
||||
/* statistics can be kept for tuning/monitoring */
|
||||
struct fusbh200_stats {
|
||||
/* irq usage */
|
||||
unsigned long normal;
|
||||
unsigned long error;
|
||||
unsigned long iaa;
|
||||
unsigned long lost_iaa;
|
||||
|
||||
/* termination of urbs from core */
|
||||
unsigned long complete;
|
||||
unsigned long unlink;
|
||||
};
|
||||
|
||||
/* fusbh200_hcd->lock guards shared data against other CPUs:
|
||||
* fusbh200_hcd: async, unlink, periodic (and shadow), ...
|
||||
* usb_host_endpoint: hcpriv
|
||||
* fusbh200_qh: qh_next, qtd_list
|
||||
* fusbh200_qtd: qtd_list
|
||||
*
|
||||
* Also, hold this lock when talking to HC registers or
|
||||
* when updating hw_* fields in shared qh/qtd/... structures.
|
||||
*/
|
||||
|
||||
#define FUSBH200_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */
|
||||
|
||||
/*
|
||||
* fusbh200_rh_state values of FUSBH200_RH_RUNNING or above mean that the
|
||||
* controller may be doing DMA. Lower values mean there's no DMA.
|
||||
*/
|
||||
enum fusbh200_rh_state {
|
||||
FUSBH200_RH_HALTED,
|
||||
FUSBH200_RH_SUSPENDED,
|
||||
FUSBH200_RH_RUNNING,
|
||||
FUSBH200_RH_STOPPING
|
||||
};
|
||||
|
||||
/*
|
||||
* Timer events, ordered by increasing delay length.
|
||||
* Always update event_delays_ns[] and event_handlers[] (defined in
|
||||
* ehci-timer.c) in parallel with this list.
|
||||
*/
|
||||
enum fusbh200_hrtimer_event {
|
||||
FUSBH200_HRTIMER_POLL_ASS, /* Poll for async schedule off */
|
||||
FUSBH200_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
|
||||
FUSBH200_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
|
||||
FUSBH200_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
|
||||
FUSBH200_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
|
||||
FUSBH200_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
|
||||
FUSBH200_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
|
||||
FUSBH200_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
|
||||
FUSBH200_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
|
||||
FUSBH200_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
|
||||
FUSBH200_HRTIMER_NUM_EVENTS /* Must come last */
|
||||
};
|
||||
#define FUSBH200_HRTIMER_NO_EVENT 99
|
||||
|
||||
struct fusbh200_hcd { /* one per controller */
|
||||
/* timing support */
|
||||
enum fusbh200_hrtimer_event next_hrtimer_event;
|
||||
unsigned enabled_hrtimer_events;
|
||||
ktime_t hr_timeouts[FUSBH200_HRTIMER_NUM_EVENTS];
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
int PSS_poll_count;
|
||||
int ASS_poll_count;
|
||||
int died_poll_count;
|
||||
|
||||
/* glue to PCI and HCD framework */
|
||||
struct fusbh200_caps __iomem *caps;
|
||||
struct fusbh200_regs __iomem *regs;
|
||||
struct ehci_dbg_port __iomem *debug;
|
||||
|
||||
__u32 hcs_params; /* cached register copy */
|
||||
spinlock_t lock;
|
||||
enum fusbh200_rh_state rh_state;
|
||||
|
||||
/* general schedule support */
|
||||
bool scanning:1;
|
||||
bool need_rescan:1;
|
||||
bool intr_unlinking:1;
|
||||
bool async_unlinking:1;
|
||||
bool shutdown:1;
|
||||
struct fusbh200_qh *qh_scan_next;
|
||||
|
||||
/* async schedule support */
|
||||
struct fusbh200_qh *async;
|
||||
struct fusbh200_qh *dummy; /* For AMD quirk use */
|
||||
struct fusbh200_qh *async_unlink;
|
||||
struct fusbh200_qh *async_unlink_last;
|
||||
struct fusbh200_qh *async_iaa;
|
||||
unsigned async_unlink_cycle;
|
||||
unsigned async_count; /* async activity count */
|
||||
|
||||
/* periodic schedule support */
|
||||
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
|
||||
unsigned periodic_size;
|
||||
__hc32 *periodic; /* hw periodic table */
|
||||
dma_addr_t periodic_dma;
|
||||
struct list_head intr_qh_list;
|
||||
unsigned i_thresh; /* uframes HC might cache */
|
||||
|
||||
union fusbh200_shadow *pshadow; /* mirror hw periodic table */
|
||||
struct fusbh200_qh *intr_unlink;
|
||||
struct fusbh200_qh *intr_unlink_last;
|
||||
unsigned intr_unlink_cycle;
|
||||
unsigned now_frame; /* frame from HC hardware */
|
||||
unsigned next_frame; /* scan periodic, start here */
|
||||
unsigned intr_count; /* intr activity count */
|
||||
unsigned isoc_count; /* isoc activity count */
|
||||
unsigned periodic_count; /* periodic activity count */
|
||||
unsigned uframe_periodic_max; /* max periodic time per uframe */
|
||||
|
||||
|
||||
/* list of itds completed while now_frame was still active */
|
||||
struct list_head cached_itd_list;
|
||||
struct fusbh200_itd *last_itd_to_free;
|
||||
|
||||
/* per root hub port */
|
||||
unsigned long reset_done [FUSBH200_MAX_ROOT_PORTS];
|
||||
|
||||
/* bit vectors (one bit per port) */
|
||||
unsigned long bus_suspended; /* which ports were
|
||||
already suspended at the start of a bus suspend */
|
||||
unsigned long companion_ports; /* which ports are
|
||||
dedicated to the companion controller */
|
||||
unsigned long owned_ports; /* which ports are
|
||||
owned by the companion during a bus suspend */
|
||||
unsigned long port_c_suspend; /* which ports have
|
||||
the change-suspend feature turned on */
|
||||
unsigned long suspended_ports; /* which ports are
|
||||
suspended */
|
||||
unsigned long resuming_ports; /* which ports have
|
||||
started to resume */
|
||||
|
||||
/* per-HC memory pools (could be per-bus, but ...) */
|
||||
struct dma_pool *qh_pool; /* qh per active urb */
|
||||
struct dma_pool *qtd_pool; /* one or more per qh */
|
||||
struct dma_pool *itd_pool; /* itd per iso urb */
|
||||
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
u32 command;
|
||||
|
||||
/* SILICON QUIRKS */
|
||||
unsigned need_io_watchdog:1;
|
||||
unsigned fs_i_thresh:1; /* Intel iso scheduling */
|
||||
|
||||
u8 sbrn; /* packed release number */
|
||||
|
||||
/* irq statistics */
|
||||
struct fusbh200_stats stats;
|
||||
# define COUNT(x) do { (x)++; } while (0)
|
||||
|
||||
/* debug files */
|
||||
struct dentry *debug_dir;
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding FUSBH200_HCD */
|
||||
static inline struct fusbh200_hcd *hcd_to_fusbh200 (struct usb_hcd *hcd)
|
||||
{
|
||||
return (struct fusbh200_hcd *) (hcd->hcd_priv);
|
||||
}
|
||||
static inline struct usb_hcd *fusbh200_to_hcd (struct fusbh200_hcd *fusbh200)
|
||||
{
|
||||
return container_of ((void *) fusbh200, struct usb_hcd, hcd_priv);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
|
||||
|
||||
/* Section 2.2 Host Controller Capability Registers */
|
||||
struct fusbh200_caps {
|
||||
/* these fields are specified as 8 and 16 bit registers,
|
||||
* but some hosts can't perform 8 or 16 bit PCI accesses.
|
||||
* some hosts treat caplength and hciversion as parts of a 32-bit
|
||||
* register, others treat them as two separate registers, this
|
||||
* affects the memory map for big endian controllers.
|
||||
*/
|
||||
u32 hc_capbase;
|
||||
#define HC_LENGTH(fusbh200, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
|
||||
(fusbh200_big_endian_capbase(fusbh200) ? 24 : 0)))
|
||||
#define HC_VERSION(fusbh200, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \
|
||||
(fusbh200_big_endian_capbase(fusbh200) ? 0 : 16)))
|
||||
u32 hcs_params; /* HCSPARAMS - offset 0x4 */
|
||||
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
|
||||
|
||||
u32 hcc_params; /* HCCPARAMS - offset 0x8 */
|
||||
#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
|
||||
#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
|
||||
u8 portroute[8]; /* nibbles for routing - offset 0xC */
|
||||
};
|
||||
|
||||
|
||||
/* Section 2.3 Host Controller Operational Registers */
|
||||
struct fusbh200_regs {
|
||||
|
||||
/* USBCMD: offset 0x00 */
|
||||
u32 command;
|
||||
|
||||
/* EHCI 1.1 addendum */
|
||||
/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
|
||||
#define CMD_PARK (1<<11) /* enable "park" on async qh */
|
||||
#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
|
||||
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
|
||||
#define CMD_ASE (1<<5) /* async schedule enable */
|
||||
#define CMD_PSE (1<<4) /* periodic schedule enable */
|
||||
/* 3:2 is periodic frame list size */
|
||||
#define CMD_RESET (1<<1) /* reset HC not bus */
|
||||
#define CMD_RUN (1<<0) /* start/stop HC */
|
||||
|
||||
/* USBSTS: offset 0x04 */
|
||||
u32 status;
|
||||
#define STS_ASS (1<<15) /* Async Schedule Status */
|
||||
#define STS_PSS (1<<14) /* Periodic Schedule Status */
|
||||
#define STS_RECL (1<<13) /* Reclamation */
|
||||
#define STS_HALT (1<<12) /* Not running (any reason) */
|
||||
/* some bits reserved */
|
||||
/* these STS_* flags are also intr_enable bits (USBINTR) */
|
||||
#define STS_IAA (1<<5) /* Interrupted on async advance */
|
||||
#define STS_FATAL (1<<4) /* such as some PCI access errors */
|
||||
#define STS_FLR (1<<3) /* frame list rolled over */
|
||||
#define STS_PCD (1<<2) /* port change detect */
|
||||
#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
|
||||
#define STS_INT (1<<0) /* "normal" completion (short, ...) */
|
||||
|
||||
/* USBINTR: offset 0x08 */
|
||||
u32 intr_enable;
|
||||
|
||||
/* FRINDEX: offset 0x0C */
|
||||
u32 frame_index; /* current microframe number */
|
||||
/* CTRLDSSEGMENT: offset 0x10 */
|
||||
u32 segment; /* address bits 63:32 if needed */
|
||||
/* PERIODICLISTBASE: offset 0x14 */
|
||||
u32 frame_list; /* points to periodic list */
|
||||
/* ASYNCLISTADDR: offset 0x18 */
|
||||
u32 async_next; /* address of next async queue head */
|
||||
|
||||
u32 reserved1;
|
||||
/* PORTSC: offset 0x20 */
|
||||
u32 port_status;
|
||||
/* 31:23 reserved */
|
||||
#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
|
||||
#define PORT_RESET (1<<8) /* reset port */
|
||||
#define PORT_SUSPEND (1<<7) /* suspend port */
|
||||
#define PORT_RESUME (1<<6) /* resume it */
|
||||
#define PORT_PEC (1<<3) /* port enable change */
|
||||
#define PORT_PE (1<<2) /* port enable */
|
||||
#define PORT_CSC (1<<1) /* connect status change */
|
||||
#define PORT_CONNECT (1<<0) /* device connected */
|
||||
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC)
|
||||
|
||||
u32 reserved2[3];
|
||||
|
||||
/* BMCSR: offset 0x30 */
|
||||
u32 bmcsr; /* Bus Moniter Control/Status Register */
|
||||
#define BMCSR_HOST_SPD_TYP (3<<9)
|
||||
#define BMCSR_VBUS_OFF (1<<4)
|
||||
#define BMCSR_INT_POLARITY (1<<3)
|
||||
|
||||
/* BMISR: offset 0x34 */
|
||||
u32 bmisr; /* Bus Moniter Interrupt Status Register*/
|
||||
#define BMISR_OVC (1<<1)
|
||||
|
||||
/* BMIER: offset 0x38 */
|
||||
u32 bmier; /* Bus Moniter Interrupt Enable Register */
|
||||
#define BMIER_OVC_EN (1<<1)
|
||||
#define BMIER_VBUS_ERR_EN (1<<0)
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define QTD_NEXT(fusbh200, dma) cpu_to_hc32(fusbh200, (u32)dma)
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.5
|
||||
* QTD: describe data transfer components (buffer, direction, ...)
|
||||
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
|
||||
*
|
||||
* These are associated only with "QH" (Queue Head) structures,
|
||||
* used with control, bulk, and interrupt transfers.
|
||||
*/
|
||||
struct fusbh200_qtd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next; /* see EHCI 3.5.1 */
|
||||
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
|
||||
__hc32 hw_token; /* see EHCI 3.5.3 */
|
||||
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
||||
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
||||
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
|
||||
#define QTD_PID(tok) (((tok)>>8) & 0x3)
|
||||
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||
#define QTD_STS_HALT (1 << 6) /* halted on error */
|
||||
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
|
||||
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
|
||||
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||
#define QTD_STS_STS (1 << 1) /* split transaction state */
|
||||
#define QTD_STS_PING (1 << 0) /* issue PING? */
|
||||
|
||||
#define ACTIVE_BIT(fusbh200) cpu_to_hc32(fusbh200, QTD_STS_ACTIVE)
|
||||
#define HALT_BIT(fusbh200) cpu_to_hc32(fusbh200, QTD_STS_HALT)
|
||||
#define STATUS_BIT(fusbh200) cpu_to_hc32(fusbh200, QTD_STS_STS)
|
||||
|
||||
__hc32 hw_buf [5]; /* see EHCI 3.5.4 */
|
||||
__hc32 hw_buf_hi [5]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t qtd_dma; /* qtd address */
|
||||
struct list_head qtd_list; /* sw qtd list */
|
||||
struct urb *urb; /* qtd's urb */
|
||||
size_t length; /* length of buffer */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/* mask NakCnt+T in qh->hw_alt_next */
|
||||
#define QTD_MASK(fusbh200) cpu_to_hc32 (fusbh200, ~0x1f)
|
||||
|
||||
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* type tag from {qh,itd,fstn}->hw_next */
|
||||
#define Q_NEXT_TYPE(fusbh200,dma) ((dma) & cpu_to_hc32(fusbh200, 3 << 1))
|
||||
|
||||
/*
|
||||
* Now the following defines are not converted using the
|
||||
* cpu_to_le32() macro anymore, since we have to support
|
||||
* "dynamic" switching between be and le support, so that the driver
|
||||
* can be used on one system with SoC EHCI controller using big-endian
|
||||
* descriptors as well as a normal little-endian PCI EHCI controller.
|
||||
*/
|
||||
/* values for that type tag */
|
||||
#define Q_TYPE_ITD (0 << 1)
|
||||
#define Q_TYPE_QH (1 << 1)
|
||||
#define Q_TYPE_SITD (2 << 1)
|
||||
#define Q_TYPE_FSTN (3 << 1)
|
||||
|
||||
/* next async queue entry, or pointer to interrupt/periodic QH */
|
||||
#define QH_NEXT(fusbh200,dma) (cpu_to_hc32(fusbh200, (((u32)dma)&~0x01f)|Q_TYPE_QH))
|
||||
|
||||
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||
#define FUSBH200_LIST_END(fusbh200) cpu_to_hc32(fusbh200, 1) /* "null pointer" to hw */
|
||||
|
||||
/*
|
||||
* Entries in periodic shadow table are pointers to one of four kinds
|
||||
* of data structure. That's dictated by the hardware; a type tag is
|
||||
* encoded in the low bits of the hardware's periodic schedule. Use
|
||||
* Q_NEXT_TYPE to get the tag.
|
||||
*
|
||||
* For entries in the async schedule, the type tag always says "qh".
|
||||
*/
|
||||
union fusbh200_shadow {
|
||||
struct fusbh200_qh *qh; /* Q_TYPE_QH */
|
||||
struct fusbh200_itd *itd; /* Q_TYPE_ITD */
|
||||
struct fusbh200_fstn *fstn; /* Q_TYPE_FSTN */
|
||||
__hc32 *hw_next; /* (all types) */
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.6
|
||||
* QH: describes control/bulk/interrupt endpoints
|
||||
* See Fig 3-7 "Queue Head Structure Layout".
|
||||
*
|
||||
* These appear in both the async and (for interrupt) periodic schedules.
|
||||
*/
|
||||
|
||||
/* first part defined by EHCI spec */
|
||||
struct fusbh200_qh_hw {
|
||||
__hc32 hw_next; /* see EHCI 3.6.1 */
|
||||
__hc32 hw_info1; /* see EHCI 3.6.2 */
|
||||
#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
|
||||
#define QH_HEAD (1 << 15) /* Head of async reclamation list */
|
||||
#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
|
||||
#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
|
||||
#define QH_LOW_SPEED (1 << 12)
|
||||
#define QH_FULL_SPEED (0 << 12)
|
||||
#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
|
||||
__hc32 hw_info2; /* see EHCI 3.6.2 */
|
||||
#define QH_SMASK 0x000000ff
|
||||
#define QH_CMASK 0x0000ff00
|
||||
#define QH_HUBADDR 0x007f0000
|
||||
#define QH_HUBPORT 0x3f800000
|
||||
#define QH_MULT 0xc0000000
|
||||
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
|
||||
|
||||
/* qtd overlay (hardware parts of a struct fusbh200_qtd) */
|
||||
__hc32 hw_qtd_next;
|
||||
__hc32 hw_alt_next;
|
||||
__hc32 hw_token;
|
||||
__hc32 hw_buf [5];
|
||||
__hc32 hw_buf_hi [5];
|
||||
} __attribute__ ((aligned(32)));
|
||||
|
||||
struct fusbh200_qh {
|
||||
struct fusbh200_qh_hw *hw; /* Must come first */
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t qh_dma; /* address of qh */
|
||||
union fusbh200_shadow qh_next; /* ptr to qh; or periodic */
|
||||
struct list_head qtd_list; /* sw qtd list */
|
||||
struct list_head intr_node; /* list of intr QHs */
|
||||
struct fusbh200_qtd *dummy;
|
||||
struct fusbh200_qh *unlink_next; /* next on unlink list */
|
||||
|
||||
unsigned unlink_cycle;
|
||||
|
||||
u8 needs_rescan; /* Dequeue during giveback */
|
||||
u8 qh_state;
|
||||
#define QH_STATE_LINKED 1 /* HC sees this */
|
||||
#define QH_STATE_UNLINK 2 /* HC may still see this */
|
||||
#define QH_STATE_IDLE 3 /* HC doesn't see this */
|
||||
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
|
||||
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
||||
|
||||
u8 xacterrs; /* XactErr retry counter */
|
||||
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
|
||||
|
||||
/* periodic schedule info */
|
||||
u8 usecs; /* intr bandwidth */
|
||||
u8 gap_uf; /* uframes split/csplit gap */
|
||||
u8 c_usecs; /* ... split completion bw */
|
||||
u16 tt_usecs; /* tt downstream bandwidth */
|
||||
unsigned short period; /* polling interval */
|
||||
unsigned short start; /* where polling starts */
|
||||
#define NO_FRAME ((unsigned short)~0) /* pick new start */
|
||||
|
||||
struct usb_device *dev; /* access to TT */
|
||||
unsigned is_out:1; /* bulk or intr OUT */
|
||||
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* description of one iso transaction (up to 3 KB data if highspeed) */
|
||||
struct fusbh200_iso_packet {
|
||||
/* These will be copied to iTD when scheduling */
|
||||
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
|
||||
__hc32 transaction; /* itd->hw_transaction[i] |= */
|
||||
u8 cross; /* buf crosses pages */
|
||||
/* for full speed OUT splits */
|
||||
u32 buf1;
|
||||
};
|
||||
|
||||
/* temporary schedule data for packets from iso urbs (both speeds)
|
||||
* each packet is one logical usb transaction to the device (not TT),
|
||||
* beginning at stream->next_uframe
|
||||
*/
|
||||
struct fusbh200_iso_sched {
|
||||
struct list_head td_list;
|
||||
unsigned span;
|
||||
struct fusbh200_iso_packet packet [0];
|
||||
};
|
||||
|
||||
/*
|
||||
* fusbh200_iso_stream - groups all (s)itds for this endpoint.
|
||||
* acts like a qh would, if EHCI had them for ISO.
|
||||
*/
|
||||
struct fusbh200_iso_stream {
|
||||
/* first field matches fusbh200_hq, but is NULL */
|
||||
struct fusbh200_qh_hw *hw;
|
||||
|
||||
u8 bEndpointAddress;
|
||||
u8 highspeed;
|
||||
struct list_head td_list; /* queued itds */
|
||||
struct list_head free_list; /* list of unused itds */
|
||||
struct usb_device *udev;
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
/* output of (re)scheduling */
|
||||
int next_uframe;
|
||||
__hc32 splits;
|
||||
|
||||
/* the rest is derived from the endpoint descriptor,
|
||||
* trusting urb->interval == f(epdesc->bInterval) and
|
||||
* including the extra info for hw_bufp[0..2]
|
||||
*/
|
||||
u8 usecs, c_usecs;
|
||||
u16 interval;
|
||||
u16 tt_usecs;
|
||||
u16 maxp;
|
||||
u16 raw_mask;
|
||||
unsigned bandwidth;
|
||||
|
||||
/* This is used to initialize iTD's hw_bufp fields */
|
||||
__hc32 buf0;
|
||||
__hc32 buf1;
|
||||
__hc32 buf2;
|
||||
|
||||
/* this is used to initialize sITD's tt info */
|
||||
__hc32 address;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.95 Section 3.3
|
||||
* Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
|
||||
*
|
||||
* Schedule records for high speed iso xfers
|
||||
*/
|
||||
struct fusbh200_itd {
|
||||
/* first part defined by EHCI spec */
|
||||
__hc32 hw_next; /* see EHCI 3.3.1 */
|
||||
__hc32 hw_transaction [8]; /* see EHCI 3.3.2 */
|
||||
#define FUSBH200_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
|
||||
#define FUSBH200_ISOC_BUF_ERR (1<<30) /* Data buffer error */
|
||||
#define FUSBH200_ISOC_BABBLE (1<<29) /* babble detected */
|
||||
#define FUSBH200_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
|
||||
#define FUSBH200_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
|
||||
#define FUSBH200_ITD_IOC (1 << 15) /* interrupt on complete */
|
||||
|
||||
#define ITD_ACTIVE(fusbh200) cpu_to_hc32(fusbh200, FUSBH200_ISOC_ACTIVE)
|
||||
|
||||
__hc32 hw_bufp [7]; /* see EHCI 3.3.3 */
|
||||
__hc32 hw_bufp_hi [7]; /* Appendix B */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t itd_dma; /* for this itd */
|
||||
union fusbh200_shadow itd_next; /* ptr to periodic q entry */
|
||||
|
||||
struct urb *urb;
|
||||
struct fusbh200_iso_stream *stream; /* endpoint's queue */
|
||||
struct list_head itd_list; /* list of stream's itds */
|
||||
|
||||
/* any/all hw_transactions here may be used by that urb */
|
||||
unsigned frame; /* where scheduled */
|
||||
unsigned pg;
|
||||
unsigned index[8]; /* in urb->iso_frame_desc */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* EHCI Specification 0.96 Section 3.7
|
||||
* Periodic Frame Span Traversal Node (FSTN)
|
||||
*
|
||||
* Manages split interrupt transactions (using TT) that span frame boundaries
|
||||
* into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
|
||||
* makes the HC jump (back) to a QH to scan for fs/ls QH completions until
|
||||
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
|
||||
*/
|
||||
struct fusbh200_fstn {
|
||||
__hc32 hw_next; /* any periodic q entry */
|
||||
__hc32 hw_prev; /* qh or FUSBH200_LIST_END */
|
||||
|
||||
/* the rest is HCD-private */
|
||||
dma_addr_t fstn_dma;
|
||||
union fusbh200_shadow fstn_next; /* ptr to periodic q entry */
|
||||
} __attribute__ ((aligned (32)));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
|
||||
|
||||
#define fusbh200_prepare_ports_for_controller_suspend(fusbh200, do_wakeup) \
|
||||
fusbh200_adjust_port_wakeup_flags(fusbh200, true, do_wakeup);
|
||||
|
||||
#define fusbh200_prepare_ports_for_controller_resume(fusbh200) \
|
||||
fusbh200_adjust_port_wakeup_flags(fusbh200, false, false);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Some EHCI controllers have a Transaction Translator built into the
|
||||
* root hub. This is a non-standard feature. Each controller will need
|
||||
* to add code to the following inline functions, and call them as
|
||||
* needed (mostly in root hub code).
|
||||
*/
|
||||
|
||||
static inline unsigned int
|
||||
fusbh200_get_speed(struct fusbh200_hcd *fusbh200, unsigned int portsc)
|
||||
{
|
||||
return (readl(&fusbh200->regs->bmcsr)
|
||||
& BMCSR_HOST_SPD_TYP) >> 9;
|
||||
}
|
||||
|
||||
/* Returns the speed of a device attached to a port on the root hub. */
|
||||
static inline unsigned int
|
||||
fusbh200_port_speed(struct fusbh200_hcd *fusbh200, unsigned int portsc)
|
||||
{
|
||||
switch (fusbh200_get_speed(fusbh200, portsc)) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return USB_PORT_STAT_LOW_SPEED;
|
||||
case 2:
|
||||
default:
|
||||
return USB_PORT_STAT_HIGH_SPEED;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define fusbh200_has_fsl_portno_bug(e) (0)
|
||||
|
||||
/*
|
||||
* While most USB host controllers implement their registers in
|
||||
* little-endian format, a minority (celleb companion chip) implement
|
||||
* them in big endian format.
|
||||
*
|
||||
* This attempts to support either format at compile time without a
|
||||
* runtime penalty, or both formats with the additional overhead
|
||||
* of checking a flag bit.
|
||||
*
|
||||
*/
|
||||
|
||||
#define fusbh200_big_endian_mmio(e) 0
|
||||
#define fusbh200_big_endian_capbase(e) 0
|
||||
|
||||
static inline unsigned int fusbh200_readl(const struct fusbh200_hcd *fusbh200,
|
||||
__u32 __iomem * regs)
|
||||
{
|
||||
return readl(regs);
|
||||
}
|
||||
|
||||
static inline void fusbh200_writel(const struct fusbh200_hcd *fusbh200,
|
||||
const unsigned int val, __u32 __iomem *regs)
|
||||
{
|
||||
writel(val, regs);
|
||||
}
|
||||
|
||||
/* cpu to fusbh200 */
|
||||
static inline __hc32 cpu_to_hc32 (const struct fusbh200_hcd *fusbh200, const u32 x)
|
||||
{
|
||||
return cpu_to_le32(x);
|
||||
}
|
||||
|
||||
/* fusbh200 to cpu */
|
||||
static inline u32 hc32_to_cpu (const struct fusbh200_hcd *fusbh200, const __hc32 x)
|
||||
{
|
||||
return le32_to_cpu(x);
|
||||
}
|
||||
|
||||
static inline u32 hc32_to_cpup (const struct fusbh200_hcd *fusbh200, const __hc32 *x)
|
||||
{
|
||||
return le32_to_cpup(x);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static inline unsigned fusbh200_read_frame_index(struct fusbh200_hcd *fusbh200)
|
||||
{
|
||||
return fusbh200_readl(fusbh200, &fusbh200->regs->frame_index);
|
||||
}
|
||||
|
||||
#define fusbh200_itdlen(urb, desc, t) ({ \
|
||||
usb_pipein((urb)->pipe) ? \
|
||||
(desc)->length - FUSBH200_ITD_LENGTH(t) : \
|
||||
FUSBH200_ITD_LENGTH(t); \
|
||||
})
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* __LINUX_FUSBH200_H */
|
||||
|
|
@ -203,7 +203,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
|
|||
goto fail_disable;
|
||||
}
|
||||
|
||||
ret = clk_enable(usb_pll_clk);
|
||||
ret = clk_prepare_enable(usb_pll_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to start USB PLL\n");
|
||||
goto fail_disable;
|
||||
|
|
@ -223,7 +223,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
|
|||
goto fail_rate;
|
||||
}
|
||||
|
||||
ret = clk_enable(usb_dev_clk);
|
||||
ret = clk_prepare_enable(usb_dev_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
|
||||
goto fail_rate;
|
||||
|
|
@ -239,7 +239,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
|
|||
|
||||
__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
|
||||
|
||||
ret = clk_enable(usb_otg_clk);
|
||||
ret = clk_prepare_enable(usb_otg_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
|
||||
goto fail_otg;
|
||||
|
|
@ -283,11 +283,11 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
|
|||
fail_resource:
|
||||
usb_put_hcd(hcd);
|
||||
fail_hcd:
|
||||
clk_disable(usb_otg_clk);
|
||||
clk_disable_unprepare(usb_otg_clk);
|
||||
fail_otg:
|
||||
clk_disable(usb_dev_clk);
|
||||
clk_disable_unprepare(usb_dev_clk);
|
||||
fail_rate:
|
||||
clk_disable(usb_pll_clk);
|
||||
clk_disable_unprepare(usb_pll_clk);
|
||||
fail_disable:
|
||||
isp1301_i2c_client = NULL;
|
||||
return ret;
|
||||
|
|
@ -300,9 +300,9 @@ static int ohci_hcd_nxp_remove(struct platform_device *pdev)
|
|||
usb_remove_hcd(hcd);
|
||||
ohci_nxp_stop_hc();
|
||||
usb_put_hcd(hcd);
|
||||
clk_disable(usb_pll_clk);
|
||||
clk_disable(usb_dev_clk);
|
||||
i2c_unregister_device(isp1301_i2c_client);
|
||||
clk_disable_unprepare(usb_otg_clk);
|
||||
clk_disable_unprepare(usb_dev_clk);
|
||||
clk_disable_unprepare(usb_pll_clk);
|
||||
isp1301_i2c_client = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ static const struct of_device_id spear_ohci_id_table[] = {
|
|||
{ .compatible = "st,spear600-ohci", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spear_ohci_id_table);
|
||||
|
||||
/* Driver definition to register with the platform bus */
|
||||
static struct platform_driver spear_ohci_hcd_driver = {
|
||||
|
|
|
|||
|
|
@ -2245,8 +2245,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
|||
struct u132 *u132 = hcd_to_u132(hcd);
|
||||
if (irqs_disabled()) {
|
||||
if (__GFP_WAIT & mem_flags) {
|
||||
printk(KERN_ERR "invalid context for function that migh"
|
||||
"t sleep\n");
|
||||
printk(KERN_ERR "invalid context for function that might sleep\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ static const struct of_device_id platform_uhci_ids[] = {
|
|||
{ .compatible = "platform-uhci", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, platform_uhci_ids);
|
||||
|
||||
static struct platform_driver uhci_platform_driver = {
|
||||
.probe = uhci_hcd_platform_probe,
|
||||
|
|
|
|||
|
|
@ -175,8 +175,7 @@ void whc_clean_up(struct whc *whc)
|
|||
pzl_clean_up(whc);
|
||||
asl_clean_up(whc);
|
||||
|
||||
if (whc->qset_pool)
|
||||
dma_pool_destroy(whc->qset_pool);
|
||||
dma_pool_destroy(whc->qset_pool);
|
||||
|
||||
len = resource_size(&whc->umc->resource);
|
||||
if (whc->base)
|
||||
|
|
|
|||
|
|
@ -58,16 +58,17 @@ void xhci_dbg_regs(struct xhci_hcd *xhci)
|
|||
static void xhci_print_cap_regs(struct xhci_hcd *xhci)
|
||||
{
|
||||
u32 temp;
|
||||
u32 hci_version;
|
||||
|
||||
xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs);
|
||||
|
||||
temp = readl(&xhci->cap_regs->hc_capbase);
|
||||
hci_version = HC_VERSION(temp);
|
||||
xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n",
|
||||
(unsigned int) temp);
|
||||
xhci_dbg(xhci, "CAPLENGTH: 0x%x\n",
|
||||
(unsigned int) HC_LENGTH(temp));
|
||||
xhci_dbg(xhci, "HCIVERSION: 0x%x\n",
|
||||
(unsigned int) HC_VERSION(temp));
|
||||
xhci_dbg(xhci, "HCIVERSION: 0x%x\n", hci_version);
|
||||
|
||||
temp = readl(&xhci->cap_regs->hcs_params1);
|
||||
xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n",
|
||||
|
|
@ -108,6 +109,18 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)
|
|||
|
||||
temp = readl(&xhci->cap_regs->run_regs_off);
|
||||
xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
|
||||
|
||||
/* xhci 1.1 controllers have the HCCPARAMS2 register */
|
||||
if (hci_version > 100) {
|
||||
temp = readl(&xhci->cap_regs->hcc_params2);
|
||||
xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp);
|
||||
xhci_dbg(xhci, " HC %s Force save context capability",
|
||||
HCC2_FSC(temp) ? "supports" : "doesn't support");
|
||||
xhci_dbg(xhci, " HC %s Large ESIT Payload Capability",
|
||||
HCC2_LEC(temp) ? "supports" : "doesn't support");
|
||||
xhci_dbg(xhci, " HC %s Extended TBC capability",
|
||||
HCC2_ETC(temp) ? "supports" : "doesn't support");
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_print_command_reg(struct xhci_hcd *xhci)
|
||||
|
|
|
|||
|
|
@ -31,13 +31,15 @@
|
|||
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
|
||||
PORT_RC | PORT_PLC | PORT_PE)
|
||||
|
||||
/* USB 3.0 BOS descriptor and a capability descriptor, combined */
|
||||
/* USB 3 BOS descriptor and a capability descriptors, combined.
|
||||
* Fields will be adjusted and added later in xhci_create_usb3_bos_desc()
|
||||
*/
|
||||
static u8 usb_bos_descriptor [] = {
|
||||
USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */
|
||||
USB_DT_BOS, /* __u8 bDescriptorType */
|
||||
0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */
|
||||
0x1, /* __u8 bNumDeviceCaps */
|
||||
/* First device capability */
|
||||
/* First device capability, SuperSpeed */
|
||||
USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */
|
||||
USB_DT_DEVICE_CAPABILITY, /* Device Capability */
|
||||
USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */
|
||||
|
|
@ -46,9 +48,108 @@ static u8 usb_bos_descriptor [] = {
|
|||
0x03, /* bFunctionalitySupport,
|
||||
USB 3.0 speed only */
|
||||
0x00, /* bU1DevExitLat, set later. */
|
||||
0x00, 0x00 /* __le16 bU2DevExitLat, set later. */
|
||||
0x00, 0x00, /* __le16 bU2DevExitLat, set later. */
|
||||
/* Second device capability, SuperSpeedPlus */
|
||||
0x0c, /* bLength 12, will be adjusted later */
|
||||
USB_DT_DEVICE_CAPABILITY, /* Device Capability */
|
||||
USB_SSP_CAP_TYPE, /* bDevCapabilityType SUPERSPEED_PLUS */
|
||||
0x00, /* bReserved 0 */
|
||||
0x00, 0x00, 0x00, 0x00, /* bmAttributes, get from xhci psic */
|
||||
0x00, 0x00, /* wFunctionalitySupport */
|
||||
0x00, 0x00, /* wReserved 0 */
|
||||
/* Sublink Speed Attributes are added in xhci_create_usb3_bos_desc() */
|
||||
};
|
||||
|
||||
static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
|
||||
u16 wLength)
|
||||
{
|
||||
int i, ssa_count;
|
||||
u32 temp;
|
||||
u16 desc_size, ssp_cap_size, ssa_size = 0;
|
||||
bool usb3_1 = false;
|
||||
|
||||
desc_size = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
|
||||
ssp_cap_size = sizeof(usb_bos_descriptor) - desc_size;
|
||||
|
||||
/* does xhci support USB 3.1 Enhanced SuperSpeed */
|
||||
if (xhci->usb3_rhub.min_rev >= 0x01 && xhci->usb3_rhub.psi_uid_count) {
|
||||
/* two SSA entries for each unique PSI ID, one RX and one TX */
|
||||
ssa_count = xhci->usb3_rhub.psi_uid_count * 2;
|
||||
ssa_size = ssa_count * sizeof(u32);
|
||||
desc_size += ssp_cap_size;
|
||||
usb3_1 = true;
|
||||
}
|
||||
memcpy(buf, &usb_bos_descriptor, min(desc_size, wLength));
|
||||
|
||||
if (usb3_1) {
|
||||
/* modify bos descriptor bNumDeviceCaps and wTotalLength */
|
||||
buf[4] += 1;
|
||||
put_unaligned_le16(desc_size + ssa_size, &buf[2]);
|
||||
}
|
||||
|
||||
if (wLength < USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE)
|
||||
return wLength;
|
||||
|
||||
/* Indicate whether the host has LTM support. */
|
||||
temp = readl(&xhci->cap_regs->hcc_params);
|
||||
if (HCC_LTC(temp))
|
||||
buf[8] |= USB_LTM_SUPPORT;
|
||||
|
||||
/* Set the U1 and U2 exit latencies. */
|
||||
if ((xhci->quirks & XHCI_LPM_SUPPORT)) {
|
||||
temp = readl(&xhci->cap_regs->hcs_params3);
|
||||
buf[12] = HCS_U1_LATENCY(temp);
|
||||
put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
|
||||
}
|
||||
|
||||
if (usb3_1) {
|
||||
u32 ssp_cap_base, bm_attrib, psi;
|
||||
int offset;
|
||||
|
||||
ssp_cap_base = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
|
||||
|
||||
if (wLength < desc_size)
|
||||
return wLength;
|
||||
buf[ssp_cap_base] = ssp_cap_size + ssa_size;
|
||||
|
||||
/* attribute count SSAC bits 4:0 and ID count SSIC bits 8:5 */
|
||||
bm_attrib = (ssa_count - 1) & 0x1f;
|
||||
bm_attrib |= (xhci->usb3_rhub.psi_uid_count - 1) << 5;
|
||||
put_unaligned_le32(bm_attrib, &buf[ssp_cap_base + 4]);
|
||||
|
||||
if (wLength < desc_size + ssa_size)
|
||||
return wLength;
|
||||
/*
|
||||
* Create the Sublink Speed Attributes (SSA) array.
|
||||
* The xhci PSI field and USB 3.1 SSA fields are very similar,
|
||||
* but link type bits 7:6 differ for values 01b and 10b.
|
||||
* xhci has also only one PSI entry for a symmetric link when
|
||||
* USB 3.1 requires two SSA entries (RX and TX) for every link
|
||||
*/
|
||||
offset = desc_size;
|
||||
for (i = 0; i < xhci->usb3_rhub.psi_count; i++) {
|
||||
psi = xhci->usb3_rhub.psi[i];
|
||||
psi &= ~USB_SSP_SUBLINK_SPEED_RSVD;
|
||||
if ((psi & PLT_MASK) == PLT_SYM) {
|
||||
/* Symmetric, create SSA RX and TX from one PSI entry */
|
||||
put_unaligned_le32(psi, &buf[offset]);
|
||||
psi |= 1 << 7; /* turn entry to TX */
|
||||
offset += 4;
|
||||
if (offset >= desc_size + ssa_size)
|
||||
return desc_size + ssa_size;
|
||||
} else if ((psi & PLT_MASK) == PLT_ASYM_RX) {
|
||||
/* Asymetric RX, flip bits 7:6 for SSA */
|
||||
psi ^= PLT_MASK;
|
||||
}
|
||||
put_unaligned_le32(psi, &buf[offset]);
|
||||
offset += 4;
|
||||
if (offset >= desc_size + ssa_size)
|
||||
return desc_size + ssa_size;
|
||||
}
|
||||
}
|
||||
/* ssa_size is 0 for other than usb 3.1 hosts */
|
||||
return desc_size + ssa_size;
|
||||
}
|
||||
|
||||
static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
|
||||
struct usb_hub_descriptor *desc, int ports)
|
||||
|
|
@ -161,7 +262,7 @@ static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
|||
struct usb_hub_descriptor *desc)
|
||||
{
|
||||
|
||||
if (hcd->speed == HCD_USB3)
|
||||
if (hcd->speed >= HCD_USB3)
|
||||
xhci_usb3_hub_descriptor(hcd, xhci, desc);
|
||||
else
|
||||
xhci_usb2_hub_descriptor(hcd, xhci, desc);
|
||||
|
|
@ -250,7 +351,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
|||
if (!xhci->devs[i])
|
||||
continue;
|
||||
speed = xhci->devs[i]->udev->speed;
|
||||
if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3))
|
||||
if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3))
|
||||
&& xhci->devs[i]->fake_port == port) {
|
||||
slot_id = i;
|
||||
break;
|
||||
|
|
@ -339,7 +440,7 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
|
|||
u16 wIndex, __le32 __iomem *addr, u32 port_status)
|
||||
{
|
||||
/* Don't allow the USB core to disable SuperSpeed ports. */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if (hcd->speed >= HCD_USB3) {
|
||||
xhci_dbg(xhci, "Ignoring request to disable "
|
||||
"SuperSpeed port.\n");
|
||||
return;
|
||||
|
|
@ -407,7 +508,7 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
|
|||
int max_ports;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if (hcd->speed >= HCD_USB3) {
|
||||
max_ports = xhci->num_usb3_ports;
|
||||
*port_array = xhci->usb3_ports;
|
||||
} else {
|
||||
|
|
@ -558,6 +659,22 @@ static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
|
|||
}
|
||||
}
|
||||
|
||||
static u32 xhci_get_ext_port_status(u32 raw_port_status, u32 port_li)
|
||||
{
|
||||
u32 ext_stat = 0;
|
||||
int speed_id;
|
||||
|
||||
/* only support rx and tx lane counts of 1 in usb3.1 spec */
|
||||
speed_id = DEV_PORT_SPEED(raw_port_status);
|
||||
ext_stat |= speed_id; /* bits 3:0, RX speed id */
|
||||
ext_stat |= speed_id << 4; /* bits 7:4, TX speed id */
|
||||
|
||||
ext_stat |= PORT_RX_LANES(port_li) << 8; /* bits 11:8 Rx lane count */
|
||||
ext_stat |= PORT_TX_LANES(port_li) << 12; /* bits 15:12 Tx lane count */
|
||||
|
||||
return ext_stat;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a raw xHCI port status into the format that external USB 2.0 or USB
|
||||
* 3.0 hubs use.
|
||||
|
|
@ -590,7 +707,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
if ((raw_port_status & PORT_RC))
|
||||
status |= USB_PORT_STAT_C_RESET << 16;
|
||||
/* USB3.0 only */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if (hcd->speed >= HCD_USB3) {
|
||||
/* Port link change with port in resume state should not be
|
||||
* reported to usbcore, as this is an internal state to be
|
||||
* handled by xhci driver. Reporting PLC to usbcore may
|
||||
|
|
@ -606,13 +723,13 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
|
||||
}
|
||||
|
||||
if (hcd->speed != HCD_USB3) {
|
||||
if (hcd->speed < HCD_USB3) {
|
||||
if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
|
||||
&& (raw_port_status & PORT_POWER))
|
||||
status |= USB_PORT_STAT_SUSPEND;
|
||||
}
|
||||
if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
|
||||
!DEV_SUPERSPEED(raw_port_status)) {
|
||||
!DEV_SUPERSPEED_ANY(raw_port_status)) {
|
||||
if ((raw_port_status & PORT_RESET) ||
|
||||
!(raw_port_status & PORT_PE))
|
||||
return 0xffffffff;
|
||||
|
|
@ -669,7 +786,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
&& (raw_port_status & PORT_POWER)
|
||||
&& (bus_state->suspended_ports & (1 << wIndex))) {
|
||||
bus_state->suspended_ports &= ~(1 << wIndex);
|
||||
if (hcd->speed != HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3)
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
}
|
||||
if (raw_port_status & PORT_CONNECT) {
|
||||
|
|
@ -683,13 +800,13 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
if (raw_port_status & PORT_RESET)
|
||||
status |= USB_PORT_STAT_RESET;
|
||||
if (raw_port_status & PORT_POWER) {
|
||||
if (hcd->speed == HCD_USB3)
|
||||
if (hcd->speed >= HCD_USB3)
|
||||
status |= USB_SS_PORT_STAT_POWER;
|
||||
else
|
||||
status |= USB_PORT_STAT_POWER;
|
||||
}
|
||||
/* Update Port Link State */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if (hcd->speed >= HCD_USB3) {
|
||||
xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status);
|
||||
/*
|
||||
* Verify if all USB3 Ports Have entered U0 already.
|
||||
|
|
@ -734,7 +851,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
* descriptor for the USB 3.0 roothub. If not, we stall the
|
||||
* endpoint, like external hubs do.
|
||||
*/
|
||||
if (hcd->speed == HCD_USB3 &&
|
||||
if (hcd->speed >= HCD_USB3 &&
|
||||
(wLength < USB_DT_SS_HUB_SIZE ||
|
||||
wValue != (USB_DT_SS_HUB << 8))) {
|
||||
xhci_dbg(xhci, "Wrong hub descriptor type for "
|
||||
|
|
@ -748,25 +865,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
if ((wValue & 0xff00) != (USB_DT_BOS << 8))
|
||||
goto error;
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3)
|
||||
goto error;
|
||||
|
||||
/* Set the U1 and U2 exit latencies. */
|
||||
memcpy(buf, &usb_bos_descriptor,
|
||||
USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
|
||||
if ((xhci->quirks & XHCI_LPM_SUPPORT)) {
|
||||
temp = readl(&xhci->cap_regs->hcs_params3);
|
||||
buf[12] = HCS_U1_LATENCY(temp);
|
||||
put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
|
||||
}
|
||||
|
||||
/* Indicate whether the host has LTM support. */
|
||||
temp = readl(&xhci->cap_regs->hcc_params);
|
||||
if (HCC_LTC(temp))
|
||||
buf[8] |= USB_LTM_SUPPORT;
|
||||
|
||||
retval = xhci_create_usb3_bos_desc(xhci, buf, wLength);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
|
||||
return retval;
|
||||
case GetPortStatus:
|
||||
if (!wIndex || wIndex > max_ports)
|
||||
goto error;
|
||||
|
|
@ -786,6 +890,19 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
|
||||
|
||||
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
|
||||
/* if USB 3.1 extended port status return additional 4 bytes */
|
||||
if (wValue == 0x02) {
|
||||
u32 port_li;
|
||||
|
||||
if (hcd->speed < HCD_USB31 || wLength != 8) {
|
||||
xhci_err(xhci, "get ext port status invalid parameter\n");
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
port_li = readl(port_array[wIndex] + PORTLI);
|
||||
status = xhci_get_ext_port_status(temp, port_li);
|
||||
put_unaligned_le32(cpu_to_le32(status), &buf[4]);
|
||||
}
|
||||
break;
|
||||
case SetPortFeature:
|
||||
if (wValue == USB_PORT_FEAT_LINK_STATE)
|
||||
|
|
@ -952,7 +1069,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = readl(port_array[wIndex]);
|
||||
break;
|
||||
case USB_PORT_FEAT_U1_TIMEOUT:
|
||||
if (hcd->speed != HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3)
|
||||
goto error;
|
||||
temp = readl(port_array[wIndex] + PORTPMSC);
|
||||
temp &= ~PORT_U1_TIMEOUT_MASK;
|
||||
|
|
@ -960,7 +1077,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
writel(temp, port_array[wIndex] + PORTPMSC);
|
||||
break;
|
||||
case USB_PORT_FEAT_U2_TIMEOUT:
|
||||
if (hcd->speed != HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3)
|
||||
goto error;
|
||||
temp = readl(port_array[wIndex] + PORTPMSC);
|
||||
temp &= ~PORT_U2_TIMEOUT_MASK;
|
||||
|
|
@ -1223,14 +1340,14 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|||
u32 temp;
|
||||
|
||||
temp = readl(port_array[port_index]);
|
||||
if (DEV_SUPERSPEED(temp))
|
||||
if (DEV_SUPERSPEED_ANY(temp))
|
||||
temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
|
||||
else
|
||||
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||
if (test_bit(port_index, &bus_state->bus_suspended) &&
|
||||
(temp & PORT_PLS_MASK)) {
|
||||
set_bit(port_index, &port_was_suspended);
|
||||
if (!DEV_SUPERSPEED(temp)) {
|
||||
if (!DEV_SUPERSPEED_ANY(temp)) {
|
||||
xhci_set_link_state(xhci, port_array,
|
||||
port_index, XDEV_RESUME);
|
||||
need_usb2_u3_exit = true;
|
||||
|
|
|
|||
|
|
@ -1828,24 +1828,20 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|||
for (i = 1; i < MAX_HC_SLOTS; ++i)
|
||||
xhci_free_virt_device(xhci, i);
|
||||
|
||||
if (xhci->segment_pool)
|
||||
dma_pool_destroy(xhci->segment_pool);
|
||||
dma_pool_destroy(xhci->segment_pool);
|
||||
xhci->segment_pool = NULL;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed segment pool");
|
||||
|
||||
if (xhci->device_pool)
|
||||
dma_pool_destroy(xhci->device_pool);
|
||||
dma_pool_destroy(xhci->device_pool);
|
||||
xhci->device_pool = NULL;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed device context pool");
|
||||
|
||||
if (xhci->small_streams_pool)
|
||||
dma_pool_destroy(xhci->small_streams_pool);
|
||||
dma_pool_destroy(xhci->small_streams_pool);
|
||||
xhci->small_streams_pool = NULL;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"Freed small stream array pool");
|
||||
|
||||
if (xhci->medium_streams_pool)
|
||||
dma_pool_destroy(xhci->medium_streams_pool);
|
||||
dma_pool_destroy(xhci->medium_streams_pool);
|
||||
xhci->medium_streams_pool = NULL;
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
"Freed medium stream array pool");
|
||||
|
|
@ -2072,14 +2068,23 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
|||
{
|
||||
u32 temp, port_offset, port_count;
|
||||
int i;
|
||||
struct xhci_hub *rhub;
|
||||
|
||||
if (major_revision > 0x03) {
|
||||
temp = readl(addr);
|
||||
|
||||
if (XHCI_EXT_PORT_MAJOR(temp) == 0x03) {
|
||||
rhub = &xhci->usb3_rhub;
|
||||
} else if (XHCI_EXT_PORT_MAJOR(temp) <= 0x02) {
|
||||
rhub = &xhci->usb2_rhub;
|
||||
} else {
|
||||
xhci_warn(xhci, "Ignoring unknown port speed, "
|
||||
"Ext Cap %p, revision = 0x%x\n",
|
||||
addr, major_revision);
|
||||
/* Ignoring port protocol we can't understand. FIXME */
|
||||
return;
|
||||
}
|
||||
rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp);
|
||||
rhub->min_rev = XHCI_EXT_PORT_MINOR(temp);
|
||||
|
||||
/* Port offset and count in the third dword, see section 7.2 */
|
||||
temp = readl(addr + 2);
|
||||
|
|
@ -2094,6 +2099,33 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
|
|||
/* WTF? "Valid values are ‘1’ to MaxPorts" */
|
||||
return;
|
||||
|
||||
rhub->psi_count = XHCI_EXT_PORT_PSIC(temp);
|
||||
if (rhub->psi_count) {
|
||||
rhub->psi = kcalloc(rhub->psi_count, sizeof(*rhub->psi),
|
||||
GFP_KERNEL);
|
||||
if (!rhub->psi)
|
||||
rhub->psi_count = 0;
|
||||
|
||||
rhub->psi_uid_count++;
|
||||
for (i = 0; i < rhub->psi_count; i++) {
|
||||
rhub->psi[i] = readl(addr + 4 + i);
|
||||
|
||||
/* count unique ID values, two consecutive entries can
|
||||
* have the same ID if link is assymetric
|
||||
*/
|
||||
if (i && (XHCI_EXT_PORT_PSIV(rhub->psi[i]) !=
|
||||
XHCI_EXT_PORT_PSIV(rhub->psi[i - 1])))
|
||||
rhub->psi_uid_count++;
|
||||
|
||||
xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d PSIM:%d\n",
|
||||
XHCI_EXT_PORT_PSIV(rhub->psi[i]),
|
||||
XHCI_EXT_PORT_PSIE(rhub->psi[i]),
|
||||
XHCI_EXT_PORT_PLT(rhub->psi[i]),
|
||||
XHCI_EXT_PORT_PFD(rhub->psi[i]),
|
||||
XHCI_EXT_PORT_LP(rhub->psi[i]),
|
||||
XHCI_EXT_PORT_PSIM(rhub->psi[i]));
|
||||
}
|
||||
}
|
||||
/* cache usb2 port capabilities */
|
||||
if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
|
||||
xhci->ext_caps[xhci->num_ext_caps++] = temp;
|
||||
|
|
|
|||
|
|
@ -201,15 +201,17 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
|||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
int retval;
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
if (!xhci->sbrn)
|
||||
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
|
||||
|
||||
retval = xhci_gen_setup(hcd, xhci_pci_quirks);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
if (!usb_hcd_is_primary_hcd(hcd))
|
||||
return 0;
|
||||
|
||||
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
|
||||
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
|
||||
|
||||
/* Find any debug ports */
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/usb/phy.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb/xhci_pdriver.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "xhci.h"
|
||||
#include "xhci-mvebu.h"
|
||||
|
|
@ -93,14 +94,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
if (irq < 0)
|
||||
return -ENODEV;
|
||||
|
||||
/* Initialize dma_mask and coherent_dma_mask to 32-bits */
|
||||
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!pdev->dev.dma_mask)
|
||||
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
|
||||
/* Try to set 64-bit DMA first */
|
||||
if (WARN_ON(!pdev->dev.dma_mask))
|
||||
/* Platform did not initialize dma_mask */
|
||||
ret = dma_coerce_mask_and_coherent(&pdev->dev,
|
||||
DMA_BIT_MASK(64));
|
||||
else
|
||||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
|
||||
|
||||
/* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
|
||||
if (ret) {
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
|
|
@ -262,6 +269,13 @@ static const struct of_device_id usb_xhci_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
|
||||
#endif
|
||||
|
||||
static const struct acpi_device_id usb_xhci_acpi_match[] = {
|
||||
/* XHCI-compliant USB Controller */
|
||||
{ "PNP0D10", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match);
|
||||
|
||||
static struct platform_driver usb_xhci_driver = {
|
||||
.probe = xhci_plat_probe,
|
||||
.remove = xhci_plat_remove,
|
||||
|
|
@ -269,6 +283,7 @@ static struct platform_driver usb_xhci_driver = {
|
|||
.name = "xhci-hcd",
|
||||
.pm = DEV_PM_OPS,
|
||||
.of_match_table = of_match_ptr(usb_xhci_of_match),
|
||||
.acpi_match_table = ACPI_PTR(usb_xhci_acpi_match),
|
||||
},
|
||||
};
|
||||
MODULE_ALIAS("platform:xhci-hcd");
|
||||
|
|
|
|||
|
|
@ -1453,7 +1453,7 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
|
|||
* 1.1 ports are under the USB 2.0 hub. If the port speed
|
||||
* matches the device speed, it's a similar speed port.
|
||||
*/
|
||||
if ((port_speed == 0x03) == (hcd->speed == HCD_USB3))
|
||||
if ((port_speed == 0x03) == (hcd->speed >= HCD_USB3))
|
||||
num_similar_speed_ports++;
|
||||
}
|
||||
return num_similar_speed_ports;
|
||||
|
|
@ -1515,7 +1515,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
|
||||
/* Find the right roothub. */
|
||||
hcd = xhci_to_hcd(xhci);
|
||||
if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
|
||||
if ((major_revision == 0x03) != (hcd->speed >= HCD_USB3))
|
||||
hcd = xhci->shared_hcd;
|
||||
|
||||
if (major_revision == 0) {
|
||||
|
|
@ -1541,7 +1541,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
* correct bus_state structure.
|
||||
*/
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
if (hcd->speed == HCD_USB3)
|
||||
if (hcd->speed >= HCD_USB3)
|
||||
port_array = xhci->usb3_ports;
|
||||
else
|
||||
port_array = xhci->usb2_ports;
|
||||
|
|
@ -1555,7 +1555,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
usb_hcd_resume_root_hub(hcd);
|
||||
}
|
||||
|
||||
if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
|
||||
if (hcd->speed >= HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
|
||||
bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
|
||||
|
||||
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
|
||||
|
|
@ -1567,7 +1567,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
if (DEV_SUPERSPEED_ANY(temp)) {
|
||||
xhci_dbg(xhci, "remote wake SS port %d\n", port_id);
|
||||
/* Set a flag to say the port signaled remote wakeup,
|
||||
* so we can tell the difference between the end of
|
||||
|
|
@ -1595,7 +1595,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
}
|
||||
|
||||
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
|
||||
DEV_SUPERSPEED(temp)) {
|
||||
DEV_SUPERSPEED_ANY(temp)) {
|
||||
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
|
||||
/* We've just brought the device into U0 through either the
|
||||
* Resume state after a device remote wakeup, or through the
|
||||
|
|
@ -1625,7 +1625,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
* RExit to a disconnect state). If so, let the the driver know it's
|
||||
* out of the RExit state.
|
||||
*/
|
||||
if (!DEV_SUPERSPEED(temp) &&
|
||||
if (!DEV_SUPERSPEED_ANY(temp) &&
|
||||
test_and_clear_bit(faked_port_index,
|
||||
&bus_state->rexit_ports)) {
|
||||
complete(&bus_state->rexit_done[faked_port_index]);
|
||||
|
|
@ -1633,7 +1633,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3)
|
||||
xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
|
||||
PORT_PLC);
|
||||
|
||||
|
|
@ -3048,21 +3048,6 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||
}
|
||||
|
||||
/*
|
||||
* The TD size is the number of bytes remaining in the TD (including this TRB),
|
||||
* right shifted by 10.
|
||||
* It must fit in bits 21:17, so it can't be bigger than 31.
|
||||
*/
|
||||
static u32 xhci_td_remainder(unsigned int remainder)
|
||||
{
|
||||
u32 max = (1 << (21 - 17 + 1)) - 1;
|
||||
|
||||
if ((remainder >> 10) >= max)
|
||||
return max << 17;
|
||||
else
|
||||
return (remainder >> 10) << 17;
|
||||
}
|
||||
|
||||
/*
|
||||
* For xHCI 1.0 host controllers, TD size is the number of max packet sized
|
||||
* packets remaining in the TD (*not* including this TRB).
|
||||
|
|
@ -3075,30 +3060,36 @@ static u32 xhci_td_remainder(unsigned int remainder)
|
|||
*
|
||||
* TD size = total_packet_count - packets_transferred
|
||||
*
|
||||
* It must fit in bits 21:17, so it can't be bigger than 31.
|
||||
* For xHCI 0.96 and older, TD size field should be the remaining bytes
|
||||
* including this TRB, right shifted by 10
|
||||
*
|
||||
* For all hosts it must fit in bits 21:17, so it can't be bigger than 31.
|
||||
* This is taken care of in the TRB_TD_SIZE() macro
|
||||
*
|
||||
* The last TRB in a TD must have the TD size set to zero.
|
||||
*/
|
||||
static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
|
||||
unsigned int total_packet_count, struct urb *urb,
|
||||
unsigned int num_trbs_left)
|
||||
static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
|
||||
int trb_buff_len, unsigned int td_total_len,
|
||||
struct urb *urb, unsigned int num_trbs_left)
|
||||
{
|
||||
int packets_transferred;
|
||||
u32 maxp, total_packet_count;
|
||||
|
||||
if (xhci->hci_version < 0x100)
|
||||
return ((td_total_len - transferred) >> 10);
|
||||
|
||||
maxp = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
|
||||
total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
|
||||
|
||||
/* One TRB with a zero-length data packet. */
|
||||
if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0))
|
||||
if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) ||
|
||||
trb_buff_len == td_total_len)
|
||||
return 0;
|
||||
|
||||
/* All the TRB queueing functions don't count the current TRB in
|
||||
* running_total.
|
||||
*/
|
||||
packets_transferred = (running_total + trb_buff_len) /
|
||||
GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
|
||||
|
||||
if ((total_packet_count - packets_transferred) > 31)
|
||||
return 31 << 17;
|
||||
return (total_packet_count - packets_transferred) << 17;
|
||||
/* Queueing functions don't count the current TRB into transferred */
|
||||
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
|
||||
}
|
||||
|
||||
|
||||
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct urb *urb, int slot_id, unsigned int ep_index)
|
||||
{
|
||||
|
|
@ -3220,17 +3211,12 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
}
|
||||
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
if (xhci->hci_version < 0x100) {
|
||||
remainder = xhci_td_remainder(
|
||||
urb->transfer_buffer_length -
|
||||
running_total);
|
||||
} else {
|
||||
remainder = xhci_v1_0_td_remainder(running_total,
|
||||
trb_buff_len, total_packet_count, urb,
|
||||
num_trbs - 1);
|
||||
}
|
||||
remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
|
||||
urb->transfer_buffer_length,
|
||||
urb, num_trbs - 1);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
remainder |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
if (num_trbs > 1)
|
||||
|
|
@ -3393,17 +3379,12 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
field |= TRB_ISP;
|
||||
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
if (xhci->hci_version < 0x100) {
|
||||
remainder = xhci_td_remainder(
|
||||
urb->transfer_buffer_length -
|
||||
running_total);
|
||||
} else {
|
||||
remainder = xhci_v1_0_td_remainder(running_total,
|
||||
trb_buff_len, total_packet_count, urb,
|
||||
num_trbs - 1);
|
||||
}
|
||||
remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
|
||||
urb->transfer_buffer_length,
|
||||
urb, num_trbs - 1);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
remainder |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
if (num_trbs > 1)
|
||||
|
|
@ -3441,7 +3422,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
struct usb_ctrlrequest *setup;
|
||||
struct xhci_generic_trb *start_trb;
|
||||
int start_cycle;
|
||||
u32 field, length_field;
|
||||
u32 field, length_field, remainder;
|
||||
struct urb_priv *urb_priv;
|
||||
struct xhci_td *td;
|
||||
|
||||
|
|
@ -3514,9 +3495,15 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
else
|
||||
field = TRB_TYPE(TRB_DATA);
|
||||
|
||||
remainder = xhci_td_remainder(xhci, 0,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer_length,
|
||||
urb, 1);
|
||||
|
||||
length_field = TRB_LEN(urb->transfer_buffer_length) |
|
||||
xhci_td_remainder(urb->transfer_buffer_length) |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
if (urb->transfer_buffer_length > 0) {
|
||||
if (setup->bRequestType & USB_DIR_IN)
|
||||
field |= TRB_DIR_IN;
|
||||
|
|
@ -3845,17 +3832,12 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
trb_buff_len = td_remain_len;
|
||||
|
||||
/* Set the TRB length, TD size, & interrupter fields. */
|
||||
if (xhci->hci_version < 0x100) {
|
||||
remainder = xhci_td_remainder(
|
||||
td_len - running_total);
|
||||
} else {
|
||||
remainder = xhci_v1_0_td_remainder(
|
||||
running_total, trb_buff_len,
|
||||
total_packet_count, urb,
|
||||
(trbs_per_td - j - 1));
|
||||
}
|
||||
remainder = xhci_td_remainder(xhci, running_total,
|
||||
trb_buff_len, td_len,
|
||||
urb, trbs_per_td - j - 1);
|
||||
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
remainder |
|
||||
TRB_TD_SIZE(remainder) |
|
||||
TRB_INTR_TARGET(0);
|
||||
|
||||
queue_trb(xhci, ep_ring, more_trbs_coming,
|
||||
|
|
|
|||
|
|
@ -3973,7 +3973,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
|
|||
__le32 __iomem *addr;
|
||||
int raw_port;
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
if (hcd->speed < HCD_USB3)
|
||||
addr = xhci->usb2_ports[port1 - 1];
|
||||
else
|
||||
addr = xhci->usb3_ports[port1 - 1];
|
||||
|
|
@ -4124,7 +4124,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
|||
int hird, exit_latency;
|
||||
int ret;
|
||||
|
||||
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
|
||||
if (hcd->speed >= HCD_USB3 || !xhci->hw_lpm_support ||
|
||||
!udev->lpm_capable)
|
||||
return -EPERM;
|
||||
|
||||
|
|
@ -4241,7 +4241,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int portnum = udev->portnum - 1;
|
||||
|
||||
if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
|
||||
if (hcd->speed >= HCD_USB3 || !xhci->sw_lpm_support ||
|
||||
!udev->lpm_capable)
|
||||
return 0;
|
||||
|
||||
|
|
@ -4841,8 +4841,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||
/* XHCI controllers don't stop the ep queue on short packets :| */
|
||||
hcd->self.no_stop_on_short = 1;
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (usb_hcd_is_primary_hcd(hcd)) {
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
xhci->main_hcd = hcd;
|
||||
/* Mark the first roothub as being USB 2.0.
|
||||
* The xHCI driver will register the USB 3.0 roothub.
|
||||
|
|
@ -4856,6 +4857,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||
*/
|
||||
hcd->has_tt = 1;
|
||||
} else {
|
||||
if (xhci->sbrn == 0x31) {
|
||||
xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n");
|
||||
hcd->speed = HCD_USB31;
|
||||
}
|
||||
/* xHCI private pointer was set in xhci_pci_probe for the second
|
||||
* registered roothub.
|
||||
*/
|
||||
|
|
@ -4875,6 +4880,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||
xhci->hcc_params = readl(&xhci->cap_regs->hc_capbase);
|
||||
xhci->hci_version = HC_VERSION(xhci->hcc_params);
|
||||
xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);
|
||||
if (xhci->hci_version > 0x100)
|
||||
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
|
||||
xhci_print_registers(xhci);
|
||||
|
||||
xhci->quirks = quirks;
|
||||
|
|
@ -4906,6 +4913,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||
!dma_set_mask(dev, DMA_BIT_MASK(64))) {
|
||||
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
|
||||
dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
|
||||
} else {
|
||||
/*
|
||||
* This is to avoid error in cases where a 32-bit USB
|
||||
* controller is used on a 64-bit capable system.
|
||||
*/
|
||||
retval = dma_set_mask(dev, DMA_BIT_MASK(32));
|
||||
if (retval)
|
||||
return retval;
|
||||
xhci_dbg(xhci, "Enabling 32-bit DMA addresses.\n");
|
||||
dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Calling HCD init\n");
|
||||
|
|
@ -5020,7 +5037,7 @@ static int __init xhci_hcd_init(void)
|
|||
BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);
|
||||
BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);
|
||||
BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
|
||||
BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8);
|
||||
BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 8*32/8);
|
||||
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
|
||||
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
|
||||
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include <asm-generic/io-64-nonatomic-lo-hi.h>
|
||||
|
||||
/* Code sharing between pci-quirks and xhci hcd */
|
||||
#include "xhci-ext-caps.h"
|
||||
#include "pci-quirks.h"
|
||||
|
|
@ -56,6 +58,7 @@
|
|||
* @hcc_params: HCCPARAMS - Capability Parameters
|
||||
* @db_off: DBOFF - Doorbell array offset
|
||||
* @run_regs_off: RTSOFF - Runtime register space offset
|
||||
* @hcc_params2: HCCPARAMS2 Capability Parameters 2, xhci 1.1 only
|
||||
*/
|
||||
struct xhci_cap_regs {
|
||||
__le32 hc_capbase;
|
||||
|
|
@ -65,6 +68,7 @@ struct xhci_cap_regs {
|
|||
__le32 hcc_params;
|
||||
__le32 db_off;
|
||||
__le32 run_regs_off;
|
||||
__le32 hcc_params2; /* xhci 1.1 */
|
||||
/* Reserved up to (CAPLENGTH - 0x1C) */
|
||||
};
|
||||
|
||||
|
|
@ -134,6 +138,21 @@ struct xhci_cap_regs {
|
|||
/* run_regs_off bitmask - bits 0:4 reserved */
|
||||
#define RTSOFF_MASK (~0x1f)
|
||||
|
||||
/* HCCPARAMS2 - hcc_params2 - bitmasks */
|
||||
/* true: HC supports U3 entry Capability */
|
||||
#define HCC2_U3C(p) ((p) & (1 << 0))
|
||||
/* true: HC supports Configure endpoint command Max exit latency too large */
|
||||
#define HCC2_CMC(p) ((p) & (1 << 1))
|
||||
/* true: HC supports Force Save context Capability */
|
||||
#define HCC2_FSC(p) ((p) & (1 << 2))
|
||||
/* true: HC supports Compliance Transition Capability */
|
||||
#define HCC2_CTC(p) ((p) & (1 << 3))
|
||||
/* true: HC support Large ESIT payload Capability > 48k */
|
||||
#define HCC2_LEC(p) ((p) & (1 << 4))
|
||||
/* true: HC support Configuration Information Capability */
|
||||
#define HCC2_CIC(p) ((p) & (1 << 5))
|
||||
/* true: HC support Extended TBC Capability, Isoc burst count > 65535 */
|
||||
#define HCC2_ETC(p) ((p) & (1 << 6))
|
||||
|
||||
/* Number of registers per port */
|
||||
#define NUM_PORT_REGS 4
|
||||
|
|
@ -269,7 +288,11 @@ struct xhci_op_regs {
|
|||
/* CONFIG - Configure Register - config_reg bitmasks */
|
||||
/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */
|
||||
#define MAX_DEVS(p) ((p) & 0xff)
|
||||
/* bits 8:31 - reserved and should be preserved */
|
||||
/* bit 8: U3 Entry Enabled, assert PLC when root port enters U3, xhci 1.1 */
|
||||
#define CONFIG_U3E (1 << 8)
|
||||
/* bit 9: Configuration Information Enable, xhci 1.1 */
|
||||
#define CONFIG_CIE (1 << 9)
|
||||
/* bits 10:31 - reserved and should be preserved */
|
||||
|
||||
/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
|
||||
/* true: device connected */
|
||||
|
|
@ -306,11 +329,16 @@ struct xhci_op_regs {
|
|||
#define XDEV_LS (0x2 << 10)
|
||||
#define XDEV_HS (0x3 << 10)
|
||||
#define XDEV_SS (0x4 << 10)
|
||||
#define XDEV_SSP (0x5 << 10)
|
||||
#define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10))
|
||||
#define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS)
|
||||
#define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS)
|
||||
#define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS)
|
||||
#define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS)
|
||||
#define DEV_SUPERSPEEDPLUS(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP)
|
||||
#define DEV_SUPERSPEED_ANY(p) (((p) & DEV_SPEED_MASK) >= XDEV_SS)
|
||||
#define DEV_PORT_SPEED(p) (((p) >> 10) & 0x0f)
|
||||
|
||||
/* Bits 20:23 in the Slot Context are the speed for the device */
|
||||
#define SLOT_SPEED_FS (XDEV_FS << 10)
|
||||
#define SLOT_SPEED_LS (XDEV_LS << 10)
|
||||
|
|
@ -394,6 +422,9 @@ struct xhci_op_regs {
|
|||
#define PORT_L1DS(p) (((p) & 0xff) << 8)
|
||||
#define PORT_HLE (1 << 16)
|
||||
|
||||
/* USB3 Protocol PORTLI Port Link Information */
|
||||
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
|
||||
#define PORT_TX_LANES(p) (((p) >> 20) & 0xf)
|
||||
|
||||
/* USB2 Protocol PORTHLPMC */
|
||||
#define PORT_HIRDM(p)((p) & 3)
|
||||
|
|
@ -519,9 +550,23 @@ struct xhci_protocol_caps {
|
|||
};
|
||||
|
||||
#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff)
|
||||
#define XHCI_EXT_PORT_MINOR(x) (((x) >> 16) & 0xff)
|
||||
#define XHCI_EXT_PORT_PSIC(x) (((x) >> 28) & 0x0f)
|
||||
#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff)
|
||||
#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff)
|
||||
|
||||
#define XHCI_EXT_PORT_PSIV(x) (((x) >> 0) & 0x0f)
|
||||
#define XHCI_EXT_PORT_PSIE(x) (((x) >> 4) & 0x03)
|
||||
#define XHCI_EXT_PORT_PLT(x) (((x) >> 6) & 0x03)
|
||||
#define XHCI_EXT_PORT_PFD(x) (((x) >> 8) & 0x01)
|
||||
#define XHCI_EXT_PORT_LP(x) (((x) >> 14) & 0x03)
|
||||
#define XHCI_EXT_PORT_PSIM(x) (((x) >> 16) & 0xffff)
|
||||
|
||||
#define PLT_MASK (0x03 << 6)
|
||||
#define PLT_SYM (0x00 << 6)
|
||||
#define PLT_ASYM_RX (0x02 << 6)
|
||||
#define PLT_ASYM_TX (0x03 << 6)
|
||||
|
||||
/**
|
||||
* struct xhci_container_ctx
|
||||
* @type: Type of context. Used to calculated offsets to contained contexts.
|
||||
|
|
@ -1136,6 +1181,8 @@ enum xhci_setup_dev {
|
|||
/* Normal TRB fields */
|
||||
/* transfer_len bitmasks - bits 0:16 */
|
||||
#define TRB_LEN(p) ((p) & 0x1ffff)
|
||||
/* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */
|
||||
#define TRB_TD_SIZE(p) (min((p), (u32)31) << 17)
|
||||
/* Interrupter Target - which MSI-X vector to target the completion event at */
|
||||
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
|
||||
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
|
||||
|
|
@ -1448,6 +1495,14 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
struct xhci_hub {
|
||||
u8 maj_rev;
|
||||
u8 min_rev;
|
||||
u32 *psi; /* array of protocol speed ID entries */
|
||||
u8 psi_count;
|
||||
u8 psi_uid_count;
|
||||
};
|
||||
|
||||
/* There is one xhci_hcd structure per controller */
|
||||
struct xhci_hcd {
|
||||
struct usb_hcd *main_hcd;
|
||||
|
|
@ -1465,6 +1520,7 @@ struct xhci_hcd {
|
|||
__u32 hcs_params2;
|
||||
__u32 hcs_params3;
|
||||
__u32 hcc_params;
|
||||
__u32 hcc_params2;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
|
|
@ -1586,6 +1642,8 @@ struct xhci_hcd {
|
|||
unsigned int num_usb3_ports;
|
||||
/* Array of pointers to USB 2.0 PORTSC registers */
|
||||
__le32 __iomem **usb2_ports;
|
||||
struct xhci_hub usb2_rhub;
|
||||
struct xhci_hub usb3_rhub;
|
||||
unsigned int num_usb2_ports;
|
||||
/* support xHCI 0.96 spec USB2 software LPM */
|
||||
unsigned sw_lpm_support:1;
|
||||
|
|
@ -1651,20 +1709,12 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
|
|||
static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
|
||||
__le64 __iomem *regs)
|
||||
{
|
||||
__u32 __iomem *ptr = (__u32 __iomem *) regs;
|
||||
u64 val_lo = readl(ptr);
|
||||
u64 val_hi = readl(ptr + 1);
|
||||
return val_lo + (val_hi << 32);
|
||||
return lo_hi_readq(regs);
|
||||
}
|
||||
static inline void xhci_write_64(struct xhci_hcd *xhci,
|
||||
const u64 val, __le64 __iomem *regs)
|
||||
{
|
||||
__u32 __iomem *ptr = (__u32 __iomem *) regs;
|
||||
u32 val_lo = lower_32_bits(val);
|
||||
u32 val_hi = upper_32_bits(val);
|
||||
|
||||
writel(val_lo, ptr);
|
||||
writel(val_hi, ptr + 1);
|
||||
lo_hi_writeq(val, regs);
|
||||
}
|
||||
|
||||
static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ static int __init usb3503_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver);
|
||||
err = i2c_add_driver(&usb3503_i2c_driver);
|
||||
if (err != 0)
|
||||
pr_err("usb3503: Failed to register I2C driver: %d\n", err);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
static int override_alt = -1;
|
||||
module_param_named(alt, override_alt, int, 0644);
|
||||
MODULE_PARM_DESC(alt, ">= 0 to override altsetting selection");
|
||||
static void complicated_callback(struct urb *urb);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -95,6 +96,7 @@ static struct usb_device *testdev_to_usbdev(struct usbtest_dev *test)
|
|||
dev_warn(&(tdev)->intf->dev , fmt , ## args)
|
||||
|
||||
#define GUARD_BYTE 0xA5
|
||||
#define MAX_SGLEN 128
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -238,7 +240,8 @@ static struct urb *usbtest_alloc_urb(
|
|||
unsigned long bytes,
|
||||
unsigned transfer_flags,
|
||||
unsigned offset,
|
||||
u8 bInterval)
|
||||
u8 bInterval,
|
||||
usb_complete_t complete_fn)
|
||||
{
|
||||
struct urb *urb;
|
||||
|
||||
|
|
@ -247,10 +250,10 @@ static struct urb *usbtest_alloc_urb(
|
|||
return urb;
|
||||
|
||||
if (bInterval)
|
||||
usb_fill_int_urb(urb, udev, pipe, NULL, bytes, simple_callback,
|
||||
usb_fill_int_urb(urb, udev, pipe, NULL, bytes, complete_fn,
|
||||
NULL, bInterval);
|
||||
else
|
||||
usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback,
|
||||
usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, complete_fn,
|
||||
NULL);
|
||||
|
||||
urb->interval = (udev->speed == USB_SPEED_HIGH)
|
||||
|
|
@ -295,7 +298,17 @@ static struct urb *simple_alloc_urb(
|
|||
u8 bInterval)
|
||||
{
|
||||
return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
|
||||
bInterval);
|
||||
bInterval, simple_callback);
|
||||
}
|
||||
|
||||
static struct urb *complicated_alloc_urb(
|
||||
struct usb_device *udev,
|
||||
int pipe,
|
||||
unsigned long bytes,
|
||||
u8 bInterval)
|
||||
{
|
||||
return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
|
||||
bInterval, complicated_callback);
|
||||
}
|
||||
|
||||
static unsigned pattern;
|
||||
|
|
@ -303,11 +316,20 @@ static unsigned mod_pattern;
|
|||
module_param_named(pattern, mod_pattern, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(mod_pattern, "i/o pattern (0 == zeroes)");
|
||||
|
||||
static inline void simple_fill_buf(struct urb *urb)
|
||||
static unsigned get_maxpacket(struct usb_device *udev, int pipe)
|
||||
{
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
ep = usb_pipe_endpoint(udev, pipe);
|
||||
return le16_to_cpup(&ep->desc.wMaxPacketSize);
|
||||
}
|
||||
|
||||
static void simple_fill_buf(struct urb *urb)
|
||||
{
|
||||
unsigned i;
|
||||
u8 *buf = urb->transfer_buffer;
|
||||
unsigned len = urb->transfer_buffer_length;
|
||||
unsigned maxpacket;
|
||||
|
||||
switch (pattern) {
|
||||
default:
|
||||
|
|
@ -316,8 +338,9 @@ static inline void simple_fill_buf(struct urb *urb)
|
|||
memset(buf, 0, len);
|
||||
break;
|
||||
case 1: /* mod63 */
|
||||
maxpacket = get_maxpacket(urb->dev, urb->pipe);
|
||||
for (i = 0; i < len; i++)
|
||||
*buf++ = (u8) (i % 63);
|
||||
*buf++ = (u8) ((i % maxpacket) % 63);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -349,6 +372,7 @@ static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
|
|||
u8 expected;
|
||||
u8 *buf = urb->transfer_buffer;
|
||||
unsigned len = urb->actual_length;
|
||||
unsigned maxpacket = get_maxpacket(urb->dev, urb->pipe);
|
||||
|
||||
int ret = check_guard_bytes(tdev, urb);
|
||||
if (ret)
|
||||
|
|
@ -366,7 +390,7 @@ static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
|
|||
* with set_interface or set_config.
|
||||
*/
|
||||
case 1: /* mod63 */
|
||||
expected = i % 63;
|
||||
expected = (i % maxpacket) % 63;
|
||||
break;
|
||||
/* always fail unsupported patterns */
|
||||
default:
|
||||
|
|
@ -478,11 +502,13 @@ static void free_sglist(struct scatterlist *sg, int nents)
|
|||
}
|
||||
|
||||
static struct scatterlist *
|
||||
alloc_sglist(int nents, int max, int vary)
|
||||
alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned i;
|
||||
unsigned size = max;
|
||||
unsigned maxpacket =
|
||||
get_maxpacket(interface_to_usbdev(dev->intf), pipe);
|
||||
|
||||
if (max == 0)
|
||||
return NULL;
|
||||
|
|
@ -511,7 +537,7 @@ alloc_sglist(int nents, int max, int vary)
|
|||
break;
|
||||
case 1:
|
||||
for (j = 0; j < size; j++)
|
||||
*buf++ = (u8) (j % 63);
|
||||
*buf++ = (u8) ((j % maxpacket) % 63);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1719,7 +1745,7 @@ static int ctrl_out(struct usbtest_dev *dev,
|
|||
for (i = 0; i < count; i++) {
|
||||
/* write patterned data */
|
||||
for (j = 0; j < len; j++)
|
||||
buf[j] = i + j;
|
||||
buf[j] = (u8)(i + j);
|
||||
retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,
|
||||
0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
|
||||
|
|
@ -1749,9 +1775,9 @@ static int ctrl_out(struct usbtest_dev *dev,
|
|||
|
||||
/* fail if we can't verify */
|
||||
for (j = 0; j < len; j++) {
|
||||
if (buf[j] != (u8) (i + j)) {
|
||||
if (buf[j] != (u8)(i + j)) {
|
||||
ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
|
||||
j, buf[j], (u8) i + j);
|
||||
j, buf[j], (u8)(i + j));
|
||||
retval = -EBADMSG;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1781,12 +1807,12 @@ static int ctrl_out(struct usbtest_dev *dev,
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* ISO tests ... mimics common usage
|
||||
/* ISO/BULK tests ... mimics common usage
|
||||
* - buffer length is split into N packets (mostly maxpacket sized)
|
||||
* - multi-buffers according to sglen
|
||||
*/
|
||||
|
||||
struct iso_context {
|
||||
struct transfer_context {
|
||||
unsigned count;
|
||||
unsigned pending;
|
||||
spinlock_t lock;
|
||||
|
|
@ -1795,11 +1821,12 @@ struct iso_context {
|
|||
unsigned long errors;
|
||||
unsigned long packet_count;
|
||||
struct usbtest_dev *dev;
|
||||
bool is_iso;
|
||||
};
|
||||
|
||||
static void iso_callback(struct urb *urb)
|
||||
static void complicated_callback(struct urb *urb)
|
||||
{
|
||||
struct iso_context *ctx = urb->context;
|
||||
struct transfer_context *ctx = urb->context;
|
||||
|
||||
spin_lock(&ctx->lock);
|
||||
ctx->count--;
|
||||
|
|
@ -1808,7 +1835,7 @@ static void iso_callback(struct urb *urb)
|
|||
if (urb->error_count > 0)
|
||||
ctx->errors += urb->error_count;
|
||||
else if (urb->status != 0)
|
||||
ctx->errors += urb->number_of_packets;
|
||||
ctx->errors += (ctx->is_iso ? urb->number_of_packets : 1);
|
||||
else if (urb->actual_length != urb->transfer_buffer_length)
|
||||
ctx->errors++;
|
||||
else if (check_guard_bytes(ctx->dev, urb) != 0)
|
||||
|
|
@ -1895,7 +1922,7 @@ static struct urb *iso_alloc_urb(
|
|||
urb->iso_frame_desc[i].offset = maxp * i;
|
||||
}
|
||||
|
||||
urb->complete = iso_callback;
|
||||
urb->complete = complicated_callback;
|
||||
/* urb->context = SET BY CALLER */
|
||||
urb->interval = 1 << (desc->bInterval - 1);
|
||||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
||||
|
|
@ -1903,37 +1930,33 @@ static struct urb *iso_alloc_urb(
|
|||
}
|
||||
|
||||
static int
|
||||
test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
||||
test_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
||||
int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)
|
||||
{
|
||||
struct iso_context context;
|
||||
struct transfer_context context;
|
||||
struct usb_device *udev;
|
||||
unsigned i;
|
||||
unsigned long packets = 0;
|
||||
int status = 0;
|
||||
struct urb *urbs[10]; /* FIXME no limit */
|
||||
|
||||
if (param->sglen > 10)
|
||||
return -EDOM;
|
||||
struct urb *urbs[param->sglen];
|
||||
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.count = param->iterations * param->sglen;
|
||||
context.dev = dev;
|
||||
context.is_iso = !!desc;
|
||||
init_completion(&context.done);
|
||||
spin_lock_init(&context.lock);
|
||||
|
||||
memset(urbs, 0, sizeof(urbs));
|
||||
udev = testdev_to_usbdev(dev);
|
||||
dev_info(&dev->intf->dev,
|
||||
"iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
|
||||
1 << (desc->bInterval - 1),
|
||||
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
|
||||
usb_endpoint_maxp(desc) & 0x7ff,
|
||||
1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)));
|
||||
|
||||
for (i = 0; i < param->sglen; i++) {
|
||||
urbs[i] = iso_alloc_urb(udev, pipe, desc,
|
||||
if (context.is_iso)
|
||||
urbs[i] = iso_alloc_urb(udev, pipe, desc,
|
||||
param->length, offset);
|
||||
else
|
||||
urbs[i] = complicated_alloc_urb(udev, pipe,
|
||||
param->length, 0);
|
||||
|
||||
if (!urbs[i]) {
|
||||
status = -ENOMEM;
|
||||
goto fail;
|
||||
|
|
@ -1942,11 +1965,21 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|||
urbs[i]->context = &context;
|
||||
}
|
||||
packets *= param->iterations;
|
||||
dev_info(&dev->intf->dev,
|
||||
"total %lu msec (%lu packets)\n",
|
||||
(packets * (1 << (desc->bInterval - 1)))
|
||||
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
|
||||
packets);
|
||||
|
||||
if (context.is_iso) {
|
||||
dev_info(&dev->intf->dev,
|
||||
"iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
|
||||
1 << (desc->bInterval - 1),
|
||||
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
|
||||
usb_endpoint_maxp(desc) & 0x7ff,
|
||||
1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)));
|
||||
|
||||
dev_info(&dev->intf->dev,
|
||||
"total %lu msec (%lu packets)\n",
|
||||
(packets * (1 << (desc->bInterval - 1)))
|
||||
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
|
||||
packets);
|
||||
}
|
||||
|
||||
spin_lock_irq(&context.lock);
|
||||
for (i = 0; i < param->sglen; i++) {
|
||||
|
|
@ -1983,7 +2016,8 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|||
;
|
||||
else if (context.submit_error)
|
||||
status = -EACCES;
|
||||
else if (context.errors > context.packet_count / 10)
|
||||
else if (context.errors >
|
||||
(context.is_iso ? context.packet_count / 10 : 0))
|
||||
status = -EIO;
|
||||
return status;
|
||||
|
||||
|
|
@ -2004,8 +2038,8 @@ static int test_unaligned_bulk(
|
|||
const char *label)
|
||||
{
|
||||
int retval;
|
||||
struct urb *urb = usbtest_alloc_urb(
|
||||
testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1, 0);
|
||||
struct urb *urb = usbtest_alloc_urb(testdev_to_usbdev(tdev),
|
||||
pipe, length, transfer_flags, 1, 0, simple_callback);
|
||||
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
|
@ -2061,6 +2095,9 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
if (param->iterations <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (param->sglen > MAX_SGLEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&dev->lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
|
|
@ -2176,7 +2213,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
"TEST 5: write %d sglists %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
sg = alloc_sglist(param->sglen, param->length, 0);
|
||||
sg = alloc_sglist(param->sglen, param->length,
|
||||
0, dev, dev->out_pipe);
|
||||
if (!sg) {
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
|
|
@ -2194,7 +2232,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
"TEST 6: read %d sglists %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
sg = alloc_sglist(param->sglen, param->length, 0);
|
||||
sg = alloc_sglist(param->sglen, param->length,
|
||||
0, dev, dev->in_pipe);
|
||||
if (!sg) {
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
|
|
@ -2211,7 +2250,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
"TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
|
||||
param->vary, param->iterations,
|
||||
param->sglen, param->length);
|
||||
sg = alloc_sglist(param->sglen, param->length, param->vary);
|
||||
sg = alloc_sglist(param->sglen, param->length,
|
||||
param->vary, dev, dev->out_pipe);
|
||||
if (!sg) {
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
|
|
@ -2228,7 +2268,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
"TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
|
||||
param->vary, param->iterations,
|
||||
param->sglen, param->length);
|
||||
sg = alloc_sglist(param->sglen, param->length, param->vary);
|
||||
sg = alloc_sglist(param->sglen, param->length,
|
||||
param->vary, dev, dev->in_pipe);
|
||||
if (!sg) {
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
|
|
@ -2325,7 +2366,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
/* FIRMWARE: iso sink */
|
||||
retval = test_iso_queue(dev, param,
|
||||
retval = test_queue(dev, param,
|
||||
dev->out_iso_pipe, dev->iso_out, 0);
|
||||
break;
|
||||
|
||||
|
|
@ -2338,7 +2379,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
/* FIRMWARE: iso source */
|
||||
retval = test_iso_queue(dev, param,
|
||||
retval = test_queue(dev, param,
|
||||
dev->in_iso_pipe, dev->iso_in, 0);
|
||||
break;
|
||||
|
||||
|
|
@ -2419,7 +2460,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
"TEST 22: write %d iso odd, %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
retval = test_iso_queue(dev, param,
|
||||
retval = test_queue(dev, param,
|
||||
dev->out_iso_pipe, dev->iso_out, 1);
|
||||
break;
|
||||
|
||||
|
|
@ -2430,7 +2471,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
"TEST 23: read %d iso odd, %d entries of %d bytes\n",
|
||||
param->iterations,
|
||||
param->sglen, param->length);
|
||||
retval = test_iso_queue(dev, param,
|
||||
retval = test_queue(dev, param,
|
||||
dev->in_iso_pipe, dev->iso_in, 1);
|
||||
break;
|
||||
|
||||
|
|
@ -2487,6 +2528,25 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
|
|||
retval = simple_io(dev, urb, param->iterations, 0, 0, "test26");
|
||||
simple_free_urb(urb);
|
||||
break;
|
||||
case 27:
|
||||
/* We do performance test, so ignore data compare */
|
||||
if (dev->out_pipe == 0 || param->sglen == 0 || pattern != 0)
|
||||
break;
|
||||
dev_info(&intf->dev,
|
||||
"TEST 27: bulk write %dMbytes\n", (param->iterations *
|
||||
param->sglen * param->length) / (1024 * 1024));
|
||||
retval = test_queue(dev, param,
|
||||
dev->out_pipe, NULL, 0);
|
||||
break;
|
||||
case 28:
|
||||
if (dev->in_pipe == 0 || param->sglen == 0 || pattern != 0)
|
||||
break;
|
||||
dev_info(&intf->dev,
|
||||
"TEST 28: bulk read %dMbytes\n", (param->iterations *
|
||||
param->sglen * param->length) / (1024 * 1024));
|
||||
retval = test_queue(dev, param,
|
||||
dev->in_pipe, NULL, 0);
|
||||
break;
|
||||
}
|
||||
do_gettimeofday(¶m->duration);
|
||||
param->duration.tv_sec -= start.tv_sec;
|
||||
|
|
|
|||
|
|
@ -1028,18 +1028,22 @@ void musb_start(struct musb *musb)
|
|||
{
|
||||
void __iomem *regs = musb->mregs;
|
||||
u8 devctl = musb_readb(regs, MUSB_DEVCTL);
|
||||
u8 power;
|
||||
|
||||
dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
|
||||
|
||||
musb_enable_interrupts(musb);
|
||||
musb_writeb(regs, MUSB_TESTMODE, 0);
|
||||
|
||||
/* put into basic highspeed mode and start session */
|
||||
musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
|
||||
| MUSB_POWER_HSENAB
|
||||
/* ENSUSPEND wedges tusb */
|
||||
/* | MUSB_POWER_ENSUSPEND */
|
||||
);
|
||||
power = MUSB_POWER_ISOUPDATE;
|
||||
/*
|
||||
* treating UNKNOWN as unspecified maximum speed, in which case
|
||||
* we will default to high-speed.
|
||||
*/
|
||||
if (musb->config->maximum_speed == USB_SPEED_HIGH ||
|
||||
musb->config->maximum_speed == USB_SPEED_UNKNOWN)
|
||||
power |= MUSB_POWER_HSENAB;
|
||||
musb_writeb(regs, MUSB_POWER, power);
|
||||
|
||||
musb->is_active = 0;
|
||||
devctl = musb_readb(regs, MUSB_DEVCTL);
|
||||
|
|
@ -1771,13 +1775,20 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
unsigned long flags;
|
||||
unsigned long val;
|
||||
int vbus;
|
||||
u8 devctl;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
val = musb->a_wait_bcon;
|
||||
/* FIXME get_vbus_status() is normally #defined as false...
|
||||
* and is effectively TUSB-specific.
|
||||
*/
|
||||
vbus = musb_platform_get_vbus_status(musb);
|
||||
if (vbus < 0) {
|
||||
/* Use default MUSB method by means of DEVCTL register */
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
if ((devctl & MUSB_DEVCTL_VBUS)
|
||||
== (3 << MUSB_DEVCTL_VBUS_SHIFT))
|
||||
vbus = 1;
|
||||
else
|
||||
vbus = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
return sprintf(buf, "Vbus %s, timeout %lu msec\n",
|
||||
|
|
|
|||
|
|
@ -579,7 +579,7 @@ static inline int musb_platform_recover(struct musb *musb)
|
|||
static inline int musb_platform_get_vbus_status(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->vbus_status)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
|
||||
return musb->ops->vbus_status(musb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ static int get_musb_port_mode(struct device *dev)
|
|||
{
|
||||
enum usb_dr_mode mode;
|
||||
|
||||
mode = of_usb_get_dr_mode(dev->of_node);
|
||||
mode = usb_get_dr_mode(dev);
|
||||
switch (mode) {
|
||||
case USB_DR_MODE_HOST:
|
||||
return MUSB_PORT_MODE_HOST;
|
||||
|
|
@ -747,6 +747,19 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
|
|||
if (!ret && val)
|
||||
config->multipoint = true;
|
||||
|
||||
config->maximum_speed = usb_get_maximum_speed(&parent->dev);
|
||||
switch (config->maximum_speed) {
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
dev_warn(dev, "ignore incorrect maximum_speed "
|
||||
"(super-speed) setting in dts");
|
||||
/* fall through */
|
||||
default:
|
||||
config->maximum_speed = USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add platform_data\n");
|
||||
|
|
|
|||
|
|
@ -341,6 +341,16 @@ static void sunxi_musb_disable(struct musb *musb)
|
|||
clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
|
||||
}
|
||||
|
||||
struct dma_controller *sunxi_musb_dma_controller_create(struct musb *musb,
|
||||
void __iomem *base)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sunxi_musb_dma_controller_destroy(struct dma_controller *c)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* sunxi musb register layout
|
||||
* 0x00 - 0x17 fifo regs, 1 long per fifo
|
||||
|
|
@ -566,6 +576,8 @@ static const struct musb_platform_ops sunxi_musb_ops = {
|
|||
.writeb = sunxi_musb_writeb,
|
||||
.readw = sunxi_musb_readw,
|
||||
.writew = sunxi_musb_writew,
|
||||
.dma_init = sunxi_musb_dma_controller_create,
|
||||
.dma_exit = sunxi_musb_dma_controller_destroy,
|
||||
.set_vbus = sunxi_musb_set_vbus,
|
||||
.pre_root_reset_end = sunxi_musb_pre_root_reset_end,
|
||||
.post_root_reset_end = sunxi_musb_post_root_reset_end,
|
||||
|
|
@ -617,7 +629,7 @@ static int sunxi_musb_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
switch (of_usb_get_dr_mode(np)) {
|
||||
switch (usb_get_dr_mode(&pdev->dev)) {
|
||||
#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
|
||||
case USB_DR_MODE_HOST:
|
||||
pdata.mode = MUSB_PORT_MODE_HOST;
|
||||
|
|
|
|||
|
|
@ -1529,7 +1529,7 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
|
|||
if (IS_ERR(motg->phy_rst))
|
||||
motg->phy_rst = NULL;
|
||||
|
||||
pdata->mode = of_usb_get_dr_mode(node);
|
||||
pdata->mode = usb_get_dr_mode(&pdev->dev);
|
||||
if (pdata->mode == USB_DR_MODE_UNKNOWN)
|
||||
pdata->mode = USB_DR_MODE_OTG;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ struct phy_8x16 {
|
|||
|
||||
struct reset_control *phy_reset;
|
||||
|
||||
struct extcon_specific_cable_nb vbus_cable;
|
||||
struct extcon_dev *vbus_edev;
|
||||
struct notifier_block vbus_notify;
|
||||
|
||||
struct gpio_desc *switch_gpio;
|
||||
|
|
@ -234,7 +234,7 @@ static int phy_8x16_init(struct usb_phy *phy)
|
|||
val = ULPI_PWR_OTG_COMP_DISABLE;
|
||||
usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG));
|
||||
|
||||
state = extcon_get_cable_state(qphy->vbus_cable.edev, "USB");
|
||||
state = extcon_get_cable_state_(qphy->vbus_edev, EXTCON_USB);
|
||||
if (state)
|
||||
phy_8x16_vbus_on(qphy);
|
||||
else
|
||||
|
|
@ -314,7 +314,6 @@ static int phy_8x16_reboot_notify(struct notifier_block *this,
|
|||
|
||||
static int phy_8x16_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct extcon_dev *edev;
|
||||
struct phy_8x16 *qphy;
|
||||
struct resource *res;
|
||||
struct usb_phy *phy;
|
||||
|
|
@ -349,9 +348,9 @@ static int phy_8x16_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
edev = extcon_get_edev_by_phandle(phy->dev, 0);
|
||||
if (IS_ERR(edev))
|
||||
return PTR_ERR(edev);
|
||||
qphy->vbus_edev = extcon_get_edev_by_phandle(phy->dev, 0);
|
||||
if (IS_ERR(qphy->vbus_edev))
|
||||
return PTR_ERR(qphy->vbus_edev);
|
||||
|
||||
ret = clk_set_rate(qphy->core_clk, INT_MAX);
|
||||
if (ret < 0)
|
||||
|
|
@ -370,8 +369,8 @@ static int phy_8x16_probe(struct platform_device *pdev)
|
|||
goto off_clks;
|
||||
|
||||
qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify;
|
||||
ret = extcon_register_interest(&qphy->vbus_cable, edev->name,
|
||||
"USB", &qphy->vbus_notify);
|
||||
ret = extcon_register_notifier(qphy->vbus_edev, EXTCON_USB,
|
||||
&qphy->vbus_notify);
|
||||
if (ret < 0)
|
||||
goto off_power;
|
||||
|
||||
|
|
@ -385,7 +384,8 @@ static int phy_8x16_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
off_extcon:
|
||||
extcon_unregister_interest(&qphy->vbus_cable);
|
||||
extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB,
|
||||
&qphy->vbus_notify);
|
||||
off_power:
|
||||
phy_8x16_regulators_disable(qphy);
|
||||
off_clks:
|
||||
|
|
@ -400,7 +400,8 @@ static int phy_8x16_remove(struct platform_device *pdev)
|
|||
struct phy_8x16 *qphy = platform_get_drvdata(pdev);
|
||||
|
||||
unregister_reboot_notifier(&qphy->reboot_notify);
|
||||
extcon_unregister_interest(&qphy->vbus_cable);
|
||||
extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB,
|
||||
&qphy->vbus_notify);
|
||||
|
||||
/*
|
||||
* Ensure that D+/D- lines are routed to uB connector, so
|
||||
|
|
|
|||
|
|
@ -1029,7 +1029,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (of_find_property(np, "dr_mode", NULL))
|
||||
tegra_phy->mode = of_usb_get_dr_mode(np);
|
||||
tegra_phy->mode = usb_get_dr_mode(&pdev->dev);
|
||||
else
|
||||
tegra_phy->mode = USB_DR_MODE_HOST;
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue