[linux-yocto] [PATCH 15/65] usb: add owl usb driver
Jiang Lu
lu.jiang at windriver.com
Wed Dec 21 01:16:16 PST 2016
From: wurui <wurui at actions-semi.com>
commit 5b2ea66f1539600f19ffc54bb9ea170bc4634c58 from
https://github.com/xapp-le/kernel.git
Change-Id: I963b06334ef94324ccde58f1238d15b033417e6e
---
drivers/hid/hid-magicmouse.c | 3 +-
drivers/hid/hid-ntrig.c | 6 +-
drivers/usb/Kconfig | 1 +
drivers/usb/Makefile | 2 +
drivers/usb/dwc3/Kconfig | 9 +
drivers/usb/dwc3/Makefile | 1 +
drivers/usb/dwc3/core.c | 455 ++-
drivers/usb/dwc3/core.h | 5 +
drivers/usb/dwc3/dwc3-actions.c | 516 +++
drivers/usb/dwc3/ep0.c | 31 +-
drivers/usb/dwc3/gadget.c | 155 +-
drivers/usb/dwc3/gadget.h | 14 +
drivers/usb/dwc3/hotplug_handle.c | 237 ++
drivers/usb/dwc3/irqs.h | 127 +
drivers/usb/dwc3/usb3_regs.h | 136 +
drivers/usb/gadget/Kconfig | 13 +
drivers/usb/gadget/composite.c | 11 +-
drivers/usb/gadget/function/f_mass_storage.c | 16 +-
drivers/usb/gadget/function/storage_common.c | 18 +
drivers/usb/gadget/legacy/Makefile | 3 +
drivers/usb/gadget/legacy/adfuserver.c | 4987 ++++++++++++++++++++++++++
drivers/usb/gadget/legacy/adfuserver.h | 85 +
drivers/usb/gadget/usbstring.c | 112 +-
drivers/usb/host/Kconfig | 7 +
drivers/usb/host/Makefile | 5 +-
drivers/usb/host/aotg_debug.c | 985 +++++
drivers/usb/host/aotg_debug.h | 88 +
drivers/usb/host/aotg_hcd.c | 4168 +++++++++++++++++++++
drivers/usb/host/aotg_hcd.h | 467 +++
drivers/usb/host/aotg_mon.c | 386 ++
drivers/usb/host/aotg_mon.h | 11 +
drivers/usb/host/aotg_plat_data.h | 22 +
drivers/usb/host/aotg_regs.h | 1527 ++++++++
drivers/usb/host/aotg_ring.c | 1509 ++++++++
drivers/usb/host/aotg_ring.h | 48 +
drivers/usb/host/uhost_hotplug_handle.c | 34 +
drivers/usb/host/xhci.c | 71 +
drivers/usb/host/xhci_ss_phy_setting.c | 131 +
drivers/usb/host/xhci_ss_retry_mode.c | 224 ++
drivers/usb/host/xhci_usb3_regs.h | 79 +
drivers/usb/monitor/Kconfig | 23 +
drivers/usb/monitor/Makefile | 10 +
drivers/usb/monitor/aotg_regs.h | 162 +
drivers/usb/monitor/umonitor_api.c | 1341 +++++++
drivers/usb/monitor/umonitor_config.h | 108 +
drivers/usb/monitor/umonitor_core.c | 1016 ++++++
drivers/usb/monitor/umonitor_core.h | 130 +
drivers/usb/monitor/umonitor_hal.c | 534 +++
drivers/usb/monitor/umonitor_hal.h | 108 +
drivers/usb/serial/option.c | 272 +-
drivers/usb/storage/usb.c | 33 +
51 files changed, 20378 insertions(+), 64 deletions(-)
mode change 100644 => 100755 drivers/hid/hid-magicmouse.c
mode change 100644 => 100755 drivers/hid/hid-ntrig.c
mode change 100644 => 100755 drivers/usb/Kconfig
mode change 100644 => 100755 drivers/usb/Makefile
mode change 100644 => 100755 drivers/usb/dwc3/Kconfig
mode change 100644 => 100755 drivers/usb/dwc3/Makefile
mode change 100644 => 100755 drivers/usb/dwc3/core.c
mode change 100644 => 100755 drivers/usb/dwc3/core.h
create mode 100644 drivers/usb/dwc3/dwc3-actions.c
mode change 100644 => 100755 drivers/usb/dwc3/ep0.c
mode change 100644 => 100755 drivers/usb/dwc3/gadget.c
mode change 100644 => 100755 drivers/usb/dwc3/gadget.h
create mode 100644 drivers/usb/dwc3/hotplug_handle.c
create mode 100644 drivers/usb/dwc3/irqs.h
create mode 100644 drivers/usb/dwc3/usb3_regs.h
mode change 100644 => 100755 drivers/usb/gadget/Kconfig
mode change 100644 => 100755 drivers/usb/gadget/composite.c
mode change 100644 => 100755 drivers/usb/gadget/function/f_mass_storage.c
mode change 100644 => 100755 drivers/usb/gadget/function/storage_common.c
mode change 100644 => 100755 drivers/usb/gadget/legacy/Makefile
create mode 100644 drivers/usb/gadget/legacy/adfuserver.c
create mode 100644 drivers/usb/gadget/legacy/adfuserver.h
mode change 100644 => 100755 drivers/usb/gadget/usbstring.c
mode change 100644 => 100755 drivers/usb/host/Kconfig
mode change 100644 => 100755 drivers/usb/host/Makefile
create mode 100644 drivers/usb/host/aotg_debug.c
create mode 100644 drivers/usb/host/aotg_debug.h
create mode 100644 drivers/usb/host/aotg_hcd.c
create mode 100644 drivers/usb/host/aotg_hcd.h
create mode 100644 drivers/usb/host/aotg_mon.c
create mode 100644 drivers/usb/host/aotg_mon.h
create mode 100644 drivers/usb/host/aotg_plat_data.h
create mode 100644 drivers/usb/host/aotg_regs.h
create mode 100644 drivers/usb/host/aotg_ring.c
create mode 100644 drivers/usb/host/aotg_ring.h
create mode 100644 drivers/usb/host/uhost_hotplug_handle.c
mode change 100644 => 100755 drivers/usb/host/xhci.c
create mode 100644 drivers/usb/host/xhci_ss_phy_setting.c
create mode 100644 drivers/usb/host/xhci_ss_retry_mode.c
create mode 100644 drivers/usb/host/xhci_usb3_regs.h
create mode 100644 drivers/usb/monitor/Kconfig
create mode 100644 drivers/usb/monitor/Makefile
create mode 100644 drivers/usb/monitor/aotg_regs.h
create mode 100644 drivers/usb/monitor/umonitor_api.c
create mode 100644 drivers/usb/monitor/umonitor_config.h
create mode 100644 drivers/usb/monitor/umonitor_core.c
create mode 100644 drivers/usb/monitor/umonitor_core.h
create mode 100644 drivers/usb/monitor/umonitor_hal.c
create mode 100644 drivers/usb/monitor/umonitor_hal.h
mode change 100644 => 100755 drivers/usb/serial/option.c
mode change 100644 => 100755 drivers/usb/storage/usb.c
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
old mode 100644
new mode 100755
index 29a74c1..a3c5dad
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -471,7 +471,7 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
return 0;
}
-static void magicmouse_input_configured(struct hid_device *hdev,
+static int magicmouse_input_configured(struct hid_device *hdev,
struct hid_input *hi)
{
@@ -483,6 +483,7 @@ static void magicmouse_input_configured(struct hid_device *hdev,
/* clean msc->input to notify probe() of the failure */
msc->input = NULL;
}
+ return ret;
}
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
old mode 100644
new mode 100755
index 600f207..756d1ef
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -859,14 +859,14 @@ not_claimed_input:
return 1;
}
-static void ntrig_input_configured(struct hid_device *hid,
+static int ntrig_input_configured(struct hid_device *hid,
struct hid_input *hidinput)
{
struct input_dev *input = hidinput->input;
if (hidinput->report->maxfield < 1)
- return;
+ return 0;
switch (hidinput->report->field[0]->application) {
case HID_DG_PEN:
@@ -890,6 +890,8 @@ static void ntrig_input_configured(struct hid_device *hid,
"N-Trig MultiTouch";
break;
}
+
+ return 0;
}
static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
old mode 100644
new mode 100755
index 8ed451d..1074941
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -80,6 +80,7 @@ source "drivers/usb/core/Kconfig"
source "drivers/usb/mon/Kconfig"
+source "drivers/usb/monitor/Kconfig"
source "drivers/usb/wusbcore/Kconfig"
source "drivers/usb/host/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
old mode 100644
new mode 100755
index d8926c6..059faed
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_MON) += mon/
+obj-$(CONFIG_USB_ACTIONS_MON) += monitor/
+
obj-$(CONFIG_PCI) += host/
obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_ISP116X_HCD) += host/
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
old mode 100644
new mode 100755
index 473bfaa..66b6c68
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -96,6 +96,15 @@ config USB_DWC3_ST
inside (i.e. STiH407).
Say 'Y' or 'M' if you have one such device.
+config USB_DWC3_ACT
+ tristate "Actions S500 Platforms"
+ depends on ARCH_OWL && OF
+ default USB_DWC3
+ help
+ Actions S500 SoCs with one DesignWare Core USB3 IP
+ inside
+ Say 'Y' or 'M' if you have one such device.
+
config USB_DWC3_QCOM
tristate "Qualcomm Platforms"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
old mode 100644
new mode 100755
index c7076e3..20b6a87
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -35,6 +35,7 @@ endif
# and allyesconfig builds.
##
+obj-$(CONFIG_USB_DWC3_ACT) += dwc3-actions.o
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o
obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
old mode 100644
new mode 100755
index 1f79708..3136835
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -39,15 +39,111 @@
#include <linux/usb/gadget.h>
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
+#include <mach/hardware.h>
+#include <mach/powergate.h>
#include "platform_data.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
+#include "usb3_regs.h"
#include "debug.h"
+static char *maximum_speed = "high";
+module_param(maximum_speed, charp, 0);
+MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
+static int dwc3_slew_rate =-1;
+module_param(dwc3_slew_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dwc3_slew_rate, "dwc3_slew_rate");
+static int dwc3_tx_bias=-1;
+module_param(dwc3_tx_bias, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dwc3_tx_bias, "dwc3_tx_bias");
/* -------------------------------------------------------------------------- */
+#define DWC3_DEVS_POSSIBLE 32
+struct dwc3_port_info {
+ void __iomem *usbecs;
+ void __iomem *devrst;
+ void __iomem *usbpll;
+};
+struct dwc3_actions {
+ struct platform_device *dwc3;
+ struct device *dev;
+
+ struct dwc3_port_info port_info;
+ void __iomem *base;
+ int ic_type;
+};
+enum{
+ IC_ATM7039C = 0,
+ IC_ATM7059A
+};
+static int g_ic_type = IC_ATM7039C;
+
+static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE);
+
+#if SUPPORT_NOT_RMMOD_USBDRV
+static struct platform_device *pdev_dwc;
+extern int __dwc3_set_plugstate(struct dwc3 *dwc,int s);
+int dwc3_set_plugstate(int s)
+{
+ struct dwc3 *dwc;
+
+ if(pdev_dwc ==NULL){
+ printk("------can't get dwc3 platform device (structure)!!---\n");
+ return -ENODEV;
+ }
+
+ dwc = platform_get_drvdata(pdev_dwc);
+ __dwc3_set_plugstate(dwc,s);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dwc3_set_plugstate);
+
+void (*dwc3_clk_open)(void );
+void (*dwc3_clk_close)(void );
+ void dwc3_set_usb_clk_ops(void (*clk_open)(void ),void (*clk_close)(void ))
+{
+ dwc3_clk_open = clk_open;
+ dwc3_clk_close = clk_close;
+}
+EXPORT_SYMBOL_GPL(dwc3_set_usb_clk_ops);
+#endif
+
+int dwc3_get_device_id(void)
+{
+ int id;
+
+again:
+ id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE);
+ if (id < DWC3_DEVS_POSSIBLE) {
+ int old;
+
+ old = test_and_set_bit(id, dwc3_devs);
+ if (old)
+ goto again;
+ } else {
+ pr_err("dwc3: no space for new device\n");
+ id = -ENOMEM;
+ }
+
+ return id;
+}
+EXPORT_SYMBOL_GPL(dwc3_get_device_id);
+
+void dwc3_put_device_id(int id)
+{
+ int ret;
+
+ if (id < 0)
+ return;
+
+ ret = test_bit(id, dwc3_devs);
+ WARN(!ret, "dwc3: ID %d not in use\n", id);
+ smp_mb__before_atomic();
+ clear_bit(id, dwc3_devs);
+}
+EXPORT_SYMBOL_GPL(dwc3_put_device_id);
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
@@ -63,7 +159,7 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
* @dwc: pointer to our context structure
*/
-static int dwc3_core_soft_reset(struct dwc3 *dwc)
+static int dwc3_core_soft_reset(struct dwc3 *dwc,int phy_reset_en)
{
u32 reg;
int ret;
@@ -73,40 +169,55 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
- /* Assert USB3 PHY reset */
- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
- reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-
- /* Assert USB2 PHY reset */
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
- reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ if(phy_reset_en){
+ /* Assert USB3 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ /* Assert USB2 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ if(g_ic_type == IC_ATM7059A){
+ /* port 1 */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(1));
+ reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(1), reg);
+ }
- usb_phy_init(dwc->usb2_phy);
- usb_phy_init(dwc->usb3_phy);
- ret = phy_init(dwc->usb2_generic_phy);
- if (ret < 0)
- return ret;
+ usb_phy_init(dwc->usb2_phy);
+ usb_phy_init(dwc->usb3_phy);
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ return ret;
- ret = phy_init(dwc->usb3_generic_phy);
- if (ret < 0) {
- phy_exit(dwc->usb2_generic_phy);
- return ret;
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0) {
+ phy_exit(dwc->usb2_generic_phy);
+ return ret;
+ }
+ mdelay(100);
+
+ /* Clear USB3 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ /* Clear USB2 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ if(g_ic_type == IC_ATM7059A){
+ /* port 1 */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(1));
+ reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(1), reg);
+ }
+ mdelay(100);
}
- mdelay(100);
-
- /* Clear USB3 PHY reset */
- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
- reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-
- /* Clear USB2 PHY reset */
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
- reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-
- mdelay(100);
/* After PHYs are stable we can take Core out of reset state */
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
@@ -264,7 +375,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
*
* Returns 0 on success otherwise negative errno.
*/
-static int dwc3_event_buffers_setup(struct dwc3 *dwc)
+int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
int n;
@@ -417,6 +528,208 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
}
+static void setphy(unsigned char reg_add, unsigned char value, unsigned char port_num)
+{
+ void __iomem *usb3_usb_vcon= NULL;
+ volatile unsigned char addr_low;
+ volatile unsigned char addr_high;
+ volatile unsigned int vstate;
+
+ if(g_ic_type == IC_ATM7059A){
+ if (port_num == 0)
+ usb3_usb_vcon = (void __iomem *)IO_ADDRESS((0xB0400000 + 0xCe00));
+ else if (port_num == 1)
+ usb3_usb_vcon = (void __iomem *)IO_ADDRESS((0xB0400000 + 0xCe10));
+ else {
+ printk("port_num must is 0 or 1!!\n");
+ return;
+ }
+ }
+ else if(g_ic_type == IC_ATM7039C){
+ usb3_usb_vcon = (void __iomem *)IO_ADDRESS(USB3_USB2_P0_VDCTRL);
+ }
+ addr_low = reg_add & 0x0f;
+ addr_high = (reg_add >> 4) & 0x0f;
+
+ vstate = value;
+ vstate = vstate << 8;
+
+ addr_low |= 0x10;
+ writel(vstate | addr_low, usb3_usb_vcon);
+ mb();
+
+ addr_low &= 0x0f;
+ writel(vstate | addr_low, usb3_usb_vcon);
+ mb();
+
+ addr_low |= 0x10;
+ writel(vstate | addr_low, usb3_usb_vcon);
+ mb();
+
+ addr_high |= 0x10;
+ writel(vstate | addr_high, usb3_usb_vcon);
+ mb();
+
+ addr_high &= 0x0f;
+ writel(vstate | addr_high, usb3_usb_vcon);
+ mb();
+
+ addr_high |= 0x10;
+ writel(vstate | addr_high, usb3_usb_vcon);
+ mb();
+ return;
+}
+#define USB3_UMON_FDT_COMPATIBLE_ATM7039C "actions,atm7039c-usb"
+#define USB3_UMON_FDT_COMPATIBLE_ATM7059TC "actions,atm7059tc-usb"
+#define USB3_UMON_FDT_COMPATIBLE_ATM7059A "actions,atm7059a-usb"
+static int dwc3_get_slewrate_config(void)
+{
+ struct device_node *fdt_node;
+ const __be32 *property;
+ int value;
+
+ fdt_node = of_find_compatible_node(NULL, NULL, USB3_UMON_FDT_COMPATIBLE_ATM7039C);
+ if (NULL == fdt_node) {
+ fdt_node = of_find_compatible_node(NULL, NULL, USB3_UMON_FDT_COMPATIBLE_ATM7059TC);
+ if (NULL == fdt_node)
+ fdt_node = of_find_compatible_node(NULL, NULL, USB3_UMON_FDT_COMPATIBLE_ATM7059A);
+ if (NULL == fdt_node)
+ {
+ printk("<dwc3>err: no usb3-fdt-compatible\n");
+ return -EINVAL;
+ }
+ }
+ property = of_get_property(fdt_node, "usb_hs_output_strength", NULL);
+ value = be32_to_cpup(property);
+ return value;
+}
+void dwc3_phy_init(u8 mode, unsigned char port_num)
+{
+ unsigned char val_u8,slew_rate;
+
+ slew_rate= dwc3_get_slewrate_config();
+ if((port_num!= 0)&&(port_num!= 1)){
+ port_num = 0;
+ }
+ if(g_ic_type == IC_ATM7039C){
+ setphy(0xe7,0x0b, port_num);
+ udelay(100);
+ setphy(0xe7,0x0f, port_num);
+ udelay(100);
+ setphy(0xe2,0x74, port_num);
+ udelay(100);
+ }
+ else if(g_ic_type == IC_ATM7059A){
+
+ if(mode == USB_DR_MODE_PERIPHERAL) {
+ printk(" GS705A phy init for dwc3 gadget\n");
+ val_u8 =(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0);//select page1
+ setphy(0xf4, val_u8, port_num);
+ val_u8 =(1<<5) |(1<<4)|(0<<3)|(1<<2)|(1<<0);//negative sample
+ setphy(0xe0, val_u8, port_num);
+
+ val_u8 =(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0);//select page1
+ setphy(0xf4, val_u8, port_num);
+ val_u8 =(slew_rate<<5) |(0<<4)|(1<<3)|(1<<2)|(3<<0);//slewRate
+ setphy(0xe1, val_u8, port_num);
+
+ val_u8 =(1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0);//bit[6:5]=select page0
+ setphy(0xf4, val_u8, port_num);
+ val_u8 =(1<<7) |(4<<4)|(1<<3)|(0<<2)|(3<<0); //bit[3]= Enablepowerdown mode
+ setphy(0xe6, val_u8, port_num);
+
+ val_u8 = (1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0);
+ setphy(0xf4, val_u8, port_num);
+ val_u8 = (7<<4)|(0<<1)|(1<<0); //sensitivity lower
+ setphy(0xe7, val_u8, port_num);
+
+ val_u8 = (1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0);
+ setphy(0xf4, val_u8, port_num);
+ val_u8 = (9<<4)|(7<<0); //hstx current lower
+ setphy(0xe4, val_u8, port_num);
+ }
+ else {
+ printk(" GS705A phy init for xhci\n");
+ val_u8 =(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0);//select page1
+ setphy(0xf4, val_u8, port_num);
+ val_u8 =(1<<5) |(1<<4)|(0<<3)|(1<<2)|(1<<0);//negative sample
+ setphy(0xe0, val_u8, port_num);
+
+ val_u8 =(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0);//select page1
+ setphy(0xf4, val_u8, port_num);
+ if((dwc3_slew_rate >=0) &&(dwc3_slew_rate <= 7))
+ val_u8 =(dwc3_slew_rate<<5) |(0<<4)|(1<<3)|(1<<2)|(3<<0);//slewRate
+ else
+ val_u8 =(3<<5) |(0<<4)|(1<<3)|(1<<2)|(3<<0);//slewRate
+ setphy(0xe1, val_u8, port_num);
+
+ val_u8 =(1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0);//bit[6:5]=select page0
+ setphy(0xf4, val_u8, port_num);
+ val_u8 =(1<<7) |(4<<4)|(1<<3)|(0<<2)|(3<<0); //bit[3]= Enablepowerdown mode
+ setphy(0xe6, val_u8, port_num);
+
+ val_u8 = (1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0);
+ setphy(0xf4, val_u8, port_num);
+ val_u8 = (9<<4)|(0<<1)|(1<<0); //sensitivity lower
+ setphy(0xe7, val_u8, port_num);
+
+ val_u8 =(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0);//select page1
+ setphy(0xf4, val_u8, port_num);
+ val_u8 =(1<<5) |(1<<4)|(0<<3)|(0<<2)|(1<<0);// REG_CAL=0
+ setphy(0xe0, val_u8, port_num);
+
+ val_u8 = (1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0); // elect page0
+ setphy(0xf4, val_u8, port_num);
+ if((dwc3_tx_bias >=0) &&(dwc3_tx_bias <= 15))
+ val_u8 = (0xf<<4)|(dwc3_tx_bias<<0); //adjust hshd threshold and hstx current
+ else
+ val_u8 = (0xf<<4)|(4<<0); //adjust hshd threshold and hstx current
+ setphy(0xe4, val_u8, port_num);
+
+ val_u8 = (1<<7) |(1<<6) |(1<<5)|(1<<4)|(1<<3)|(1<<2)|(0<<1)|(0<<0);
+ setphy(0xf0, val_u8, port_num); //disconnect enable
+ }
+
+ }
+
+ return;
+}
+EXPORT_SYMBOL_GPL(dwc3_phy_init);
+
+/*
+ *fix bug:when usb3 bias enable ,reset machine will leak current by gpio
+ *if call this func will also disable super speed.
+ */
+void disable_bias(void)
+{
+ struct dwc3 *dwc;
+ u32 reg;
+
+ dwc = platform_get_drvdata(pdev_dwc);
+ reg = dwc3_readl(dwc->regs, 0xce04);
+ reg |=(1<<27);
+ dwc3_writel(dwc->regs, 0xce04, reg);
+ reg = dwc3_readl(dwc->regs, ANA0F);
+ reg &=~(1<<14);
+ dwc3_writel(dwc->regs, ANA0F, reg);
+
+}
+EXPORT_SYMBOL_GPL(disable_bias);
+
+void enable_bias(void)
+{
+ struct dwc3 *dwc;
+ u32 reg;
+
+ dwc = platform_get_drvdata(pdev_dwc);
+
+ reg = dwc3_readl(dwc->regs, ANA0F);
+ reg |=(1<<14);
+ dwc3_writel(dwc->regs, ANA0F, reg);
+
+}
+EXPORT_SYMBOL_GPL(enable_bias);
+
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -425,7 +738,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
* initialized. The PHY interfaces and the PHYs get initialized together with
* the core in dwc3_core_init.
*/
-static int dwc3_phy_setup(struct dwc3 *dwc)
+int dwc3_phy_setup(struct dwc3 *dwc)
{
u32 reg;
int ret;
@@ -530,7 +843,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
*
* Returns 0 on success otherwise negative errno.
*/
-static int dwc3_core_init(struct dwc3 *dwc)
+int dwc3_core_init(struct dwc3 *dwc,int phy_reset_en)
{
u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg;
@@ -569,9 +882,50 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (ret)
goto err0;
- ret = dwc3_core_soft_reset(dwc);
- if (ret)
- goto err0;
+ if(g_ic_type == IC_ATM7059A){
+ dwc3_writel(dwc->regs, ANA02, 0x6046);
+ dwc3_writel(dwc->regs, ANA0E, 0x2010);
+ dwc3_writel(dwc->regs, ANA0F, 0x8000);
+ dwc3_writel(dwc->regs, REV1, 0x0);
+ dwc3_writel(dwc->regs, PAGE1_REG02, 0x0013);
+ dwc3_writel(dwc->regs, PAGE1_REG06, 0x0004);
+ dwc3_writel(dwc->regs, PAGE1_REG07, 0x22ed);
+ dwc3_writel(dwc->regs, PAGE1_REG08, 0xf802);
+ dwc3_writel(dwc->regs, PAGE1_REG09, 0x3080);
+ dwc3_writel(dwc->regs, PAGE1_REG0B, 0x2030);
+ dwc3_writel(dwc->regs, ANA0F, (1<<14));
+
+ ret = dwc3_core_soft_reset(dwc,phy_reset_en);
+ if (ret)
+ goto err0;
+
+ dwc3_cache_hwparams(dwc);
+ //====force to high speed====
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+ reg |= DWC3_DCFG_HIGHSPEED;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+ }
+ else if(g_ic_type == IC_ATM7039C){
+ /*
+ * donot need set this DWC3_BACKDOOR reg,
+ * this may cause some masstorge device transfer error!!,
+ * add by hwliu 2013.07.22 .
+ */
+ ret = dwc3_core_soft_reset(dwc,phy_reset_en);
+ if (ret)
+ goto err0;
+
+ reg = dwc3_readl(dwc->regs, DWC3_BACKDOOR);
+ reg &= ~DWC3_FLADJ_30MHZ_MASK;
+ reg |= DWC3_FLADJ_30MHZ(0x20);
+ dwc3_writel(dwc->regs, DWC3_BACKDOOR, reg);
+ }
+ else {
+ ret = dwc3_core_soft_reset(dwc, 0);
+ if (ret)
+ goto err0;
+ }
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
@@ -822,6 +1176,10 @@ static int dwc3_probe(struct platform_device *pdev)
void __iomem *regs;
void *mem;
+#if SUPPORT_NOT_RMMOD_USBDRV
+ pdev_dwc = pdev;
+#endif
+
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem)
return -ENOMEM;
@@ -830,6 +1188,14 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->mem = mem;
dwc->dev = dev;
+ //to get ic type from dwc3-actions.ko,use resource method
+ res = platform_get_resource(pdev, IORESOURCE_REG, 0);
+ if (!res) {
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
+ }
+ g_ic_type = res->flags&0xff;
+
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
@@ -982,6 +1348,8 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret)
goto err0;
+ owl_powergate_power_on(OWL_POWERGATE_USB3);
+
spin_lock_init(&dwc->lock);
if (!dev->dma_mask) {
@@ -1009,7 +1377,16 @@ static int dwc3_probe(struct platform_device *pdev)
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
dwc->dr_mode = USB_DR_MODE_OTG;
- ret = dwc3_core_init(dwc);
+ dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+ if(g_ic_type == IC_ATM7039C){
+ dwc3_phy_init(dwc->dr_mode, 0);
+ }
+ else if(g_ic_type == IC_ATM7059A){
+ dwc3_phy_init(dwc->dr_mode, 0);
+ dwc3_phy_init(dwc->dr_mode, 1);
+ }
+
+ ret = dwc3_core_init(dwc,0);
if (ret) {
dev_err(dev, "failed to initialize core\n");
goto err1;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
old mode 100644
new mode 100755
index 78be201..0068cac
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -149,6 +149,11 @@
#define DWC3_OEVTEN 0xcc0C
#define DWC3_OSTS 0xcc10
+#define DWC3_BACKDOOR 0xcd4c
+
+#define DWC3_FLADJ_30MHZ_MASK ((0x3f) << 10)
+#define DWC3_FLADJ_30MHZ(n) ((n) << 10)
+
/* Bit fields */
/* Global Configuration Register */
diff --git a/drivers/usb/dwc3/dwc3-actions.c b/drivers/usb/dwc3/dwc3-actions.c
new file mode 100644
index 0000000..86b0432
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-actions.c
@@ -0,0 +1,516 @@
+/**
+ * dwc3-actions.c - actions-semi DWC3 Specific Glue layer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+
+#include "core.h"
+#include "usb3_regs.h"
+
+#define ADFUS_PROC
+static struct resource dwc3_resources[3];
+static u64 dwc3_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device *pdev_dwc_actions;
+extern void dwc3_set_usb_clk_ops(void (*clk_open)(void ),void (*clk_close)(void ));
+
+#ifdef ADFUS_PROC
+
+#define ADFUS_PROC_FILE_LEN 64
+
+enum probatch_status {
+ PROBATCH_START = 0,
+ PROBATCH_INSTAL_FLASH,
+ PROBATCH_FINISH_INSTALL_FLASH,
+ PROBATCH_WRITE_PHY,
+ PROBATCH_FINISH_WRITE_PHY,
+ PROBATCH_FORMAT,
+ PROBATCH_FINISH_FORMAT,
+ PROBATCH_FINISH,
+ PROBATCH_FINISH_OK,
+};
+#endif
+
+enum{
+ IC_ATM7039C = 0,
+ IC_ATM7059A
+};
+
+struct dwc3_port_info {
+ void __iomem *usbecs;
+ void __iomem *devrst;
+ void __iomem *usbpll;
+};
+
+struct dwc3_actions {
+ struct platform_device *dwc3;
+ struct device *dev;
+
+ struct dwc3_port_info port_info;
+ void __iomem *base;
+ int ic_type;
+};
+int dwc3_get_device_id(void);
+void dwc3_put_device_id(int id);
+
+//static void dwc3_clk_init(struct dwc3_actions *dwc3_owl)
+static void dwc3_clk_init(void)
+{
+ u32 reg;
+ struct dwc3_actions *dwc3_owl;
+ struct dwc3_port_info *port_info ;
+
+ if(pdev_dwc_actions ==NULL){
+ printk("------can't get dwc3-actions platform device structure!!---\n");
+ return ;
+ }
+ dwc3_owl = platform_get_drvdata(pdev_dwc_actions);
+ port_info = &dwc3_owl->port_info;
+ printk("\n------------dwc3_clk_init-----ic=%d-----\n",dwc3_owl->ic_type);
+ /*USB3 PLL enable*/
+ reg = readl(port_info->usbpll);
+ if(dwc3_owl->ic_type == IC_ATM7059A){
+ reg |= (0x7f);
+ }
+ else if(dwc3_owl->ic_type == IC_ATM7039C){
+ reg |= (0x1f);
+ }
+ writel(reg, port_info->usbpll);
+
+ udelay(1000);
+
+ /*USB3 Cmu Reset */
+ reg = readl(port_info->devrst);
+ reg &= ~(USB3_MOD_RST);
+ writel(reg, port_info->devrst);
+
+ udelay(100);
+
+ reg = readl(port_info->devrst);
+ reg |= (USB3_MOD_RST);
+ writel(reg, port_info->devrst);
+
+ udelay(100);
+
+ if(dwc3_owl->ic_type == IC_ATM7059A){
+ reg = readl(dwc3_owl->base + DWC3_CMU_DEBUG_LDO);
+ reg |= CMU_BIAS_EN;
+ writel(reg, dwc3_owl->base + DWC3_CMU_DEBUG_LDO);
+ reg = readl(port_info->usbecs );
+ reg |= (1 << USB3_P0_CTL_PLLLDOEN_IC1 )|(/*2*/3 << USB3_P0_CTL_LDOVREFSEL_SHIFT_IC1);
+ writel(reg, port_info->usbecs );
+ }
+ else if(dwc3_owl->ic_type == IC_ATM7039C){
+ /*PLL1 enable*/
+ reg = readl(dwc3_owl->base + DWC3_CMU_DEBUG_LDO);
+ reg |= CMU_BIAS_EN;
+ writel(reg, dwc3_owl->base + DWC3_CMU_DEBUG_LDO);
+
+ /*PLL2 enable*/
+ reg = (BIST_QINIT(0x3) | EYE_HEIGHT(0x4) | PLL2_LOCK | PLL2_RS(0x2) |
+ PLL2_ICP(0x1) | CMU_SEL_PREDIV | CMU_DIVX2 | PLL2_DIV(0x17) |
+ PLL2_POSTDIV(0x3) | PLL2_PU);
+ writel(reg, dwc3_owl->base + DWC3_CMU_PLL2_BISTDEBUG);
+ reg = readl(port_info->usbecs );
+ reg |= (1 << USB3_P0_CTL_PLLLDOEN )|(2 << USB3_P0_CTL_LDOVREFSEL_SHIFT);
+ writel(reg, port_info->usbecs );
+ }
+
+ udelay(100);
+ reg = readl(port_info->usbecs);
+ reg &= ~((0x1 << USB3_P0_CTL_DPPUEN_P0)|(0x1 << USB3_P0_CTL_DMPUEN_P0));
+ writel(reg, port_info->usbecs );
+
+ udelay(1000);
+ return;
+}
+
+//static void dwc3_clk_exit(struct dwc3_actions *dwc3_owl)
+static void dwc3_clk_exit(void)
+{
+ u32 reg;
+ struct dwc3_actions *dwc3_owl;
+ struct dwc3_port_info *port_info ;
+
+ if(pdev_dwc_actions ==NULL){
+ printk("------can't get dwc3-actions platform device structure!!---\n");
+ return ;
+ }
+ dwc3_owl = platform_get_drvdata(pdev_dwc_actions);
+ port_info = &dwc3_owl->port_info;
+
+ printk("\n------------dwc3_clk_exit----------\n");
+ /*USB3 PLL disable*/
+ reg = readl(port_info->usbpll);
+
+ if(dwc3_owl->ic_type == IC_ATM7059A){
+ reg &= ~(0x7f);
+ }
+ else if(dwc3_owl->ic_type == IC_ATM7039C){
+ reg &= ~(0x1f);
+ }
+ writel(reg, port_info->usbpll);
+}
+
+/*---------------------------------------------------------------------------
+ * proc file entry for debug
+ *---------------------------------------------------------------------------*/
+#ifdef ADFUS_PROC
+static struct proc_dir_entry *adfus_proc_entry;
+char adfus_proc_path[] = "adfus_proc";
+
+char probatch_phase[ADFUS_PROC_FILE_LEN];
+
+char all_probatch_phase[][ADFUS_PROC_FILE_LEN]=
+{
+ "null",
+ "install_flash",
+ "finish_install_flash",
+ "write_phy",
+ "finish_write_phy",
+ "format",
+ "finish_format",
+ "finish",
+ "finish_ok",
+};
+
+int set_probatch_phase(int id)
+{
+
+ strcpy(probatch_phase, all_probatch_phase[id]);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(set_probatch_phase);
+
+int is_probatch_phase(int id)
+{
+ int ret;
+
+ ret = memcmp(probatch_phase, all_probatch_phase[id], strlen(all_probatch_phase[id]));
+ return ret;
+}
+EXPORT_SYMBOL_GPL(is_probatch_phase);
+
+static ssize_t adfus_proc_read(struct file *file, char __user *buffer,
+ size_t count, loff_t * offset)
+{
+ int len;
+
+ if(*offset > 0)
+ return 0;
+
+ len = strlen(probatch_phase);
+ if(len > count)
+ len = count;
+
+ if(copy_to_user(buffer, probatch_phase, len))
+ return -EFAULT;
+
+ *offset += len;
+ return len;
+}
+
+static ssize_t adfus_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t * offset)
+{
+ int len;
+
+ if(*offset > 0)
+ return 0;
+ if(count > ADFUS_PROC_FILE_LEN)
+ len = ADFUS_PROC_FILE_LEN;
+ else
+ len = count;
+
+ if (copy_from_user(probatch_phase, buffer, len ))
+ return -EFAULT;
+
+ probatch_phase[len]=0;
+
+ *offset += len;
+ return len;
+}
+
+static const struct file_operations __adfus_proc_file_operations =
+{
+ .owner = THIS_MODULE,
+ .read = adfus_proc_read,
+ .write = adfus_proc_write,
+};
+#endif
+
+
+
+static struct dwc3_actions atm7039c_data = {
+ .ic_type = IC_ATM7039C,
+
+};
+
+static struct dwc3_actions atm7059a_data = {
+ .ic_type = IC_ATM7059A,
+};
+
+static const struct of_device_id owl_dwc3_actions_of_match[] = {
+ {.compatible = "actions,atm7039c-usb", .data = &atm7039c_data},
+ {.compatible = "actions,atm7059tc-usb", .data = &atm7059a_data },
+ {.compatible = "actions,atm7059a-usb", .data = &atm7059a_data },
+ {}
+
+};
+MODULE_DEVICE_TABLE(of, owl_dwc3_actions_of_match);
+
+static int dwc3_actions_probe(struct platform_device *pdev)
+{
+ struct platform_device *dwc3;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct dwc3_actions *dwc3_owl;
+ const struct of_device_id *id;
+ void __iomem *base;
+ int devid = 0;
+ int ret = -ENOMEM;
+
+ pdev_dwc_actions = pdev;//record this platform_device for later use
+ id = of_match_device(owl_dwc3_actions_of_match, &pdev->dev);
+ if(id ==NULL)
+ {
+ printk("<dwc3_actions>err: no config !!!\n");
+ return -EINVAL;
+ }
+ dwc3_owl =(struct dwc3_actions *) id->data;
+
+ (pdev->dev).dma_mask = &dwc3_dma_mask;
+ (pdev->dev).coherent_dma_mask = DMA_BIT_MASK(32);
+ //dwc3_5202 = devm_kzalloc(dev,sizeof(*dwc3_5202), GFP_KERNEL);
+ //if (!dwc3_5202) {
+ // dev_err(&pdev->dev, "not enough memory\n");
+ // goto err1;
+ //}
+ platform_set_drvdata(pdev, dwc3_owl);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing memory base resource\n");
+ return -EINVAL;
+ }
+ memcpy(&dwc3_resources[0], res, sizeof(*res));
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "missing IRQ base resource\n");
+ return -EINVAL;
+ }
+ memcpy(&dwc3_resources[1], res, sizeof(*res));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(dev, "missing memory base resource\n");
+ return -EINVAL;
+ }
+
+ res = devm_request_mem_region(dev, res->start,resource_size(res),
+ dev_name(dev));
+ if (!res) {
+ dev_err(dev, "can't request mem region\n");
+ return -ENOMEM;
+ }
+
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!base) {
+ dev_err(dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+
+ dwc3_owl->port_info.devrst = (void __iomem *)IO_ADDRESS(CMU_DEVRST1);
+ dwc3_owl->port_info.usbecs = (void __iomem *)IO_ADDRESS(USB3_P0_CTL);
+ dwc3_owl->port_info.usbpll = (void __iomem *)IO_ADDRESS(CMU_USBPLL);
+
+ devid = dwc3_get_device_id();
+ if (devid < 0)
+ return -ENODEV;
+
+
+ dwc3 = platform_device_alloc("dwc3", devid);
+ if (!dwc3) {
+ dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+ goto err1;
+ }
+
+ dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+ dwc3->dev.parent = &pdev->dev;
+ dwc3->dev.dma_mask = pdev->dev.dma_mask;
+ dwc3->dev.dma_parms = pdev->dev.dma_parms;
+ dwc3_owl->dwc3 = dwc3;
+ dwc3_owl->dev = &pdev->dev;
+ dwc3_owl->base = base;
+
+ dwc3_set_usb_clk_ops(dwc3_clk_init,dwc3_clk_exit);
+ dwc3_clk_init();
+ //to transfor ic type to dwc3.ko,use resource method
+ dwc3_resources[2] = dwc3_resources[1];
+ dwc3_resources[2].flags = (IORESOURCE_REG|(dwc3_owl->ic_type));
+ ret = platform_device_add_resources(dwc3, dwc3_resources, 3);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+ goto err2;
+ }
+
+ ret = platform_device_add(dwc3);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dwc3 device\n");
+ goto err2;
+ }
+#ifdef ADFUS_PROC
+ adfus_proc_entry = proc_create(adfus_proc_path, 0, NULL, &__adfus_proc_file_operations);
+ if (adfus_proc_entry) {
+ /* proc op */
+ strcpy(probatch_phase, all_probatch_phase[0]);
+ } else {
+ /* proc op */
+ printk("adfus :can not create proc file\n");
+ }
+#endif
+ return 0;
+
+err2:
+ platform_device_put(dwc3);
+ dwc3_clk_exit();
+err1:
+ dwc3_put_device_id(devid);
+ return ret;
+}
+#if 0
+#ifdef CONFIG_PM
+static int dwc3_actions_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int irq;
+ struct dwc3_actions *dwc3_owl = platform_get_drvdata(pdev);
+ irq = platform_get_irq(dwc3_owl->dwc3, 0);
+ disable_irq(irq);
+ //dwc3_clk_exit(dwc3_5202);
+
+ return 0;
+}
+
+static int dwc3_actions_resume(struct platform_device *pdev)
+{
+ int irq;
+ struct dwc3_actions *dwc3_owl = platform_get_drvdata(pdev);
+ irq = platform_get_irq(dwc3_owl->dwc3, 0);
+ //dwc3_clk_init(dwc3_owl);
+ enable_irq(irq);
+
+ return 0;
+}
+#else
+#define dwc3_actions_suspend NULL
+#define dwc3_actions_resume NULL
+#endif
+#endif
+static int dwc3_actions_remove(struct platform_device *pdev)
+{
+ struct dwc3_actions *dwc3_owl = platform_get_drvdata(pdev);
+#ifdef ADFUS_PROC
+ if (adfus_proc_entry)
+ remove_proc_entry(adfus_proc_path, NULL);
+#endif
+ dwc3_clk_exit();
+ platform_device_unregister(dwc3_owl->dwc3);
+ dwc3_put_device_id(dwc3_owl->dwc3->id);
+
+ return 0;
+}
+#if 0
+static void dwc3_actions_release(struct device * dev)
+{
+ return ;
+}
+
+
+static struct resource dwc3_resources[] = {
+ [0] = {
+ .start = USB3_REGISTER_BASE,
+ .end = USB3_REGISTER_BASE + USB3_ACTIONS_START - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = OWL_IRQ_USB3,
+ .end = OWL_IRQ_USB3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource actions_resources[] = {
+ [0] = {
+ .start = USB3_REGISTER_BASE + USB3_ACTIONS_START,
+ .end = USB3_REGISTER_BASE + USB3_ACTIONS_END,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static u64 dwc3_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dwc3_actions_device = {
+ .name = "actions-dwc3",
+ .id = 1,
+ .dev = {
+ .dma_mask = &dwc3_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .release = dwc3_actions_release,
+ },
+ .resource = actions_resources,
+ .num_resources = ARRAY_SIZE(actions_resources),
+};
+
+#endif
+static struct platform_driver dwc3_actions_driver = {
+ .probe = dwc3_actions_probe,
+ .remove = dwc3_actions_remove,
+ //.suspend = dwc3_actions_suspend,
+ //.resume = dwc3_actions_resume,
+ .driver = {
+ .name = "actions-dwc3",
+ .of_match_table = owl_dwc3_actions_of_match,
+ },
+};
+
+static int __init dwc3_actions_init(void)
+{
+ //platform_device_register(&dwc3_actions_device);
+ return platform_driver_register(&dwc3_actions_driver);
+}
+module_init(dwc3_actions_init);
+
+static void __exit dwc3_actions_exit(void)
+{
+ platform_driver_unregister(&dwc3_actions_driver);
+ //platform_device_unregister(&dwc3_actions_device);
+}
+module_exit(dwc3_actions_exit);
+
+//module_platform_driver(dwc3_actions_driver);
+
+MODULE_ALIAS("platform:actions-dwc3");
+MODULE_AUTHOR("wanlong <wanlong at actions-semi.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 actions Glue Layer");
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
old mode 100644
new mode 100755
index 00f2c45..ffd2eb3
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -104,7 +104,13 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
return 0;
}
+static int no_delay_status = 0;
+void set_no_delay_status(int flag)
+{
+ no_delay_status = flag;
+}
+EXPORT_SYMBOL(set_no_delay_status);
static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
struct dwc3_request *req)
{
@@ -153,7 +159,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
direction = !dwc->ep0_expect_in;
dwc->delayed_status = false;
usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
-
+ no_delay_status = 0;
if (dwc->ep0state == EP0_STATUS_PHASE)
__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
else
@@ -162,8 +168,11 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
return 0;
}
-
- /*
+ else {
+ if(no_delay_status == 1)
+ dev_dbg(dwc->dev, "---- dwc3_ep0_inspect_setup is behind usb_composite_setup_continue !!\n");
+ }
+ /*
* Unfortunately we have uncovered a limitation wrt the Data Phase.
*
* Section 9.4 says we can wait for the XferNotReady(DATA) event to
@@ -1062,11 +1071,19 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
dwc->ep0state = EP0_STATUS_PHASE;
if (dwc->delayed_status) {
- WARN_ON_ONCE(event->endpoint_number != 1);
- dwc3_trace(trace_dwc3_ep0, "Delayed Status");
- return;
+ //WARN_ON_ONCE(event->endpoint_number != 1);
+ //dwc3_trace(trace_dwc3_ep0, "Delayed Status");
+ //return;
+ if (no_delay_status == 0) {
+ WARN_ON_ONCE(event->endpoint_number != 1);
+ dwc3_trace(trace_dwc3_ep0, "Delayed Status");
+ return;
+ }
}
-
+ if(no_delay_status == 1) {
+ no_delay_status = 0;
+ dwc->delayed_status = false;
+ }
dwc3_ep0_do_control_status(dwc, event);
}
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
old mode 100644
new mode 100755
index a5e1b8b..59e277c
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -26,15 +26,84 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
+#include <linux/kallsyms.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <mach/bootdev.h>
#include "debug.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
+#if SUPPORT_NOT_RMMOD_USBDRV
+#include "hotplug_handle.c"
+#endif
+
+
+#ifdef USB_CHARGE_DETECT
+typedef void (*FUNC)(int);
+#define USB_CONNECT_TO_PC 1
+#define USB_CONNECT_TO_ADAPTOR 2
+
+u32 reset_interrupt_occured =0;
+struct delayed_work dwc3_work;
+FUNC dwc3_set_usb_plugin_type;
+FUNC dwc3_set_usb_plugin_type_monitor;
+extern int owl_get_boot_mode(void);
+
+static void dwc3_charging_monitor(struct work_struct *work)
+{
+ /*0: not occured, connected adaptor. 1: occured , connected pc*/
+ if(!reset_interrupt_occured) {
+ if(owl_get_boot_mode() != OWL_BOOT_MODE_UPGRADE) {
+ printk("%s %d set adaptor mode!\n", __func__, __LINE__);
+ if(dwc3_set_usb_plugin_type)
+ dwc3_set_usb_plugin_type(USB_CONNECT_TO_ADAPTOR);
+ dwc3_set_usb_plugin_type_monitor =
+ (FUNC )kallsyms_lookup_name("monitor_set_usb_plugin_type");
+ if(dwc3_set_usb_plugin_type_monitor)
+ dwc3_set_usb_plugin_type_monitor(USB_CONNECT_TO_ADAPTOR);
+ }
+ }
+}
+
+static void usb_charge_detect_init(void)
+{
+ reset_interrupt_occured = 0;
+ INIT_DELAYED_WORK(&dwc3_work, dwc3_charging_monitor);
+ dwc3_set_usb_plugin_type = (FUNC )kallsyms_lookup_name("atc260x_set_usb_plugin_type");
+}
+
+static void start_usb_status_delaywork(void)
+{
+ /*cancel the delay work & reset the interrupt counter*/
+ cancel_delayed_work_sync(&dwc3_work);
+ //reset_interrupt_occured = 0;
+ /*10s*/
+ if(owl_get_boot_mode() != OWL_BOOT_MODE_UPGRADE)
+ schedule_delayed_work(&dwc3_work, msecs_to_jiffies(15000));
+}
+
+static void set_connect_type_to_pc_mode(void)
+{
+ reset_interrupt_occured ++;
+ if(reset_interrupt_occured == 1) {
+ if(owl_get_boot_mode() != OWL_BOOT_MODE_UPGRADE) {
+ if(dwc3_set_usb_plugin_type)
+ dwc3_set_usb_plugin_type(USB_CONNECT_TO_PC);
+ dwc3_set_usb_plugin_type_monitor =
+ (FUNC )kallsyms_lookup_name("monitor_set_usb_plugin_type");
+ if(dwc3_set_usb_plugin_type_monitor)
+ dwc3_set_usb_plugin_type_monitor(USB_CONNECT_TO_PC);
+ }
+ }
+}
+
+
+#endif
+
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
@@ -1526,9 +1595,19 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
is_on = !!is_on;
spin_lock_irqsave(&dwc->lock, flags);
+#if SUPPORT_NOT_RMMOD_USBDRV
+ if(!dwc3_gadget_is_plugin()) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return 0;
+ }
+#endif
ret = dwc3_gadget_run_stop(dwc, is_on, false);
spin_unlock_irqrestore(&dwc->lock, flags);
+#ifdef USB_CHARGE_DETECT
+ start_usb_status_delaywork();
+#endif
+
return ret;
}
@@ -1816,6 +1895,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
unsigned int count;
unsigned int s_pkt = 0;
unsigned int trb_status;
+ unsigned int loop;
trace_dwc3_complete_trb(dep, trb);
@@ -1832,7 +1912,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
- if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
+ if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) {
/*
* We continue despite the error. There is not much we
* can do. If we don't clean it up we loop forever. If
@@ -1843,6 +1923,17 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
*/
dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
dep->name, trb);
+ loop = 500000; /* 500ms */
+ while(trb->ctrl & DWC3_TRB_CTRL_HWO) {
+ loop --;
+ if(loop == 0) {
+ dev_err(dwc->dev, "%s's TRB (%p) after 500000 us, still owned by HW\n",
+ dep->name, req->trb);
+ break;
+ }
+ udelay(1);
+ }
+ }
count = trb->size & DWC3_TRB_SIZE_MASK;
@@ -2234,6 +2325,34 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
}
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+ if (suspend)
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+ else
+ reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+}
+
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+ if (suspend)
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ else
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
@@ -2283,6 +2402,10 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+#ifdef USB_CHARGE_DETECT
+ set_connect_type_to_pc_mode();
+#endif
}
static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
@@ -2637,9 +2760,23 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
while (left > 0) {
union dwc3_event event;
+ u32 loop;
event.raw = *(u32 *) (evt->buf + evt->lpos);
-
+ if(event.raw==0 ){
+ loop = 500000; /* 500ms */
+ while(event.raw == 0){
+ dev_dbg(dwc->dev, "wait event sync\n");
+ loop --;
+ if(loop == 0){
+ dev_err(dwc->dev, "after wait 500ms, process event buf error\n");
+ break;
+ }
+ udelay(1);
+ event.raw = *(u32 *) (evt->buf + evt->lpos);
+ }
+ printk("\n--wait eventbuffer use %d us--new=0x%x--pos=%d--\n",500000 - loop,*(u32 *) (evt->buf + evt->lpos),evt->lpos);
+ }
dwc3_process_event_entry(dwc, &event);
/*
@@ -2651,6 +2788,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
* boundary so I worry about that once we try to handle
* that.
*/
+ *(u32 *) (evt->buf + evt->lpos) = 0;/* just to avoid bus reset bug*/
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
left -= 4;
@@ -2773,6 +2911,11 @@ int dwc3_gadget_init(struct dwc3 *dwc)
}
dwc->gadget.ops = &dwc3_gadget_ops;
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+ dwc->gadget.max_speed = USB_SPEED_SUPER,
+#else
+ dwc->gadget.max_speed = USB_SPEED_HIGH,
+#endif
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
@@ -2821,6 +2964,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err4;
}
+#ifdef USB_CHARGE_DETECT
+ usb_charge_detect_init();
+#endif
+
return 0;
err4:
@@ -2861,6 +3008,10 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
dwc->ctrl_req, dwc->ctrl_req_addr);
+
+#ifdef USB_CHARGE_DETECT
+ cancel_delayed_work_sync(&dwc3_work);
+#endif
}
int dwc3_gadget_suspend(struct dwc3 *dwc)
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
old mode 100644
new mode 100755
index 18ae3ea..09f91ff
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -56,6 +56,20 @@ struct dwc3;
/* DEPXFERCFG parameter 0 */
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
+#define SUPPORT_NOT_RMMOD_USBDRV 1
+#define USB_CHARGE_DETECT
+
+enum plugstate{
+ PLUGSTATE_A_OUT=0,
+ PLUGSTATE_B_OUT,
+ PLUGSTATE_A_IN,
+ PLUGSTATE_B_IN,
+ PLUGSTATE_A_SUSPEND,
+ PLUGSTATE_A_RESUME,
+ PLUGSTATE_B_SUSPEND,
+ PLUGSTATE_B_RESUME,
+};
+
/* -------------------------------------------------------------------------- */
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
diff --git a/drivers/usb/dwc3/hotplug_handle.c b/drivers/usb/dwc3/hotplug_handle.c
new file mode 100644
index 0000000..6ca788d
--- /dev/null
+++ b/drivers/usb/dwc3/hotplug_handle.c
@@ -0,0 +1,237 @@
+/**
+ * hotplug_handle.c - actions-semi DWC3 Specific Glue layer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/kallsyms.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <mach/hardware.h>
+#include <mach/powergate.h>
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+#if SUPPORT_NOT_RMMOD_USBDRV
+extern int dwc3_core_init(struct dwc3 *dwc,int phy_reset_en);
+extern int dwc3_event_buffers_setup(struct dwc3 *dwc);
+extern void dwc3_phy_init(u8 mode, unsigned char port_num);
+extern void (*dwc3_clk_open)(void );
+extern void (*dwc3_clk_close)(void );
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend);
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend);
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
+extern u32 reset_interrupt_occured ;
+extern void disable_bias(void);
+
+static int gadget_is_plugin =1;
+static int dwc3_gadget_is_plugin(void)
+{
+ return gadget_is_plugin;
+}
+
+
+static int dwc3_gadget_plugout(struct dwc3 *dwc,int s)
+{
+ int cnt =500;
+ int irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ gadget_is_plugin =0;
+ //--step1------Waits until the Core Idle bit in DSTS is set------
+ while(--cnt>0)
+ {
+ if(dwc3_readl(dwc->regs, DWC3_DSTS)&DWC3_DSTS_COREIDLE)
+ break;
+ udelay(100);
+ }
+ //-----step2--------stop core ------------------------------------
+ if(s==PLUGSTATE_B_OUT)
+ dwc->gadget_driver->disconnect(&dwc->gadget);
+ dwc3_gadget_run_stop(dwc, 0, 0);
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+ dwc->gadget.speed = USB_SPEED_UNKNOWN;
+
+ //-----step3--------disable ep0 ------------------------------------
+ dwc3_gadget_suspend(dwc);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ free_irq(irq, dwc);
+
+ return 0;
+}
+
+static int dwc3_gadget_plugin(struct dwc3 *dwc)
+{
+ int ret;
+ u32 reg;
+ int irq;
+ unsigned long flags;
+
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ return -EAGAIN ;
+ }
+ spin_lock_irqsave(&dwc->lock, flags);
+
+#ifdef USB_CHARGE_DETECT
+ reset_interrupt_occured = 0;/*reset this flag every time plug in */
+#endif
+ //-----step1--------do dwc3_gadget_exit() things --------------
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg |= DWC3_DCFG_LPM_CAP;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ /* Enable all but Start and End of Frame IRQs */
+ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+ DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+ DWC3_DEVTEN_USBRSTEN |
+ DWC3_DEVTEN_DISCONNEVTEN);
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+ /* Enable USB2 LPM and automatic phy suspend only on recent versions */
+ if (dwc->revision >= DWC3_REVISION_194A) {
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg |= DWC3_DCFG_LPM_CAP;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+
+ /* TODO: This should be configurable */
+ reg |= DWC3_DCTL_HIRD_THRES(28);
+
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
+ dwc3_gadget_usb3_phy_suspend(dwc, false);
+ }
+
+ //-----step2--------set core run ------------------------------------
+ dwc3_gadget_run_stop(dwc, 1, 0);
+
+ //-----step3-------enable&config ep0 -----------------------------
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ dwc3_gadget_resume(dwc);
+
+ dwc->gadget.speed = USB_SPEED_UNKNOWN;
+ gadget_is_plugin =1;
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return 0;
+}
+int dwc3_plug_out(struct dwc3 *dwc,int s)
+{
+ if(((s == PLUGSTATE_B_OUT)||(s == PLUGSTATE_B_SUSPEND))&&(dwc->gadget_driver ==NULL))
+ return 0;
+ if((s == PLUGSTATE_B_OUT)||(s == PLUGSTATE_B_SUSPEND)){
+ dwc3_gadget_plugout(dwc,s);
+ }
+
+ if(s == PLUGSTATE_A_OUT){
+ dwc3_host_exit(dwc);
+ }
+ return 0;
+}
+
+ int dwc3_plug_in(struct dwc3 *dwc,int s)
+{
+ int ret=0;
+
+
+ if((s == PLUGSTATE_B_IN)&&(dwc->gadget_driver == NULL))
+ return 0;
+
+ owl_powergate_power_on(OWL_POWERGATE_USB3);
+ ret = dwc3_core_init(dwc,1);
+ if (ret) {
+ dev_err(dwc->dev, "failed to initialize core\n");
+ return ret;
+ }
+ dwc3_event_buffers_setup(dwc);
+ dwc3_phy_init(dwc->dr_mode,0);
+ dwc3_phy_init(dwc->dr_mode,1);
+ if(s == PLUGSTATE_A_IN){
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+ ret = dwc3_host_init(dwc);
+ if (ret) {
+ return 0;
+ }
+ }
+ else if(s == PLUGSTATE_B_IN){
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ ret =dwc3_gadget_plugin(dwc);
+ disable_bias();
+ }
+ pm_runtime_disable(dwc->dev);
+ pm_runtime_set_active(dwc->dev);
+ pm_runtime_enable(dwc->dev);
+
+ return ret;
+
+}
+
+/*
+*plugstate:
+* 0: idle, nothing plugin or connect
+* 1: host, A_IN, plug in udisk via otg wire
+* 2: device, B_IN, connect to pc
+*/
+int __dwc3_set_plugstate(struct dwc3 *dwc,int s)
+{
+ if(dwc ==NULL){
+ printk("---dwc3 device (structure) not exist!!---\n");
+ return -ENODEV;
+ }
+ if((s==PLUGSTATE_A_OUT)||(s==PLUGSTATE_B_OUT)||(s==PLUGSTATE_B_SUSPEND)){
+ printk("\n----udc_set_plugstate--PLUGSTATE_OUT--\n");
+ dwc3_plug_out(dwc,s);
+ if(owl_powergate_is_powered(OWL_POWERGATE_USB3))
+ owl_powergate_power_off(OWL_POWERGATE_USB3);
+ if(dwc3_clk_close)
+ dwc3_clk_close();
+
+ }
+ else if((s==PLUGSTATE_A_IN)||(s==PLUGSTATE_B_IN)){
+ printk("\n----udc_set_plugstate--PLUGSTATE_IN-%d--\n",s);
+ if(dwc3_clk_open)
+ dwc3_clk_open();
+ dwc3_plug_in(dwc,s);
+ }
+ return 0;
+}
+
+
+#endif
+
diff --git a/drivers/usb/dwc3/irqs.h b/drivers/usb/dwc3/irqs.h
new file mode 100644
index 0000000..2aa31cb
--- /dev/null
+++ b/drivers/usb/dwc3/irqs.h
@@ -0,0 +1,127 @@
+/*
+ * arch/arm/mach-owl/include/mach/irqs.h
+ *
+ * IRQ definitions
+ *
+ * Copyright 2012 Actions Semi Inc.
+ * Author: Actions Semi, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+#define IRQ_LOCALTIMER (29)
+#define IRQ_LOCALWDT (30)
+
+#define OWL_IRQ_OFFSET (32)
+#define OWL_IRQ(x) ((x) + OWL_IRQ_OFFSET)
+
+#define OWL_IRQ_ETHERNET OWL_IRQ(0)
+#define OWL_IRQ_DE OWL_IRQ(1)
+#define OWL_IRQ_IMX OWL_IRQ(2)
+#define OWL_IRQ_GPU OWL_IRQ(3)
+#define OWL_IRQ_PC0 OWL_IRQ(4)
+#define OWL_IRQ_PC1 OWL_IRQ(5)
+#define OWL_IRQ_PC2 OWL_IRQ(6)
+#define OWL_IRQ_PC3 OWL_IRQ(7)
+#define OWL_IRQ_RESERVED0 OWL_IRQ(8)
+#define OWL_IRQ_RESERVED1 OWL_IRQ(9)
+#define OWL_IRQ_TIMER0 OWL_IRQ(10)
+#define OWL_IRQ_TIMER1 OWL_IRQ(11)
+#define OWL_IRQ_BISP OWL_IRQ(12)
+#define OWL_IRQ_SIRQ0 OWL_IRQ(13)
+#define OWL_IRQ_SIRQ1 OWL_IRQ(14)
+#define OWL_IRQ_SIRQ2 OWL_IRQ(15)
+#define OWL_IRQ_GPIOF OWL_IRQ(16)
+#define OWL_IRQ_PCM0 OWL_IRQ(17)
+#define OWL_IRQ_PCM1 OWL_IRQ(18)
+#define OWL_IRQ_SPI0 OWL_IRQ(19)
+#define OWL_IRQ_SPI1 OWL_IRQ(20)
+#define OWL_IRQ_SPI2 OWL_IRQ(21)
+#define OWL_IRQ_SPI3 OWL_IRQ(22)
+#define OWL_IRQ_USB3 OWL_IRQ(23)
+#define OWL_IRQ_USB2H0 OWL_IRQ(24)
+#define OWL_IRQ_I2C0 OWL_IRQ(25)
+#define OWL_IRQ_I2C1 OWL_IRQ(26)
+#define OWL_IRQ_I2C2 OWL_IRQ(27)
+#define OWL_IRQ_I2C3 OWL_IRQ(28)
+#define OWL_IRQ_UART0 OWL_IRQ(29)
+#define OWL_IRQ_UART1 OWL_IRQ(30)
+#define OWL_IRQ_UART2 OWL_IRQ(31)
+#define OWL_IRQ_UART3 OWL_IRQ(32)
+#define OWL_IRQ_UART4 OWL_IRQ(33)
+#define OWL_IRQ_UART5 OWL_IRQ(34)
+#define OWL_IRQ_UART6 OWL_IRQ(35)
+#define OWL_IRQ_GPIOA OWL_IRQ(36)
+#define OWL_IRQ_GPIOB OWL_IRQ(37)
+#define OWL_IRQ_GPIOC OWL_IRQ(38)
+#define OWL_IRQ_GPIOD OWL_IRQ(39)
+#define OWL_IRQ_GPIOE OWL_IRQ(40)
+#define OWL_IRQ_NAND0 OWL_IRQ(41)
+#define OWL_IRQ_SD0 OWL_IRQ(42)
+#define OWL_IRQ_SD1 OWL_IRQ(43)
+#define OWL_IRQ_SD2 OWL_IRQ(44)
+#define OWL_IRQ_LCD OWL_IRQ(45)
+#define OWL_IRQ_HDMI OWL_IRQ(46)
+#define OWL_IRQ_USB2H1 OWL_IRQ(47)
+#define OWL_IRQ_AUDIO_INOUT OWL_IRQ(48)
+#define OWL_IRQ_VCE OWL_IRQ(49)
+#define OWL_IRQ_VDE OWL_IRQ(50)
+#define OWL_IRQ_DSI OWL_IRQ(51)
+#define OWL_IRQ_CSI0 OWL_IRQ(52)
+#define OWL_IRQ_NAND1 OWL_IRQ(53)
+#define OWL_IRQ_DCU_DEBUG OWL_IRQ(54)
+#define OWL_IRQ_L2 OWL_IRQ(55)
+#define OWL_IRQ_HDCP2TX OWL_IRQ(56)
+#define OWL_IRQ_DMA0 OWL_IRQ(57)
+#define OWL_IRQ_DMA1 OWL_IRQ(58)
+#define OWL_IRQ_DMA2 OWL_IRQ(59)
+#define OWL_IRQ_DMA3 OWL_IRQ(60)
+#define OWL_IRQ_CSI1 OWL_IRQ(61)
+#define OWL_IRQ_SD3 OWL_IRQ(62)
+#define OWL_IRQ_SECURE_TIME2 OWL_IRQ(63)
+#define OWL_IRQ_SECURE_TIME3 OWL_IRQ(64)
+#define OWL_IRQ_EDP OWL_IRQ(65)
+#define OWL_IRQ_HDE OWL_IRQ(66)
+#define OWL_IRQ_SE OWL_IRQ(67)
+#define OWL_IRQ_DCU_CH0 OWL_IRQ(68)
+#define OWL_IRQ_DCU_CH1 OWL_IRQ(69)
+
+/* Set the default NR_IRQS */
+#define NR_OWL_IRQS (OWL_IRQ(69) + 1)
+
+/* virtual IRQs: external speical IRQs */
+#define OWL_EXT_IRQ_SIRQ_BASE (NR_OWL_IRQS)
+#define OWL_EXT_IRQ_SIRQ0 (OWL_EXT_IRQ_SIRQ_BASE + 0)
+#define OWL_EXT_IRQ_SIRQ1 (OWL_EXT_IRQ_SIRQ_BASE + 1)
+#define OWL_EXT_IRQ_SIRQ2 (OWL_EXT_IRQ_SIRQ_BASE + 2)
+#define NR_OWL_SIRQ (3)
+
+/* virtual IRQs: GPIO */
+#define OWL_EXT_IRQ_GPIOA_BASE (OWL_EXT_IRQ_SIRQ_BASE + NR_OWL_SIRQ)
+#define OWL_EXT_IRQ_GPIOA(x) (OWL_EXT_IRQ_GPIOA_BASE + (x))
+#define OWL_EXT_IRQ_GPIOB_BASE (OWL_EXT_IRQ_GPIOA(31) + 1)
+#define OWL_EXT_IRQ_GPIOB(x) (OWL_EXT_IRQ_GPIOB_BASE + (x))
+#define OWL_EXT_IRQ_GPIOC_BASE (OWL_EXT_IRQ_GPIOB(31) + 1)
+#define OWL_EXT_IRQ_GPIOC(x) (OWL_EXT_IRQ_GPIOC_BASE + (x))
+#define OWL_EXT_IRQ_GPIOD_BASE (OWL_EXT_IRQ_GPIOC(31) + 1)
+#define OWL_EXT_IRQ_GPIOD(x) (OWL_EXT_IRQ_GPIOD_BASE + (x))
+
+#define NR_OWL_EXT_GPIO_INT (3 * 32 + 22) /* for ATM7029 */
+
+#define OWL_EXT_GPIO_TO_IRQ(gpio) ((gpio) + OWL_EXT_IRQ_GPIOA_BASE)
+#define OWL_EXT_IRQ_TO_GPIO(irq) ((irq) - OWL_EXT_IRQ_GPIOA_BASE)
+
+/* virtual IRQs: ATC260x */
+#define IRQ_ATC260X_BASE (OWL_EXT_IRQ_GPIOA_BASE + NR_OWL_EXT_GPIO_INT)
+/* reserved 16 interrupt sources for ATC260x */
+#define IRQ_ATC260X_MAX_NUM 16
+
+#define NR_IRQS (IRQ_ATC260X_BASE + IRQ_ATC260X_MAX_NUM)
+
+#endif /* __ASM_ARCH_IRQS_H */
diff --git a/drivers/usb/dwc3/usb3_regs.h b/drivers/usb/dwc3/usb3_regs.h
new file mode 100644
index 0000000..9abb741
--- /dev/null
+++ b/drivers/usb/dwc3/usb3_regs.h
@@ -0,0 +1,136 @@
+#ifndef __USB3_REGS_H__
+#define __USB3_REGS_H__
+
+//--------------USB3_Register-------------------------------------------//
+//--------------Register Address---------------------------------------//
+#define ANA00 (0+0xCD00)
+#define ANA01 (0+0xCD04)
+#define ANA02 (0+0xCD08)
+#define ANA03 (0+0xCD0C)
+#define ANA04 (0+0xCD10)
+
+#define ANA05 (0+0xCD14)
+#define ANA06 (0+0xCD18)
+#define ANA07 (0+0xCD1C)
+#define ANA08 (0+0xCD20)
+#define ANA09 (0+0xCD24)
+#define ANA0A (0+0xCD28)
+#define ANA0B (0+0xCD2C)
+#define ANA0C (0+0xCD30)
+#define ANA0D (0+0xCD34)
+#define ANA0E (0+0xCD38)
+#define ANA0F (0+0xCD3C)
+#define DMR (0+0xCD40)
+#define BACR (0+0xCD44)
+#define IER (0+0xCD48)
+#define BCSR (0+0xCD4C)
+#define BPR (0+0xCD50)
+#define BPNR2 (0+0xCD54)
+#define BFNR (0+0xCD58)
+#define BRNR2 (0+0xCD5C)
+#define BENR (0+0xCD60)
+#define REV0 (0+0xCD64)
+#define REV1 (0+0xCD68)
+#define REV2 (0+0xCD6C)
+#define REV3 (0+0xCD70)
+#define FLD0 (0+0xCD74)
+#define FLD1 (0+0xCD78)
+#define ANA1F (0+0xCD7C)
+#define PAGE1_REG00 (0+0xCD80)
+#define PAGE1_REG01 (0+0xCD84)
+#define PAGE1_REG02 (0+0xCD88)
+#define PAGE1_REG03 (0+0xCD8C)
+#define PAGE1_REG04 (0+0xCD90)
+#define PAGE1_REG05 (0+0xCD94)
+#define PAGE1_REG06 (0+0xCD98)
+#define PAGE1_REG07 (0+0xCD9C)
+#define PAGE1_REG08 (0+0xCDA0)
+#define PAGE1_REG09 (0+0xCDA4)
+#define PAGE1_REG0A (0+0xCDA8)
+#define PAGE1_REG0B (0+0xCDAC)
+#define PAGE1_REG0C (0+0xCDB0)
+#define PAGE1_REG0D (0+0xCDB4)
+#define PAGE1_REG0E (0+0xCDB8)
+#define PAGE1_REG0F (0+0xCDBC)
+#define PAGE1_REG10 (0+0xCDC0)
+#define USB2_P0_VDCTRL (0+0xCE00)
+#define BACKDOOR (0+0xCE04)
+#define EXT_CONTROL (0+0xCE08)
+#define EFUSE_CTR (0+0xCE0C)
+#define USB2_P1_VDCTRL (0+0xCE10)
+
+
+#define USB3_ACTIONS_START (0xcd00)
+#define USB3_ACTIONS_END (0xcd58)
+
+#define DWC3_CDR_KIKD (0x00)
+#define DWC3_CDR_KP1 (0x04)
+#define DWC3_TIMER_INIT (0x08)
+#define DWC3_CDR_CONTROL (0x0c)
+#define DWC3_RX_OFFSET_PS (0x10)
+#define DWC3_EQ_CONTROL (0x14)
+#define DWC3_RX_OOBS_SSC0 (0x18)
+#define DWC3_CMU_SSC1 (0x1C)
+#define DWC3_CMU_DEBUG_LDO (0x20)
+#define DWC3_TX_AMP_DEBUG (0x24)
+#define DWC3_Z0 (0x28)
+#define DWC3_DMR_BACR (0x2C)
+#define DWC3_IER_BCSR (0x30)
+#define DWC3_BPR (0x34)
+#define DWC3_BFNR (0x38)
+#define DWC3_BENR_REV (0x3C)
+#define DWC3_FLD (0x40)
+#define DWC3_CMU_PLL2_BISTDEBUG (0x44)
+
+#define USB3_MOD_RST (1 << 14)
+#define CMU_BIAS_EN (1 << 20)
+
+#define BIST_QINIT(n) ((n) << 24)
+#define EYE_HEIGHT(n) ((n) << 20)
+#define PLL2_LOCK (1 << 15)
+#define PLL2_RS(n) ((n) << 12)
+#define PLL2_ICP(n) ((n) << 10)
+#define CMU_SEL_PREDIV (1 << 9)
+#define CMU_DIVX2 (1 << 8)
+#define PLL2_DIV(n) ((n) << 3)
+#define PLL2_POSTDIV(n) ((n) << 1)
+#define PLL2_PU (1 << 0)
+
+//=============== USB3_P0_CTL define=======================
+#define USB3_P0_CTL_LDOVREFSEL_SHIFT_IC1 28
+#define USB3_P0_CTL_PLLLDOEN_IC1 31
+
+#define USB3_P0_CTL_LDOVREFSEL_E 30
+#define USB3_P0_CTL_LDOVREFSEL_SHIFT 29
+#define USB3_P0_CTL_LDOVREFSEL_MASK (0x3<<29)
+#define USB3_P0_CTL_PLLLDOEN 28
+#define USB3_P0_CTL_PLUGIN 25
+#define USB3_P0_CTL_CONDET_EN 24
+#define USB3_P0_CTL_WKUPBVLDEN 23
+#define USB3_P0_CTL_WKUPDPEN 22
+#define USB3_P0_CTL_WKUPIDUSEN 21
+#define USB3_P0_CTL_WKUPVBUSEN 20
+#define USB3_P0_CTL_WKUPBVLD 19
+#define USB3_P0_CTL_WKUPDP 18
+#define USB3_P0_CTL_WKUPID 17
+#define USB3_P0_CTL_WKUPVBUS 16
+#define USB3_P0_CTL_DMPUEN_P0 15
+#define USB3_P0_CTL_DPPUEN_P0 14
+#define USB3_P0_CTL_DMPDDIS_P0 13
+#define USB3_P0_CTL_DPPDDIS_P0 12
+#define USB3_P0_CTL_ID_P0 11
+#define USB3_P0_CTL_BVALID_P0 10
+#define USB3_P0_CTL_SOFTID_P0 9
+#define USB3_P0_CTL_SOFTIDEN_P0 8
+#define USB3_P0_CTL_SOFTVBUS_P0 7
+#define USB3_P0_CTL_SOFTVBUSEN_P0 6
+#define USB3_P0_CTL_VBUS_P0 5
+#define USB3_P0_CTL_LS_P0_E 4
+#define USB3_P0_CTL_LS_P0_SHIFT 3
+#define USB3_P0_CTL_LS_P0_MASK (0x3<<3)
+#define USB3_P0_CTL_VBUSTH_P0_E 2
+#define USB3_P0_CTL_VBUSTH_P0_SHIFT 0
+#define USB3_P0_CTL_VBUSTH_P0_MASK (0x7<<0)
+
+
+#endif
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
old mode 100644
new mode 100755
index bcf83c0..cc9b692
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -129,6 +129,10 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
source "drivers/usb/gadget/udc/Kconfig"
+# Selected by UDC drivers that support high-speed operation.
+config USB_GADGET_DUALSPEED
+ bool
+
#
# USB Gadget Drivers
#
@@ -455,4 +459,13 @@ source "drivers/usb/gadget/legacy/Kconfig"
endchoice
+config USB_ACTIONS_ADFUSERVER
+ tristate "Actions Adfuserver Gadget"
+ depends on ARCH_OWL
+ select USB_LIBCOMPOSITE
+ help
+ The Actions Adfuserver Gadget is use for actions' board
+ to upgrade firmware. It must work with actions' dwc3
+ driver.
+
endif # USB_GADGET
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
old mode 100644
new mode 100755
index 58b4657..fa5be9a
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -20,6 +20,7 @@
#include <linux/usb/composite.h>
#include <asm/unaligned.h>
+#include <linux/kallsyms.h>
#include "u_os_desc.h"
@@ -45,7 +46,11 @@ struct usb_os_string {
* objects, and a "usb_composite_driver" by gluing them together along
* with the relevant device-wide data.
*/
-
+#ifndef CONFIG_USB_GADGET_VBUS_DRAW
+#define CONFIG_USB_GADGET_VBUS_DRAW 400
+#endif
+typedef void (*FUNX)(int);
+FUNX set_delaystatus_flag;
static struct usb_gadget_strings **get_containers_gs(
struct usb_gadget_string_container *uc)
{
@@ -891,6 +896,7 @@ void usb_remove_config(struct usb_composite_dev *cdev,
remove_config(cdev, config);
}
+EXPORT_SYMBOL(usb_remove_config);
/*-------------------------------------------------------------------------*/
@@ -2222,6 +2228,9 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev)
DBG(cdev, "%s: Completing delayed status\n", __func__);
req->length = 0;
req->context = cdev;
+ set_delaystatus_flag = (FUNX)kallsyms_lookup_name("set_no_delay_status");
+ if (set_delaystatus_flag)
+ set_delaystatus_flag(1); /* make sure the usb_ep_queue have done really */
value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
old mode 100644
new mode 100755
index 917d99c..16d1b84
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -713,7 +713,7 @@ static int do_read(struct fsg_common *common)
}
/* Perform the read */
- file_offset_tmp = file_offset;
+ file_offset_tmp = file_offset;
nread = vfs_read(curlun->filp,
(char __user *)bh->buf,
amount, &file_offset_tmp);
@@ -1083,7 +1083,6 @@ static int do_verify(struct fsg_common *common)
return 0;
}
-
/*-------------------------------------------------------------------------*/
static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
@@ -1675,6 +1674,18 @@ static int send_status(struct fsg_common *common)
return -EIO;
common->next_buffhd_to_fill = bh->next;
+
+#ifdef SUPPORT_UDISK_UPGRADE
+ if(restart_flag == 1) {
+ set_upgrade_flags_and_restart();
+ }
+#endif
+
+#ifdef SUPPORT_SET_SERIAL_NUMBER
+ if(adfu_restart_flag == 1) {
+ gadget_andorid_shutdown_machine();
+ }
+#endif
return 0;
}
@@ -2059,7 +2070,6 @@ static int do_scsi_command(struct fsg_common *common)
if (reply == 0)
reply = do_write(common);
break;
-
/*
* Some mandatory commands that we recognize but don't implement.
* They don't mean much in this setting. It's left as an exercise
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
old mode 100644
new mode 100755
index 648f9e4..a4af310
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -293,6 +293,24 @@ int fsg_lun_fsync_sub(struct fsg_lun *curlun)
if (curlun->ro || !filp)
return 0;
+#ifdef DEBUG_TIME_OF_VFS_OP
+ if(debug_vfs_op_time) {
+ struct timeval tv_start;
+ struct timeval tv_end;
+ int ret;
+
+ do_gettimeofday(&tv_start);
+
+ ret = vfs_fsync(filp, 1);
+
+ do_gettimeofday(&tv_end);
+ calculate_time_of_vfs_op(&tv_start, &tv_end);
+
+ return ret;
+ }
+ else
+
+#endif
return vfs_fsync(filp, 1);
}
EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile
old mode 100644
new mode 100755
index 7f485f2..2b85397
--- a/drivers/usb/gadget/legacy/Makefile
+++ b/drivers/usb/gadget/legacy/Makefile
@@ -42,3 +42,6 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
+
+adfus-y := adfuserver.o
+obj-$(CONFIG_USB_ACTIONS_ADFUSERVER) += adfus.o
diff --git a/drivers/usb/gadget/legacy/adfuserver.c b/drivers/usb/gadget/legacy/adfuserver.c
new file mode 100644
index 0000000..de916fc
--- /dev/null
+++ b/drivers/usb/gadget/legacy/adfuserver.c
@@ -0,0 +1,4987 @@
+/*
+ * file_storage.c -- File-backed USB Storage Gadget, for USB development
+ *
+ * Copyright (C) 2003-2007 Alan Stern
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The File-backed Storage Gadget acts as a USB Mass Storage device,
+ * appearing to the host as a disk drive. In addition to providing an
+ * example of a genuinely useful gadget driver for a USB device, it also
+ * illustrates a technique of double-buffering for increased throughput.
+ * Last but not least, it gives an easy way to probe the behavior of the
+ * Mass Storage drivers in a USB host.
+ *
+ * Backing storage is provided by a regular file or a block device, specified
+ * by the "file" module parameter. Access can be limited to read-only by
+ * setting the optional "ro" module parameter. The gadget will indicate that
+ * it has removable media if the optional "removable" module parameter is set.
+ *
+ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
+ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
+ * by the optional "transport" module parameter. It also supports the
+ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
+ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
+ * the optional "protocol" module parameter. In addition, the default
+ * Vendor ID, Product ID, and release number can be overridden.
+ *
+ * There is support for multiple logical units (LUNs), each of which has
+ * its own backing file. The number of LUNs can be set using the optional
+ * "luns" module parameter (anywhere from 1 to 8), and the corresponding
+ * files are specified using comma-separated lists for "file" and "ro".
+ * The default number of LUNs is taken from the number of "file" elements;
+ * it is 1 if "file" is not given. If "removable" is not set then a backing
+ * file must be specified for each LUN. If it is set, then an unspecified
+ * or empty backing filename means the LUN's medium is not loaded.
+ *
+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
+ * needed (an interrupt-out endpoint is also needed for CBI). The memory
+ * requirement amounts to two 16K buffers, size configurable by a parameter.
+ * Support is included for both full-speed and high-speed operation.
+ *
+ * Note that the driver is slightly non-portable in that it assumes a
+ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
+ * interrupt-in endpoints. With most device controllers this isn't an
+ * issue, but there may be some with hardware restrictions that prevent
+ * a buffer from being used by more than one endpoint.
+ *
+ * Module options:
+ *
+ * file=filename[,filename...]
+ * Required if "removable" is not set, names of
+ * the files or block devices used for
+ * backing storage
+ * ro=b[,b...] Default false, booleans for read-only access
+ * removable Default false, boolean for removable media
+ * luns=N Default N = number of filenames, number of
+ * LUNs to support
+ * stall Default determined according to the type of
+ * USB device controller (usually true),
+ * boolean to permit the driver to halt
+ * bulk endpoints
+ * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
+ * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
+ * ATAPI, QIC, UFI, 8070, or SCSI;
+ * also 1 - 6)
+ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
+ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
+ * release=0xRRRR Override the USB release number (bcdDevice)
+ * buflen=N Default N=16384, buffer size used (will be
+ * rounded down to a multiple of
+ * PAGE_CACHE_SIZE)
+ *
+ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
+ * "removable", "luns", and "stall" options are available; default values
+ * are used for everything else.
+ *
+ * The pathnames of the backing files and the ro settings are available in
+ * the attribute files "file" and "ro" in the lun<n> subdirectory of the
+ * gadget's sysfs directory. If the "removable" option is set, writing to
+ * these files will simulate ejecting/loading the medium (writing an empty
+ * line means eject) and adjusting a write-enable tab. Changes to the ro
+ * setting are not allowed when the medium is loaded.
+ *
+ * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
+ * The driver's SCSI command interface was based on the "Information
+ * technology - Small Computer System Interface - 2" document from
+ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
+ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
+ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
+ * "Universal Serial Bus Mass Storage Class UFI Command Specification"
+ * document, Revision 1.0, December 14, 1998, available at
+ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
+ */
+
+/*
+ * Driver Design
+ *
+ * The FSG driver is fairly straightforward. There is a main kernel
+ * thread that handles most of the work. Interrupt routines field
+ * callbacks from the controller driver: bulk- and interrupt-request
+ * completion notifications, endpoint-0 events, and disconnect events.
+ * Completion events are passed to the main thread by wakeup calls. Many
+ * ep0 requests are handled at interrupt time, but SetInterface,
+ * SetConfiguration, and device reset requests are forwarded to the
+ * thread in the form of "exceptions" using SIGUSR1 signals (since they
+ * should interrupt any ongoing file I/O operations).
+ *
+ * The thread's main routine implements the standard command/data/status
+ * parts of a SCSI interaction. It and its subroutines are full of tests
+ * for pending signals/exceptions -- all this polling is necessary since
+ * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
+ * indication that the driver really wants to be running in userspace.)
+ * An important point is that so long as the thread is alive it keeps an
+ * open reference to the backing file. This will prevent unmounting
+ * the backing file's underlying filesystem and could cause problems
+ * during system shutdown, for example. To prevent such problems, the
+ * thread catches INT, TERM, and KILL signals and converts them into
+ * an EXIT exception.
+ *
+ * In normal operation the main thread is started during the gadget's
+ * fsg_bind() callback and stopped during fsg_unbind(). But it can also
+ * exit when it receives a signal, and there's no point leaving the
+ * gadget running when the thread is dead. So just before the thread
+ * exits, it deregisters the gadget driver. This makes things a little
+ * tricky: The driver is deregistered at two places, and the exiting
+ * thread can indirectly call fsg_unbind() which in turn can tell the
+ * thread to exit. The first problem is resolved through the use of the
+ * REGISTERED atomic bitflag; the driver will only be deregistered once.
+ * The second problem is resolved by having fsg_unbind() check
+ * fsg->state; it won't try to stop the thread if the state is already
+ * FSG_STATE_TERMINATED.
+ *
+ * To provide maximum throughput, the driver uses a circular pipeline of
+ * buffer heads (struct fsg_buffhd). In principle the pipeline can be
+ * arbitrarily long; in practice the benefits don't justify having more
+ * than 2 stages (i.e., double buffering). But it helps to think of the
+ * pipeline as being a long one. Each buffer head contains a bulk-in and
+ * a bulk-out request pointer (since the buffer can be used for both
+ * output and input -- directions always are given from the host's
+ * point of view) as well as a pointer to the buffer and various state
+ * variables.
+ *
+ * Use of the pipeline follows a simple protocol. There is a variable
+ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
+ * At any time that buffer head may still be in use from an earlier
+ * request, so each buffer head has a state variable indicating whether
+ * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
+ * buffer head to be EMPTY, filling the buffer either by file I/O or by
+ * USB I/O (during which the buffer head is BUSY), and marking the buffer
+ * head FULL when the I/O is complete. Then the buffer will be emptied
+ * (again possibly by USB I/O, during which it is marked BUSY) and
+ * finally marked EMPTY again (possibly by a completion routine).
+ *
+ * A module parameter tells the driver to avoid stalling the bulk
+ * endpoints wherever the transport specification allows. This is
+ * necessary for some UDCs like the SuperH, which cannot reliably clear a
+ * halt on a bulk endpoint. However, under certain circumstances the
+ * Bulk-only specification requires a stall. In such cases the driver
+ * will halt the endpoint and set a flag indicating that it should clear
+ * the halt in software during the next device reset. Hopefully this
+ * will permit everything to work correctly. Furthermore, although the
+ * specification allows the bulk-out endpoint to halt when the host sends
+ * too much data, implementing this would cause an unavoidable race.
+ * The driver will always use the "no-stall" approach for OUT transfers.
+ *
+ * One subtle point concerns sending status-stage responses for ep0
+ * requests. Some of these requests, such as device reset, can involve
+ * interrupting an ongoing file I/O operation, which might take an
+ * arbitrarily long time. During that delay the host might give up on
+ * the original ep0 request and issue a new one. When that happens the
+ * driver should not notify the host about completion of the original
+ * request, as the host will no longer be waiting for it. So the driver
+ * assigns to each ep0 request a unique tag, and it keeps track of the
+ * tag value of the request associated with a long-running exception
+ * (device-reset, interface-change, or configuration-change). When the
+ * exception handler is finished, the status-stage response is submitted
+ * only if the current ep0 request tag is equal to the exception request
+ * tag. Thus only the most recently received ep0 request will get a
+ * status-stage response.
+ *
+ * Warning: This driver source file is too long. It ought to be split up
+ * into a header file plus about 3 separate .c files, to handle the details
+ * of the Gadget, USB Mass Storage, and SCSI protocols.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/dcache.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kref.h>
+#include <linux/kthread.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/freezer.h>
+#include <linux/utsname.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+#include <linux/of.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/kdev_t.h>
+#include <mach/hardware.h>
+
+#include <linux/string.h>
+
+//#include <mach/atc260x/atc260x.h>
+#include <linux/ctype.h>
+#include <linux/usb/composite.h>
+#include "gadget_chips.h"
+#include "adfuserver.h"
+#include <mach/bootdev.h>
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+//#include "usbstring.c"
+//#include "config.c"
+//#include "epautoconf.c"
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_DESC "File-backed Storage Gadget"
+#define DRIVER_NAME "g_file_storage"
+#define DRIVER_VERSION "7 August 2007"
+
+static const char longname[] = DRIVER_DESC;
+static const char shortname[] = DRIVER_NAME;
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Alan Stern");
+MODULE_LICENSE("GPL");
+#if 0
+struct uparam {
+ unsigned int flash_partition;
+ unsigned int devnum_in_phypart;
+};
+#endif
+enum probatch_status {
+ PROBATCH_START = 0,
+ PROBATCH_INSTAL_FLASH,
+ PROBATCH_FINISH_INSTALL_FLASH,
+ PROBATCH_WRITE_PHY,
+ PROBATCH_FINISH_WRITE_PHY,
+ PROBATCH_FORMAT,
+ PROBATCH_FINISH_FORMAT,
+ PROBATCH_FINISH,
+ PROBATCH_FINISH_OK,
+};
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures. */
+#define DRIVER_VENDOR_ID 0x10D6 /* NetChip */
+#define DRIVER_PRODUCT_ID 0x10D6
+/* Linux-USB File-backed Storage Gadget */
+
+/*
+ * This driver assumes self-powered hardware and has no way for users to
+ * trigger remote wakeup. It uses autoconfiguration to select endpoints
+ * and endpoint addresses.
+ */
+
+#define MAJOR_OF_MMS 254
+#define MAJOR_OF_CARD 179
+#define MAJOR_OF_NAND 93
+
+#define CARD_MEDIUM 10
+#define NAND_MEDIUM 20
+#define MMS_MEDIUM 30
+
+#define WHEN_FOR_ADFU 1
+
+#ifndef CONFIG_USB_GADGET_VBUS_DRAW
+#define CONFIG_USB_GADGET_VBUS_DRAW 400
+#endif
+/* NAND directly ADFU is not ready yet, defined for debug */
+
+#define SUPPORT_DIRECT_UDISK
+unsigned char no_finish_reply;
+
+static int adfu_success_flag;
+static int need_format = 0;
+static char need_restart = 1;
+static int need_checksum = 0;
+
+static int write_mbrc = 0;
+static int write_recovery = 0;
+static int write_system = 0;
+
+#define INVALID_ADFU_CHECKSUM 0xAFAFAFAF
+static __u32 system_checksum = INVALID_ADFU_CHECKSUM;
+static __u32 misc_checksum = INVALID_ADFU_CHECKSUM;
+static __u32 recovery_checksum = INVALID_ADFU_CHECKSUM;
+
+char afinfo_name[32];
+char mbrc_name[32];
+char format_fs_name[8];
+char format_disk_name[32];
+char disk_label[][8]={
+ "bootmsg",
+ "data",
+ "cache",
+ "NONAME"
+ };
+char *format_disk_label;
+
+//static int first_start;
+
+static unsigned int uniSerial;
+
+/* add by hmwei */
+extern char probatch_phase[];
+int cmnd_sequence_first_flag=1;
+struct file *misc_disk_filp;
+char last_cmnd=-1;
+
+enum plugstate{
+ PLUGSTATE_A_OUT=0,
+ PLUGSTATE_B_OUT,
+ PLUGSTATE_A_IN,
+ PLUGSTATE_B_IN,
+
+};
+extern int dwc3_set_plugstate(int s);
+
+extern int set_probatch_phase(int id);
+extern int is_probatch_phase(int id);
+
+
+/*-------------------------------------------------------------------------*/
+
+#define LDBG(lun, fmt, args...) \
+ dev_dbg(&(lun)->dev , fmt , ## args)
+#define MDBG(fmt, args...) \
+ pr_debug(DRIVER_NAME ": " fmt , ## args)
+
+// #define VERBOSE_DEBUG
+
+#ifndef DEBUG
+#undef VERBOSE_DEBUG
+#undef DUMP_MSGS
+#endif /* !DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#define VLDBG LDBG
+#else
+#define VLDBG(lun, fmt, args...) \
+ do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define LERROR(lun, fmt, args...) \
+ dev_err(&(lun)->dev, fmt, ## args)
+#define LWARN(lun, fmt,args...) \
+ dev_warn(&(lun)->dev, fmt, ## args)
+#define LINFO(lun, fmt, args...) \
+ dev_info(&(lun)->dev, fmt, ## args)
+
+#define MINFO(fmt, args...) \
+ pr_info(DRIVER_NAME ": " fmt , ## args)
+
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* Encapsulate the module parameter settings */
+
+#define MAX_LUNS 8
+
+/* USB protocol value = the transport method */
+#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
+#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
+#define USB_PR_BULK 0x50 /* Bulk-only */
+
+/* USB subclass value = the protocol encapsulation */
+#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
+#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
+#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
+#define USB_SC_UFI 0x04 /* UFI (floppy) */
+#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
+#define USB_SC_SCSI 0x06 /* Transparent SCSI */
+
+static struct {
+ char *file[MAX_LUNS];
+ int ro[MAX_LUNS];
+ unsigned int num_filenames;
+ unsigned int num_ros;
+ unsigned int nluns;
+
+ int removable;
+ int can_stall;
+
+ char *transport_parm;
+ char *protocol_parm;
+ unsigned short vendor;
+ unsigned short product;
+ unsigned short release;
+ unsigned int buflen;
+
+ int transport_type;
+ char *transport_name;
+ int protocol_type;
+ char *protocol_name;
+
+} mod_data = { /* Default values */
+ /* .file[0] = "/dev/actd", */
+ .transport_parm = "BBB",
+ //.protocol_parm = "SCSI",
+ .protocol_parm = "8070i",
+
+
+ .transport_type = USB_PR_BULK, /*! transport type signed by usb-if*/
+ .transport_name = "Bulk-only", /*! transport name*/
+ .protocol_type = USB_SC_8070, /*! protocol type*/
+ .protocol_name = "8070i", /*! protocol name*/
+
+ .nluns = 2, /* tmp used by wlt 20091130 */
+ .removable = 1,
+ .can_stall = 0,
+ .vendor = DRIVER_VENDOR_ID,
+ .product = DRIVER_PRODUCT_ID,
+ .release = 0xffff, /* Use controller chip type */
+ .buflen = 16384,
+};
+
+module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
+ S_IRUGO);
+MODULE_PARM_DESC(file, "names of backing files or devices");
+
+
+module_param_named(uniSerial, uniSerial, uint, S_IRUGO);
+MODULE_PARM_DESC(uniSerial,
+ "1 to indicate we should report iSerialNumber as unicode mod");
+
+//MODULE_PARM_DESC(file, "names of backing files or devices");
+
+module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
+MODULE_PARM_DESC(vendor, "USB Vendor ID");
+
+module_param_named(product, mod_data.product, ushort, S_IRUGO);
+MODULE_PARM_DESC(product, "USB Product ID");
+
+module_param_named(release, mod_data.release, ushort, S_IRUGO);
+MODULE_PARM_DESC(release, "USB release number");
+
+/*-------------------------------------------------------------------------*/
+
+
+/* Bulk-only data structures */
+
+/* Command Block Wrapper */
+struct bulk_cb_wrap {
+ __le32 Signature; /* Contains 'USBC' */
+ u32 Tag; /* Unique per command id */
+ __le32 DataTransferLength; /* Size of the data */
+ u8 Flags; /* Direction in bit 7 */
+ u8 Lun; /* LUN (normally 0) */
+ u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
+ u8 CDB[16]; /* Command Data Block */
+};
+
+#define USB_BULK_CB_WRAP_LEN 31
+#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
+#define USB_BULK_IN_FLAG 0x80
+
+/* Command Status Wrapper */
+struct bulk_cs_wrap {
+ __le32 Signature; /* Should = 'USBS' */
+ u32 Tag; /* Same as original command */
+ __le32 Residue; /* Amount not transferred */
+ u8 Status; /* See below */
+};
+
+#define USB_BULK_CS_WRAP_LEN 13
+#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
+#define USB_STATUS_PASS 0
+#define USB_STATUS_FAIL 1
+#define USB_STATUS_PHASE_ERROR 2
+
+/* Bulk-only class specific requests */
+#define USB_BULK_RESET_REQUEST 0xff
+#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
+
+/* CBI Interrupt data structure */
+struct interrupt_data {
+ u8 bType;
+ u8 bValue;
+};
+
+#define CBI_INTERRUPT_DATA_LEN 2
+
+/* CBI Accept Device-Specific Command request */
+#define USB_CBI_ADSC_REQUEST 0x00
+
+#define MAX_COMMAND_SIZE 16
+/* Length of a SCSI Command Data Block */
+
+/* SCSI commands that we recognize */
+#define SC_FORMAT_UNIT 0x04
+#define SC_INQUIRY 0x12
+#define SC_MODE_SELECT_6 0x15
+#define SC_MODE_SELECT_10 0x55
+#define SC_MODE_SENSE_6 0x1a
+#define SC_MODE_SENSE_10 0x5a
+#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
+#define SC_READ_6 0x08
+#define SC_READ_10 0x28
+#define SC_READ_12 0xa8
+#define SC_READ_CAPACITY 0x25
+#define SC_READ_FORMAT_CAPACITIES 0x23
+#define SC_RELEASE 0x17
+#define SC_REQUEST_SENSE 0x03
+#define SC_RESERVE 0x16
+#define SC_SEND_DIAGNOSTIC 0x1d
+#define SC_START_STOP_UNIT 0x1b
+#define SC_SYNCHRONIZE_CACHE 0x35
+#define SC_TEST_UNIT_READY 0x00
+#define SC_VERIFY 0x2f
+#define SC_WRITE_6 0x0a
+#define SC_WRITE_10 0x2a
+#define SC_WRITE_12 0xaa
+
+/* make sure the U-device is ACTIONS */
+#define SC_ACTIONS_INQUIRY 0xcc
+#define SC_ADFU_UPGRADE 0xcd
+/* sub-code used for up-tool */
+#define SC_ADFU_ACCESS_MBR 0x90
+#define SC_ADFU_WRITE_ROOTFS 0x11
+#define SC_ADFU_READ_ROOTFS 0x91
+
+#define SC_ADFU_ACCESS_INTERNAL_RAM 0x13
+
+#define SC_ADFU_FORMAT_FLASH 0x16
+#define SC_ADFU_TEST_FLASHRDY 0x17
+
+/* sub-code used for u-disk upgrade */
+#define SC_ADFU_WRITE_FILES 0x12
+
+/* FILE TYPE PARAM */
+#define FP_MBREC 0x01
+#define FP_MBRINFO 0x02
+#define FP_VMLINUX 0x03
+
+#define SC_ADFU_TEST_READY 0x13
+
+/* TEST ACTION TYPE PARAM */
+#define SC_ADFU_FILE_READY 0x01
+#define SC_ADFU_APP_READY 0x02
+
+#define SC_ADFU_START_APP 0x14
+#define SC_ADFU_CREATE_FILES 0x15
+
+#define SC_ADFU_DOWNLOAD_IMG 0x60
+
+#define SC_ADFU_INFO 0xc0
+#define SC_ADFU_TFEROVER 0x30
+
+/* upgrade success-ful */
+#define SC_ADFU_SUCCESSFUL 0xb0
+#define SS_CHECKSUM_FAIL 0x083800
+
+/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
+#define SS_NO_SENSE 0
+#define SS_COMMUNICATION_FAILURE 0x040800
+#define SS_INVALID_COMMAND 0x052000
+#define SS_INVALID_FIELD_IN_CDB 0x052400
+#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
+#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
+#define SS_MEDIUM_NOT_PRESENT 0x023a00
+#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
+#define SS_NOT_READY_TO_READY_TRANSITION 0x062800
+#define SS_RESET_OCCURRED 0x062900
+#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
+#define SS_UNRECOVERED_READ_ERROR 0x031100
+#define SS_WRITE_ERROR 0x030c02
+#define SS_WRITE_PROTECTED 0x072700
+
+#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
+#define ASC(x) ((u8) ((x) >> 8))
+#define ASCQ(x) ((u8) (x))
+
+/*-------------------------------------------------------------------------*/
+
+#define transport_is_bbb() 1
+#define transport_is_cbi() 0
+
+struct lun {
+ struct file *filp;
+ loff_t file_length;
+ loff_t num_sectors;
+ u8 sector_size_mask;
+ u8 disk_type; /* add by wlt 20091130 */
+ dev_t devnum; /* add by wlt 20091223 */
+
+ unsigned int ro:1;
+ unsigned int prevent_medium_removal:1;
+ unsigned int registered:1;
+ unsigned int info_valid:1;
+
+ u32 sense_data;
+ u32 sense_data_info;
+ u32 unit_attention_data;
+
+ struct device dev;
+};
+
+#define backing_file_is_open(curlun) ((curlun)->filp != NULL)
+
+static struct lun *dev_to_lun(struct device *dev)
+{
+ return container_of(dev, struct lun, dev);
+}
+
+/* Big enough to hold our biggest descriptor */
+#define EP0_BUFSIZE 256
+#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
+
+/* Number of buffers we will use. 2 is enough for double-buffering */
+#define NUM_BUFFERS 2
+
+
+enum fsg_buffer_state {
+ BUF_STATE_EMPTY = 0,
+ BUF_STATE_FULL,
+ BUF_STATE_BUSY
+};
+
+struct fsg_buffhd {
+ void *buf;
+ enum fsg_buffer_state state;
+ struct fsg_buffhd *next;
+
+ /* The NetChip 2280 is faster, and handles some protocol faults
+ * better, if we don't submit any short bulk-out read requests.
+ * So we will record the intended request length here. */
+ unsigned int bulk_out_intended_length;
+
+ struct usb_request *inreq;
+ int inreq_busy;
+ struct usb_request *outreq;
+ int outreq_busy;
+};
+
+enum fsg_state {
+ FSG_STATE_COMMAND_PHASE = -10, /* This one isn't used anywhere */
+ FSG_STATE_DATA_PHASE,
+ FSG_STATE_STATUS_PHASE,
+
+ FSG_STATE_IDLE = 0,
+ FSG_STATE_ABORT_BULK_OUT,
+ FSG_STATE_RESET,
+ FSG_STATE_INTERFACE_CHANGE,
+ FSG_STATE_CONFIG_CHANGE,
+ FSG_STATE_DISCONNECT,
+ FSG_STATE_EXIT,
+ FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+ DATA_DIR_UNKNOWN = 0,
+ DATA_DIR_FROM_HOST,
+ DATA_DIR_TO_HOST,
+ DATA_DIR_NONE
+};
+
+struct fsg_dev {
+ /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
+ spinlock_t lock;
+ struct usb_gadget *gadget;
+
+ /* filesem protects: backing files in use */
+ struct rw_semaphore filesem;
+
+ /* reference counting: wait until all LUNs are released */
+ struct kref ref;
+
+ struct usb_ep *ep0; /* Handy copy of gadget->ep0 */
+ struct usb_request *ep0req; /* For control responses */
+ unsigned int ep0_req_tag;
+ const char *ep0req_name;
+
+ struct usb_request *intreq; /* For interrupt responses */
+ int intreq_busy;
+ struct fsg_buffhd *intr_buffhd;
+
+ unsigned int bulk_out_maxpacket;
+ enum fsg_state state; /* For exception handling */
+ unsigned int exception_req_tag;
+
+ u8 config, new_config;
+
+ unsigned int running:1;
+ unsigned int bulk_in_enabled:1;
+ unsigned int bulk_out_enabled:1;
+ unsigned int intr_in_enabled:1;
+ unsigned int phase_error:1;
+ unsigned int short_packet_received:1;
+ unsigned int bad_lun_okay:1;
+
+ unsigned long atomic_bitflags;
+#define REGISTERED 0
+#define IGNORE_BULK_OUT 1
+/* #define CLEAR_BULK_HALTS 1 */
+#define SUSPENDED 2
+
+ struct usb_ep *bulk_in;
+ struct usb_ep *bulk_out;
+ struct usb_ep *intr_in;
+
+ struct fsg_buffhd *next_buffhd_to_fill;
+ struct fsg_buffhd *next_buffhd_to_drain;
+ struct fsg_buffhd buffhds[NUM_BUFFERS];
+
+ int thread_wakeup_needed;
+ struct completion thread_notifier;
+ struct task_struct *thread_task;
+
+ int cmnd_size;
+ u8 cmnd[MAX_COMMAND_SIZE];
+ enum data_direction data_dir;
+ u32 data_size;
+ u32 data_size_from_cmnd;
+ u32 tag;
+ unsigned int lun;
+ u32 residue;
+ u32 usb_amount_left;
+
+ /* The CB protocol offers no way for a host to know when a command
+ * has completed. As a result the next command may arrive early,
+ * and we will still have to handle it. For that reason we need
+ * a buffer to store new commands when using CB (or CBI, which
+ * does not oblige a host to wait for command completion either). */
+ int cbbuf_cmnd_size;
+ u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
+
+ unsigned int nluns;
+ struct lun *luns;
+ struct lun *curlun;
+};
+
+/****************************************************/
+/**** for the app to know current state of udisk ****/
+
+#define TIMEOUT (HZ * 1)
+struct status_ops {
+ unsigned long timeout;
+ wait_queue_head_t wait;
+ struct completion thread_exit;
+ unsigned char quit;
+} status_arg;
+
+#define STATE_IDLE 0
+#define STATE_READING 1
+#define STATE_WRITING 2
+
+//static unsigned int card_dirty_flag;
+//static unsigned int nand_dirty_flag;
+
+int check_partition_flag=0;//partiton update
+int update_phy_boot=0;//
+
+/*****************************************************/
+//static int do_ADFU_acmbr(struct fsg_dev *);
+static int do_ADFU_wtrootfs(struct fsg_dev *);
+static void handle_exception(struct fsg_dev *fsg);
+//static int open_backing_file(struct lun *curlun, const char *filename);
+
+extern void machine_restart(char *cmd);
+
+typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+static int exception_in_progress(struct fsg_dev *fsg)
+{
+ return fsg->state > FSG_STATE_IDLE;
+}
+
+/* Make bulk-out requests be divisible by the maxpacket size */
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
+ struct fsg_buffhd *bh, unsigned int length)
+{
+ unsigned int rem;
+
+ bh->bulk_out_intended_length = length;
+ rem = length % fsg->bulk_out_maxpacket;
+ if (rem > 0)
+ length += fsg->bulk_out_maxpacket - rem;
+ bh->outreq->length = length;
+}
+
+static struct fsg_dev *the_fsg;
+static struct usb_gadget_driver fsg_driver;
+
+static void close_backing_file(struct lun *curlun);
+static void close_all_backing_files(struct fsg_dev *fsg);
+
+/*-------------------------------------------------------------------------*/
+static int act_gadget_is_dualspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+#ifdef DUMP_MSGS
+
+static void dump_msg(struct fsg_dev *fsg, const char *label,
+ const u8 *buf, unsigned int length)
+{
+ if (length < 512) {
+ DBG(fsg, "%s, length %u:\n", label, length);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, length, 0);
+ }
+}
+
+static void dump_cdb(struct fsg_dev *fsg)
+{
+}
+
+#else
+
+static void dump_msg(struct fsg_dev *fsg, const char *label,
+ const u8 *buf, unsigned int length)
+{
+}
+
+#ifdef VERBOSE_DEBUG
+
+static void dump_cdb(struct fsg_dev *fsg)
+{
+ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+ 16, 1, fsg->cmnd, fsg->cmnd_size, 0);
+}
+
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{
+}
+
+#endif /* VERBOSE_DEBUG */
+#endif /* DUMP_MSGS */
+
+#define EP_STALL (1<<6)
+static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
+{
+ const char *name;
+
+ if (ep == fsg->bulk_in)
+ name = "bulk-in";
+ else if (ep == fsg->bulk_out)
+ name = "bulk-out";
+ else
+ name = ep->name;
+ DBG(fsg, "%s set halt\n", name);
+ return usb_ep_set_halt(ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Routines for unaligned data access */
+
+static u32 get_le32(u8 *buf)
+{
+ return ((u32) buf[3] << 24) | ((u32) buf[2] << 16) |
+ ((u32) buf[1] << 8) | ((u32) buf[0]);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand. Also the (static) config and interface
+ * descriptors are adjusted during fsg_bind().
+ */
+#define STRING_MANUFACTURER 1
+#define STRING_PRODUCT 2
+#define STRING_SERIAL 3
+#define STRING_CONFIG 4
+#define STRING_INTERFACE 5
+
+/* There is only one configuration. */
+#define CONFIG_VALUE 1
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+
+ /* The next three values can be overridden by module parameters */
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
+ .bcdDevice = __constant_cpu_to_le16(0x0100),
+
+ .iManufacturer = 0,
+ .iProduct = 0,
+ .iSerialNumber = 0,
+ .bNumConfigurations = 1,
+};
+
+static struct usb_config_descriptor config_desc = {
+ .bLength = sizeof config_desc,
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* wTotalLength computed by usb_gadget_config_buf() */
+ .bNumInterfaces = 1,
+ .bConfigurationValue = CONFIG_VALUE,
+ .iConfiguration = STRING_CONFIG,
+ /*.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ /*.bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, */
+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW,
+};
+
+static struct usb_otg_descriptor otg_desc = {
+ .bLength = sizeof(otg_desc),
+ .bDescriptorType = USB_DT_OTG,
+
+ .bmAttributes = USB_OTG_SRP,
+};
+
+/* There is only one interface. */
+
+static struct usb_interface_descriptor intf_desc = {
+ .bLength = sizeof intf_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bNumEndpoints = 2, /* Adjusted during fsg_bind() */
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0xff, /* Adjusted during fsg_bind() */
+ .bInterfaceProtocol = 0xff, /* Adjusted during fsg_bind() */
+ .iInterface = STRING_INTERFACE,
+};
+
+/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
+ * and interrupt-in. */
+
+static struct usb_endpoint_descriptor fs_bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ /* wMaxPacketSize set by autoconfiguration */
+};
+
+static struct usb_endpoint_descriptor fs_bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ /* wMaxPacketSize set by autoconfiguration */
+};
+
+static struct usb_endpoint_descriptor fs_intr_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(2),
+ .bInterval = 32, /* frames -> 32 ms */
+};
+
+static const struct usb_descriptor_header *fs_function[] = {
+ (struct usb_descriptor_header *)&otg_desc,
+ (struct usb_descriptor_header *)&intf_desc,
+ (struct usb_descriptor_header *)&fs_bulk_in_desc,
+ (struct usb_descriptor_header *)&fs_bulk_out_desc,
+ (struct usb_descriptor_header *)&fs_intr_in_desc,
+ NULL,
+};
+
+#define FS_FUNCTION_PRE_EP_ENTRIES 2
+
+/*
+ * USB 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ *
+ * That means alternate endpoint descriptors (bigger packets)
+ * and a "device qualifier" ... plus more construction options
+ * for the config descriptor.
+ */
+static struct usb_qualifier_descriptor dev_qualifier = {
+ .bLength = sizeof dev_qualifier,
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+
+ .bNumConfigurations = 1,
+};
+
+static struct usb_endpoint_descriptor hs_bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
+ .bInterval = 1, /* NAK every 1 uframe */
+};
+
+static struct usb_endpoint_descriptor hs_intr_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = __constant_cpu_to_le16(2),
+ .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static const struct usb_descriptor_header *hs_function[] = {
+ (struct usb_descriptor_header *)&otg_desc,
+ (struct usb_descriptor_header *)&intf_desc,
+ (struct usb_descriptor_header *)&hs_bulk_in_desc,
+ (struct usb_descriptor_header *)&hs_bulk_out_desc,
+ (struct usb_descriptor_header *)&hs_intr_in_desc,
+ NULL,
+};
+
+#define HS_FUNCTION_PRE_EP_ENTRIES 2
+
+/* Maxpacket and other transfer characteristics vary by speed. */
+static struct usb_endpoint_descriptor
+*ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor
+ *fs, struct usb_endpoint_descriptor
+ *hs)
+{
+ /* printk(KERN_INFO "act_gadget_is_dualspeed:0x%x.\n",
+ act_gadget_is_dualspeed(g));
+ printk(KERN_INFO "%d",
+ g->speed == USB_SPEED_HIGH); */
+ if (act_gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ {
+ printk("reutrn hs\n");
+ return hs;
+ }
+ printk("reutrn fs, 0x%x, 0x%x,0x%x\n",act_gadget_is_dualspeed(g),g->speed,USB_SPEED_HIGH );
+ return fs;
+}
+
+/* The CBI specification limits the serial string to 12 uppercase hexadecimal
+ * characters. */
+static char manufacturer[64];
+static char serial[13];
+module_param_string(iSerialNumber, serial, 13, S_IRUGO);
+
+/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
+static struct usb_string strings[] = {
+ {STRING_MANUFACTURER, manufacturer},
+ {STRING_PRODUCT, longname},
+ {STRING_SERIAL, serial},
+ {STRING_CONFIG, "Bus-powered"},
+ {STRING_INTERFACE, "Mass Storage"},
+ {}
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+int wait_adfus_proc(int probatch_phase)
+{
+ int ret;
+ while(1)
+ {
+ ret = is_probatch_phase(probatch_phase);
+ if(ret == 0)
+ {
+ break;
+ }
+ VLDBG("schedule_timeout 1000,ret:%d,probatch_phase:%s\n",ret, probatch_phase);
+ schedule_timeout_interruptible(msecs_to_jiffies(1000));
+ }
+
+ return ret;
+}
+
+unsigned int nand_part[MAX_PARTITION];
+mbr_info_t *mbr_info_buf;
+
+//typedef unsigned int (*func_t)(unsigned int *, mbr_info_t *);
+//extern func_t AdfuUpdateMbrFromPhyToUsr;
+//EXPORT_SYMBOL(AdfuUpdateMbrFromPhyToUsr);
+
+//typedef void (*func_t1)(void);
+//extern func_t1 adfu_flush_nand_cache;
+//EXPORT_SYMBOL(adfu_flush_nand_cache);
+
+//int adfus_register_func_cb(unsigned int func)
+//typedef int (*func_t4)(unsigned long, unsigned long , void *, struct uparam *);
+
+//extern func_t4 adfus_nand_read;
+//extern func_t4 adfus_nand_write;
+//EXPORT_SYMBOL(adfus_nand_read);
+//EXPORT_SYMBOL(adfus_nand_write);
+
+/*
+ * Config descriptors must agree with the code that sets configurations
+ * and with code managing interfaces and their altsettings. They must
+ * also handle different speeds and other-speed requests.
+ */
+static int populate_config_buf(struct usb_gadget *gadget,
+ u8 *buf, u8 type, unsigned index)
+{
+ enum usb_device_speed speed = gadget->speed;
+ int len;
+ const struct usb_descriptor_header **function;
+
+ if (index > 0)
+ return -EINVAL;
+
+ if (act_gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
+ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
+ if (act_gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
+ function = hs_function;
+ else
+ function = fs_function;
+
+ /* for now, don't advertise srp-only devices */
+ if (!gadget_is_otg(gadget))
+ function++;
+
+ len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
+ ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+ return len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* These routines may be called in process context or in_irq */
+
+/* Caller must hold fsg->lock */
+static void wakeup_thread(struct fsg_dev *fsg)
+{
+ /* Tell the main thread that something has happened */
+ fsg->thread_wakeup_needed = 1;
+ if (fsg->thread_task)
+ wake_up_process(fsg->thread_task);
+}
+
+static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
+{
+ unsigned long flags;
+
+ /* Do nothing if a higher-priority exception is already in progress.
+ * If a lower-or-equal priority exception is in progress, preempt it
+ * and notify the main thread by sending it a signal. */
+ spin_lock_irqsave(&fsg->lock, flags);
+ if (fsg->state <= new_state) {
+ fsg->exception_req_tag = fsg->ep0_req_tag;
+ fsg->state = new_state;
+ if (fsg->thread_task) {
+ send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+ fsg->thread_task);
+ }
+ }
+ spin_unlock_irqrestore(&fsg->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The disconnect callback and ep0 routines. These always run in_irq,
+ * except that ep0_queue() is called in the main thread to acknowledge
+ * completion of various requests: set config, set interface, and
+ * Bulk-only device reset. */
+
+static void fsg_disconnect(struct usb_gadget *gadget)
+{
+ struct fsg_dev *fsg = get_gadget_data(gadget);
+
+ DBG(fsg, "disconnect or port reset\n");
+ raise_exception(fsg, FSG_STATE_DISCONNECT);
+}
+
+static int ep0_queue(struct fsg_dev *fsg)
+{
+ int rc;
+
+ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
+ if (rc != 0 && rc != -ESHUTDOWN) {
+
+ /* We can't do much more than wait for a reset */
+ WARNING(fsg, "error in submission: %s --> %d\n",
+ fsg->ep0->name, rc);
+ }
+ return rc;
+}
+
+static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct fsg_dev *fsg = ep->driver_data;
+
+ if (req->actual > 0)
+ dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
+ if (req->status || req->actual != req->length)
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual, req->length);
+ if (req->status == -ECONNRESET) /* Request was cancelled */
+ usb_ep_fifo_flush(ep);
+
+ if (req->status == 0 && req->context)
+ ((fsg_routine_t) (req->context)) (fsg);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Bulk and interrupt endpoint completion handlers.
+ * These always run in_irq. */
+
+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct fsg_dev *fsg = ep->driver_data;
+ //struct lun *curlun = fsg->curlun;
+ //dev_t media_dev_t = curlun->devnum;
+ //struct block_device *bdev_back;
+ struct fsg_buffhd *bh = req->context;
+
+ //bdev_back = bdget(media_dev_t);
+
+ if (req->status || req->actual != req->length)
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual, req->length);
+ if (req->status == -ECONNRESET) /* Request was cancelled */
+ usb_ep_fifo_flush(ep);
+ /* Hold the lock while we update the request and buffer states */
+ smp_wmb();
+ spin_lock(&fsg->lock);
+ bh->inreq_busy = 0;
+ bh->state = BUF_STATE_EMPTY;
+ wakeup_thread(fsg);
+ spin_unlock(&fsg->lock);
+
+ /* when adfu upgrade successful, disconnect and sync */
+ if (unlikely(adfu_success_flag == 1)) {
+ //adfu_flush_nand_cache();
+ printk(KERN_INFO "UPGRADE SUCCESSFULLY\n");
+ raise_exception(fsg, FSG_STATE_DISCONNECT);
+ }
+
+}
+
+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
+
+ dump_msg(fsg, "bulk-out", req->buf, req->actual);
+ if (req->status || req->actual != bh->bulk_out_intended_length)
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
+ req->status, req->actual, bh->bulk_out_intended_length);
+ if (req->status == -ECONNRESET) /* Request was cancelled */
+ usb_ep_fifo_flush(ep);
+
+ /* Hold the lock while we update the request and buffer states */
+ smp_wmb();
+ spin_lock(&fsg->lock);
+ bh->outreq_busy = 0;
+ bh->state = BUF_STATE_FULL;
+ wakeup_thread(fsg);
+ spin_unlock(&fsg->lock);
+}
+
+static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Ep0 class-specific handlers. These always run in_irq. */
+
+static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+}
+
+static int class_setup_req(struct fsg_dev *fsg,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_request *req = fsg->ep0req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ if (!fsg->config)
+ return value;
+
+ /* Handle Bulk-only class-specific requests */
+ if (transport_is_bbb()) {
+ switch (ctrl->bRequest) {
+
+ case USB_BULK_RESET_REQUEST:
+ /* printk(KERN_INFO "****USB_BULK_RESET_REQUEST****\n"); */
+ if (ctrl->bRequestType != (USB_DIR_OUT |
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ break;
+ if ((w_index != 0) || (w_value != 0)
+ || (w_length !=0)) {
+ value = -EDOM;
+ break;
+ }
+
+ /* Raise an exception to stop the current operation
+ * and reinitialize our state. */
+ DBG(fsg, "bulk reset request\n");
+ raise_exception(fsg, FSG_STATE_RESET);
+ value = DELAYED_STATUS;
+ break;
+
+ case USB_BULK_GET_MAX_LUN_REQUEST:
+ /* printk(KERN_INFO
+ "****USB_BULK_GET_MAX_LUN_REQUEST****\n"); */
+ if (ctrl->bRequestType != (USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ break;
+ if ((w_index != 0) || (w_value != 0)
+ || (w_length !=1)) {
+ value = -EDOM;
+ break;
+ }
+ VDBG(fsg, "get max LUN\n");
+ *(u8 *) req->buf = fsg->nluns - 1;
+ value = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Handle CBI class-specific requests */
+ else {
+ switch (ctrl->bRequest) {
+
+ case USB_CBI_ADSC_REQUEST:
+ if (ctrl->bRequestType != (USB_DIR_OUT |
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE))
+ break;
+ if (w_index != 0 || w_value != 0) {
+ value = -EDOM;
+ break;
+ }
+ if (w_length > MAX_COMMAND_SIZE) {
+ value = -EOVERFLOW;
+ break;
+ }
+ value = w_length;
+ fsg->ep0req->context = received_cbi_adsc;
+ break;
+ }
+ }
+
+ if (value == -EOPNOTSUPP)
+ VDBG(fsg,
+ "unknown class-specific control req "
+ "%02x.%02x v%04x i%04x l%u\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ le16_to_cpu(ctrl->wValue), w_index, w_length);
+ return value;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Ep0 standard request handlers. These always run in_irq. */
+
+static int standard_setup_req(struct fsg_dev *fsg,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_request *req = fsg->ep0req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ /* Usually this just stores reply data in the pre-allocated ep0 buffer,
+ * but config change events will also reconfigure hardware. */
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ /* printk(KERN_INFO "****USB_REQ_GET_DESCRIPTOR_\n");*/
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE)) {
+ printk("DING!!\n");
+ break;
+ }
+ switch (w_value >> 8) {
+
+ case USB_DT_DEVICE:
+ /* printk(KERN_INFO "**** GET_DEVICE_DESC ****\n"); */
+ VDBG(fsg, "get device descriptor\n");
+ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
+ value = sizeof device_desc;
+ memcpy(req->buf, &device_desc, value);
+ break;
+ case USB_DT_DEVICE_QUALIFIER:
+ /* printk(KERN_INFO "QUALIFIER****\n"); */
+ VDBG(fsg, "get device qualifier\n");
+ if (!act_gadget_is_dualspeed(fsg->gadget))
+ break;
+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+ value = sizeof dev_qualifier;
+ memcpy(req->buf, &dev_qualifier, value);
+ break;
+
+ case USB_DT_OTHER_SPEED_CONFIG:
+ /* printk(KERN_INFO "OTHER_SPEED_CONFIG****\n"); */
+ VDBG(fsg, "get other-speed config descriptor\n");
+ if (!act_gadget_is_dualspeed(fsg->gadget))
+ break;
+ goto get_config;
+ case USB_DT_CONFIG:
+ /* printk(KERN_INFO "DT_CONFIG****\n"); */
+ VDBG(fsg, "get configuration descriptor\n");
+get_config:
+ value = populate_config_buf(fsg->gadget,
+ req->buf,
+ w_value >> 8,
+ w_value & 0xff);
+ break;
+
+ case USB_DT_STRING:
+ /* printk(KERN_INFO "DT_STRING****\n"); */
+ VDBG(fsg, "get string descriptor\n");
+
+ /* wIndex == language code */
+ value = usb_gadget_get_string(&stringtab,
+ w_value & 0xff, req->buf);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ /* One config, two speeds */
+ case USB_REQ_SET_CONFIGURATION:
+ /* printk(KERN_INFO "****USB_REQ_SET_CONFIGURATION****\n"); */
+ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ VDBG(fsg, "set configuration\n");
+ if (w_value == CONFIG_VALUE || w_value == 0) {
+ /* printk(KERN_INFO
+ "The w_value is 0x%x.\n",w_value); */
+ fsg->new_config = w_value;
+
+ /* Raise an exception to wipe out previous transaction
+ * state (queued bufs, etc) and set the new config. */
+ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
+ /* wakeup_thread(fsg);
+ wakeup_thread(fsg);
+ handle_exception(fsg); */
+ /* wakeup_thread(fsg); */
+ value = DELAYED_STATUS;
+ }
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ /* printk(KERN_INFO "****USB_REQ_GET_CONFIGUATION****\n"); */
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ VDBG(fsg, "get configuration\n");
+ *(u8 *) req->buf = fsg->config;
+ value = 1;
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ /* printk(KERN_INFO "****USB_REQ_SET_INTERFACE****\n"); */
+ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_INTERFACE))
+ break;
+ if (fsg->config && w_index == 0) {
+
+ /* Raise an exception to wipe out previous transaction
+ * state (queued bufs, etc) and install the new
+ * interface altsetting. */
+ raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
+ value = DELAYED_STATUS;
+ }
+ break;
+ case USB_REQ_GET_INTERFACE:
+ /* printk(KERN_INFO "****USB_REQ_GET_INTERFACE****\n"); */
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+ USB_RECIP_INTERFACE))
+ break;
+ if (!fsg->config)
+ break;
+ if (w_index != 0) {
+ value = -EDOM;
+ break;
+ }
+ VDBG(fsg, "get interface\n");
+ *(u8 *) req->buf = 0;
+ value = 1;
+ break;
+
+ default:
+ printk("unknown control req %02x.%02x v%04x i%04x l%u\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, le16_to_cpu(ctrl->wLength));
+ /* printk(KERN_INFO "*****UNKNOWN_CONTROL_REQ*****.\n"); */
+ }
+ return value;
+}
+
+static int fsg_setup(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct fsg_dev *fsg = get_gadget_data(gadget);
+ int rc;
+ int w_length = le16_to_cpu(ctrl->wLength);
+
+ ++fsg->ep0_req_tag; /* Record arrival of a new request */
+ fsg->ep0req->context = NULL;
+ fsg->ep0req->length = 0;
+ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
+
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ rc = class_setup_req(fsg, ctrl);
+ else
+ rc = standard_setup_req(fsg, ctrl);
+
+ /* Respond with data/status or defer until later? */
+ if (rc >= 0 && rc != DELAYED_STATUS) {
+ rc = min(rc, w_length);
+ fsg->ep0req->length = rc;
+ fsg->ep0req->zero = rc < w_length;
+ fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
+ "ep0-in" : "ep0-out");
+ rc = ep0_queue(fsg);
+ }
+
+ /* Device either stalls (rc < 0) or reports success */
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* All the following routines run in process context */
+
+/* Use this for bulk or interrupt transfers, not ep0 */
+static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
+ struct usb_request *req, int *pbusy,
+ enum fsg_buffer_state *state)
+{
+ int rc;
+ unsigned long flag;
+
+ if (ep == fsg->bulk_in)
+ dump_msg(fsg, "bulk-in", req->buf, req->length);
+ else if (ep == fsg->intr_in)
+ dump_msg(fsg, "intr-in", req->buf, req->length);
+ spin_lock_irqsave(&fsg->lock, flag);
+ *pbusy = 1;
+ *state = BUF_STATE_BUSY;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+ rc = usb_ep_queue(ep, req, GFP_KERNEL);
+ if (rc != 0) {
+ printk(KERN_INFO "usb_ep_queue error !!!\n");
+ *pbusy = 0;
+ *state = BUF_STATE_EMPTY;
+
+ /* We can't do much more than wait for a reset */
+
+ /* Note: currently the net2280 driver fails zero-length
+ * submissions if DMA is enabled. */
+ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
+ req->length == 0))
+ WARNING(fsg, "error in submission: %s --> %d\n",
+ ep->name, rc);
+ }
+
+ return;
+}
+
+static int sleep_thread(struct fsg_dev *fsg)
+{
+ int rc = 0;
+
+ /* Wait until a signal arrives or we are woken up */
+ for (;;) {
+ try_to_freeze();
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (signal_pending(current)) {
+ rc = -EINTR;
+ break;
+ }
+ if (fsg->thread_wakeup_needed)
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+ fsg->thread_wakeup_needed = 0;
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+#if 0
+static int do_ADFU_rdrootfs(struct fsg_dev *fsg)
+{
+ struct lun *curlun = fsg->curlun;
+ dev_t media_dev_t;
+ struct block_device *bdev_back;
+ struct gendisk *disk;
+
+ u32 lba;
+ struct fsg_buffhd *bh;
+ int rc;
+ u32 amount_left;
+ loff_t file_offset, file_offset_tmp;
+ struct uparam rd_param;
+ unsigned int amount;
+ ssize_t nread;
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+
+ lba = get_le32(&fsg->cmnd[5]);
+#if 0
+ if (lba >= curlun->num_sectors) {
+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+#endif
+ rd_param.flash_partition = fsg->cmnd[3];
+ rd_param.devnum_in_phypart = fsg->cmnd[4];
+
+ /* Carry out the file reads */
+ file_offset = lba;
+ amount_left = fsg->data_size_from_cmnd;
+
+ if (unlikely(amount_left == 0))
+ {
+ //printk("return:%d\n",__LINE__);
+ return -EIO; /* No default reply */
+ }
+
+ for (;;) {
+
+ /* Figure out how much we need to read:
+ * Try to read the remaining amount.
+ * But don't read more than the buffer size.
+ * And don't try to read past the end of the file.
+ * Finally, if we're not at a page boundary, don't read past
+ * the next page.
+ * If this means reading 0 then we were asked to read past
+ * the end of file. */
+ amount = min((unsigned int)amount_left, mod_data.buflen);
+ /*
+ amount = min((loff_t) amount,
+ curlun->file_length - file_offset);
+ partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
+ if (partial_page > 0)
+ amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
+ partial_page);
+ */
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ {
+ //printk("return:%d\n",__LINE__);
+ return rc;
+ }
+ }
+
+ /* If we were asked to read past the end of file,
+ * end with an empty buffer. */
+ /*
+ if (amount == 0) {
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = file_offset;
+ curlun->info_valid = 1;
+ bh->inreq->length = 0;
+ bh->state = BUF_STATE_FULL;
+ break;
+ }
+ */
+ /* Perform the read */
+ amount = amount << 9; /* unit by sector */
+ file_offset_tmp = file_offset;
+ media_dev_t = curlun->devnum;
+ bdev_back = bdget(media_dev_t);
+ disk = bdev_back->bd_disk;
+ //nread = disk->fops->adfu_read(file_offset, amount,
+ // bh->buf, &rd_param);
+ nread = vfs_read(curlun->filp,
+ (char __user *)bh->buf,
+ amount, &file_offset_tmp);
+
+#if 0
+ nread = vfs_read(curlun->filp,
+ (char __user *)bh->buf,
+ amount, &file_offset_tmp);
+#endif
+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+ (unsigned long long)file_offset, (int)nread);
+ if (signal_pending(current)) {
+ bdput(bdev_back);
+ //printk("return:%d\n",__LINE__);
+ return -EINTR;
+ }
+ if (nread < 0) {
+ LDBG(curlun, "error in file read: %d\n", (int)nread);
+ nread = 0;
+ } else if (nread < amount) {
+ LDBG(curlun, "partial file read: %d/%u\n",
+ (int)nread, amount);
+ }
+ file_offset += nread;
+ amount_left -= (((unsigned int)nread) << 9);
+ fsg->residue -= (((unsigned int)nread) << 9);
+ bh->inreq->length = (((unsigned int)nread) << 9);
+ bh->state = BUF_STATE_FULL;
+
+ /* If an error occurred, report it and its position */
+ if (nread < amount) {
+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+ curlun->sense_data_info = file_offset;
+ curlun->info_valid = 1;
+ break;
+ }
+
+ if (amount_left == 0)
+ break; /* No more left to read */
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ }
+ no_finish_reply = 0; /* the last buf has not been transfered,
+ move it into finish_reply() */
+ bdput(bdev_back);
+ //printk("return:%d\n",__LINE__);
+ return -EIO; /* No default reply */
+}
+#endif
+static int get_udisk_size(struct lun *curlun, const char *filename)
+{
+ int ro;
+ struct file *filp = NULL;
+ int rc = -EINVAL;
+ struct inode *inode = NULL;
+ loff_t size;
+ loff_t num_sectors;
+
+ /* R/W if we can, R/O if we must */
+ ro = curlun->ro;
+ if (!ro) {
+ filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
+ if (-EROFS == PTR_ERR(filp))
+ ro = 1;
+ }
+ if (ro)
+ filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ LINFO(curlun, "unable to open backing file: %s\n", filename);
+ return PTR_ERR(filp);
+ }
+
+ if (!(filp->f_mode & FMODE_WRITE))
+ ro = 1;
+
+ if (filp->f_path.dentry)
+ inode = filp->f_path.dentry->d_inode;
+ if (inode && S_ISBLK(inode->i_mode)) {
+ if (bdev_read_only(inode->i_bdev))
+ ro = 1;
+ } else if (!inode || !S_ISREG(inode->i_mode)) {
+ LINFO(curlun, "invalid file type: %s\n", filename);
+ goto out;
+ }
+
+ /* If we can't read the file, it's no good.
+ * If we can't write the file, use it read-only. */
+ if (!filp->f_op || !(filp->f_op->read || filp->f_op->read_iter)) {
+ LINFO(curlun, "file not readable: %s\n", filename);
+ goto out;
+ }
+ if (!(filp->f_op->write || filp->f_op->write_iter))
+ ro = 1;
+
+ size = i_size_read(inode->i_mapping->host);
+ if (size < 0) {
+ LINFO(curlun, "unable to find file size: %s\n", filename);
+ rc = (int)size;
+ goto out;
+ }
+ num_sectors = size >> 9; /* File size in 512-byte sectors */
+ if (num_sectors == 0) {
+ LINFO(curlun, "file too small: %s\n", filename);
+ rc = -ETOOSMALL;
+ goto out;
+ }
+
+ get_file(filp);
+
+ curlun->devnum = filp->f_path.dentry->d_inode->i_rdev;
+
+ curlun->ro = ro;
+ curlun->filp = filp;
+ curlun->file_length = size;
+ curlun->num_sectors = num_sectors;
+ LDBG(curlun, "open backing file: %s\n", filename);
+ rc = 0;
+
+out:
+ filp_close(filp, current->files);
+ return rc;
+}
+static int do_ADFU_check_partition(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh;
+ int rc, ret;
+ loff_t file_offset_byte;
+ u32 amount_left;
+ unsigned int amount;
+ ssize_t nread;
+ unsigned int tmp;
+ struct file *f_filp;
+ struct lun *curlun = fsg->curlun;
+ int rc2 = -EINVAL;
+ char buf[4];
+ int size = 1;
+
+ if(cmnd_sequence_first_flag) //wait insmod flash
+ {
+ set_probatch_phase(PROBATCH_INSTAL_FLASH);
+ wait_adfus_proc(PROBATCH_FINISH_INSTALL_FLASH);//sync with upgrade_app
+ cmnd_sequence_first_flag = 0;
+ check_partition_flag = 0;
+ // add by lty
+ f_filp = filp_open("/usr/flash_check", O_RDONLY, 0644);
+ if ( f_filp != NULL ) { //
+ file_offset_byte = 0;
+ buf[0] = 0;
+ ret = vfs_read(f_filp, buf, 2, &file_offset_byte);
+ filp_close(f_filp, current->files);
+ if ( buf[0] != '0' ) {
+ check_partition_flag = buf[0]-'0';
+ check_partition_flag = -check_partition_flag;
+ }
+ printk("read install flash return ret=%d, val=%d, flag=%d\n",ret, buf[0], check_partition_flag);
+
+ } else {
+ printk("open /usr/flash_check fail\n");
+ }
+ rc2=get_udisk_size(curlun, "/dev/actk");
+ if(rc2 != 0)
+ {
+ VLDBG("open /dev/actk error:%d\n",__LINE__);
+ /*return rc2;*/
+ }
+ size = (int)curlun->num_sectors;
+ printk("##udisk size:%d 0x%x\n",size,size);
+ }
+
+ amount_left = fsg->data_size_from_cmnd;
+
+ if (unlikely(amount_left == 0))
+ {
+ return -EIO; /* No default reply */
+ }
+
+ for (;;) {
+ amount = (unsigned int)amount_left;
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ {
+ return rc;
+ }
+ }
+ /* Perform the read */
+ memset((char *)bh->buf, 0, amount);
+ if(check_partition_flag < 0)
+ {
+ tmp = (unsigned int)bh->buf;
+ writel(-check_partition_flag, (volatile void *)tmp);
+ }
+
+ //add partition cap info
+ memcpy((unsigned char *)((unsigned int)bh->buf + 0x10), (unsigned char *)&size, sizeof(unsigned int));
+ nread = amount;
+
+ amount_left -= (unsigned int)nread;
+ fsg->residue -= (unsigned int)nread;
+ bh->inreq->length = (unsigned int)nread;
+ bh->state = BUF_STATE_FULL;
+
+ if (amount_left == 0)
+ break; /* No more left to read */
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ }
+ no_finish_reply = 0; /* the last buf has not been transfered,
+ move it into finish_reply() */
+
+ return -EIO; /* No default reply */
+}
+
+#define FLASH_READ_BUF_SECTORS (32)
+#define FLASH_READ_BUF_SIZE (FLASH_READ_BUF_SECTORS*512)
+unsigned int image_sectors, check_image_sectors;
+struct uparam read_param;
+
+#if 0
+static int do_ADFU_check_image_checksum(struct fsg_dev *fsg)
+{
+ /*struct lun *curlun = fsg->curlun;*/
+ struct fsg_buffhd *bh;
+ int rc;
+ u32 amount_left;
+ unsigned int amount;
+ ssize_t nread;
+
+ int read_err=0;
+ unsigned int tmp;
+ unsigned int file_offset=0,read_sectors=0;
+ void *buf ;
+
+ //Don't check phy_boot_partition
+ if(read_param.flash_partition == 0)
+ {
+ goto finish_check;
+ }
+
+ read_param.flash_partition -= 1;
+ read_param.devnum_in_phypart -= 1;
+
+ buf= kmalloc(FLASH_READ_BUF_SIZE, GFP_KERNEL);
+
+ for(;;)
+ {
+ if(check_image_sectors == 0)
+ {
+ break;
+ }
+ if(check_image_sectors>FLASH_READ_BUF_SECTORS)
+ {
+ read_sectors = FLASH_READ_BUF_SECTORS;
+ }
+ else
+ {
+ read_sectors = check_image_sectors;
+ }
+
+// printk("nand_read:0x%x,0x%x,%d,%d\n", file_offset, read_sectors, read_param.flash_partition, read_param.devnum_in_phypart);
+ read_err = adfus_nand_read(file_offset, read_sectors,
+ buf, &read_param);
+ //read_err = vfs_read(curlun->filp, buf, read_sectors << 9, &file_offset);
+ if(read_err < 0)
+ {
+ break;
+ }
+ file_offset += read_sectors;
+ check_image_sectors -= read_sectors;
+ }
+
+ kfree(buf);
+ buf=NULL;
+
+finish_check:
+
+ amount_left = fsg->data_size_from_cmnd;
+
+ if (unlikely(amount_left == 0))
+ {
+ return -EIO; /* No default reply */
+ }
+
+ for (;;) {
+ amount = (unsigned int)amount_left;
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ {
+ return rc;
+ }
+ }
+ /* Perform the read */
+ memset((char *)bh->buf, 0, amount);
+ if(read_err < 0)
+ {
+ tmp = (unsigned int)bh->buf;
+ writel(1,(volatile void *)tmp);
+ }
+ nread = amount;
+
+ amount_left -= (unsigned int)nread;
+ fsg->residue -= (unsigned int)nread;
+ bh->inreq->length = (unsigned int)nread;
+ bh->state = BUF_STATE_FULL;
+
+ if (amount_left == 0)
+ break; /* No more left to read */
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ }
+ no_finish_reply = 0; /* the last buf has not been transfered,
+ move it into finish_reply() */
+ return -EIO; /* No default reply */
+}
+#endif
+
+int do_ADFU_INFO(struct fsg_dev *fsg)
+{
+ int ret=0;
+ struct timeval tv1,tv2;
+
+ switch(fsg->cmnd[2])
+ {
+ case 0x20:
+ ret = do_ADFU_check_partition(fsg);
+ break;
+ case 0x21:
+ do_gettimeofday(&tv1);
+ //ret = do_ADFU_check_image_checksum(fsg);
+ do_gettimeofday(&tv2);
+ printk("do_ADFU_check_image_checksum,timing:%ds\n",(int)(tv2.tv_sec-tv1.tv_sec));
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int write_ram_bin(u32 addr, char *buf, u32 len)
+{
+ int ret=0;
+ char ram_bin_name[64];
+ static struct file *ram_bin_filp;
+ loff_t file_offset_byte;
+ static int off_set;
+ int i;
+ char p[32];
+ int j,num1,num2;
+ num1=0;
+ num2=0;
+
+ if ( buf == NULL ) {
+ if ( ram_bin_filp != NULL ) {
+ filp_close(ram_bin_filp, current->files);
+ printk("write_ram_bin, finished, len=0x%x\n", off_set);
+ ram_bin_filp = NULL;
+ }
+ return 0;
+ }
+
+ memset(ram_bin_name, 0, 64);
+ strcpy(ram_bin_name, "/usr/");
+
+ if(addr == 0x21340000)
+ {
+ strcat(ram_bin_name, "mbrec.bin");
+ }
+ else if(addr == 0x21340001)
+ {
+ strcat(ram_bin_name, "oem.ko");
+ }
+ else if(addr == 0x21350000)
+ {
+ printk("receive afinfo_name \n");
+ j=0;
+ for (i=0;i<32;i++)
+ {
+ afinfo_name[i]= readw((volatile void *)buf+i*2);
+ if( afinfo_name[i] == '.')
+ {
+ if(j==0)
+ {
+ num1=i;
+ j++;
+ }
+ else
+ {
+ num2=i;
+ }
+ }
+
+ }
+ printk("afinfo_name:%s\n", afinfo_name);
+ printk("num1=%d, num2=%d\n", num1,num2);
+ if (num1==num2)
+ {
+ strcpy(mbrc_name,"nand-boot.bin");
+ }
+ else
+ {
+ for(i=num1+1,j=0;i<num2;i++,j++)
+ {
+ p[j]=afinfo_name[i];
+ }
+ p[j]='\0';
+ strcpy(mbrc_name,"nand-boot.");
+ strcat(mbrc_name,p);
+ strcat(mbrc_name,".bin");
+ }
+ printk("mbrc_name:%s\n", mbrc_name);
+ return 0;
+ }
+ else if(addr == 0x32140000)
+ {
+ strcat(ram_bin_name, "mbr_info.bin");
+ mbr_info_buf = kmalloc(1024, GFP_KERNEL);
+ memcpy(mbr_info_buf, buf, len);
+ need_format = readb((volatile void *)buf + 0x04);
+ printk("need_format:%d\n", need_format);
+ }
+ else if (addr == 0x32170000) { //checksum_system.bin
+ system_checksum = readl((volatile void *)buf);
+ printk("system checksum: 0x%08X\n", system_checksum);
+ return 0;
+ }
+ else if (addr == 0x32160000) { //checksum_recovery.bin
+ recovery_checksum = readl((volatile void *)buf);
+ printk("recovery checksum: 0x%08X\n", recovery_checksum);
+ return 0;
+ }
+ else if (addr == 0x32150000) { //checksum_misc.bin
+ misc_checksum = readl((volatile void *)buf);
+ printk("misc checksum: 0x%08X\n", misc_checksum);
+ return 0;
+ }
+ else
+ {
+ strcat(ram_bin_name, "afinfo.bin");
+ printk("need_checksum:%d\n", need_checksum);
+ need_format = readb((volatile void *)buf + 0x10);
+ need_restart = readb((volatile void *)buf + 0x11);
+ need_checksum = readb((volatile void *)buf + 0x09);
+ printk("need_format:%d\n", need_format);
+ printk("need_restart:%d\n", need_restart);
+ printk("need_checksum:%d\n", need_checksum);
+ }
+ printk("addr:0x%x, ram_bin_name:%s, len=0x%x\n", addr, ram_bin_name, len);
+
+ if(!ram_bin_filp)
+ {
+ off_set = 0;
+ ram_bin_filp = filp_open(ram_bin_name, O_WRONLY|O_CREAT, 0700);
+ if(!ram_bin_filp)
+ {
+ printk("fail to creat %s,errno:%p\n", ram_bin_name, ram_bin_filp);
+ ret = -1;
+ goto out;
+ }
+ else
+ {
+ printk("creat %s,filp:%p\n", ram_bin_name, ram_bin_filp);
+ }
+ }
+ file_offset_byte = off_set;
+ ret = vfs_write(ram_bin_filp, buf, len, &file_offset_byte);
+ printk("wr:len=0x%x, ret=0x%x, of=0x%x\n", len,ret,off_set);
+ off_set += ret;
+out:
+ return ret;
+}
+
+static int do_ADFU_access_iram(struct fsg_dev *fsg)
+{
+ struct lun *curlun = fsg->curlun;
+ struct fsg_buffhd *bh;
+ int get_some_more;
+ u32 amount_left_to_req, amount_left_to_write,download_addr;
+
+ unsigned int amount;
+ ssize_t nwritten;
+ int rc;
+
+ if (curlun->ro) {
+ curlun->sense_data = SS_WRITE_PROTECTED;
+ printk("return:%d\n",__LINE__);
+ return -EINVAL;
+ }
+
+ download_addr = get_le32(&fsg->cmnd[9]);
+ /* Carry out the file writes */
+ get_some_more = 1;
+ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
+
+ printk("write ram len=0x%x\n", amount_left_to_req);
+ while (amount_left_to_write > 0) {
+
+ /* Queue a request for more data from the host */
+ bh = fsg->next_buffhd_to_fill;
+ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+ /* Figure out how much we want to get:
+ * Try to get the remaining amount.
+ * But don't get more than the buffer size.
+ * And don't try to go past the end of the file.
+ * If we're not at a page boundary,
+ * don't go past the next page.
+ * If this means getting 0, then we were asked
+ * to write past the end of file.
+ * Finally, round down to a block boundary. */
+ amount = min(amount_left_to_req, mod_data.buflen);
+
+
+ /* Get the next buffer */
+ fsg->usb_amount_left -= amount;
+ amount_left_to_req -= amount;
+ if (amount_left_to_req == 0)
+ get_some_more = 0;
+
+ /* Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
+ */
+ set_bulk_out_req_length(fsg, bh, amount);
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ continue;
+ }
+
+ /* Write the received data to the backing file */
+ bh = fsg->next_buffhd_to_drain;
+ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+ {
+ VLDBG("break:%d,bh->state:%d, BUF_STATE_EMPTY:%d\n",__LINE__, bh->state, BUF_STATE_EMPTY);
+ break; /* We stopped early */
+ }
+
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+ fsg->next_buffhd_to_drain = bh->next;
+ bh->state = BUF_STATE_EMPTY;
+
+ /* Did something go wrong with the transfer? */
+ if (bh->outreq->status != 0) {
+ curlun->sense_data = SS_COMMUNICATION_FAILURE;
+ curlun->info_valid = 1;
+ VLDBG("break:%d,bh->outreq->status:%d\n",__LINE__, bh->outreq->status);
+ break;
+ }
+
+ amount = bh->outreq->actual; /* unit by sector */
+
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+ //amount = round_down(amount, curlun->blksize);
+ /* Perform the write */
+ nwritten = write_ram_bin(download_addr, bh->buf, amount);
+ if(nwritten >= 0)
+ {
+ nwritten = amount;
+ }
+
+ if (signal_pending(current)) {
+ printk("return:%d\n",__LINE__);
+ return -EINTR; /* Interrupted! */
+ }
+ if (nwritten < 0) {
+ LDBG(curlun, "error in file write: %d\n",
+ (int)nwritten);
+ nwritten = 0;
+ } else if (nwritten < amount) {
+ LDBG(curlun, "partial file write: %d/%u\n",
+ (int)nwritten, amount);
+ /* Round down to a block */
+ }
+ amount_left_to_write -= nwritten;
+ fsg->residue -= nwritten;
+
+ /* If an error occurred, report it and its position */
+ if (nwritten < amount) {
+ curlun->sense_data = SS_WRITE_ERROR;
+ curlun->info_valid = 1;
+ VLDBG("break:%d\n",__LINE__);
+ break;
+ }
+
+ /* Did the host decide to stop early? */
+ if (bh->outreq->actual != bh->outreq->length) {
+ fsg->short_packet_received = 1;
+ VLDBG("break:%d\n",__LINE__);
+ break;
+ }
+ continue;
+ }
+ else
+ {
+ VLDBG("break:%d,bh->state:%d\n",__LINE__, bh->state);
+ }
+
+ /* Wait for something to happen */
+ rc = sleep_thread(fsg);
+ if (rc) {
+ printk("return:%d\n",__LINE__);
+ return rc;
+ }
+ }
+ if(amount_left_to_write == 0) {
+ printk("write ram finished:\n");
+ write_ram_bin(0, NULL, 0); // finshed
+ }
+ no_finish_reply = 1;
+ printk("return:%d\n",__LINE__);
+ return -EIO; /* No default reply */
+}
+
+char write_file_name[32];
+struct file *write_file_fp = NULL;
+loff_t pos = 0;
+static int do_ADFU_wtrootfs(struct fsg_dev *fsg)
+{
+ struct lun *curlun = fsg->curlun;
+ u32 lba;
+ struct fsg_buffhd *bh;
+ int get_some_more;
+ u32 amount_left_to_req, amount_left_to_write;
+ loff_t usb_offset, file_offset, file_offset_tmp;
+ struct uparam wt_param;
+ unsigned int amount;
+ ssize_t nwritten;
+ int rc;
+ char op_type;
+ int fs_len;
+ int i, error;
+
+
+ if (curlun->ro) {
+ curlun->sense_data = SS_WRITE_PROTECTED;
+ printk("return:%d\n",__LINE__);
+ return -EINVAL;
+ }
+
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+ lba = get_le32(&fsg->cmnd[9]);
+ wt_param.flash_partition = fsg->cmnd[2] & ~0x80;
+ wt_param.devnum_in_phypart = fsg->cmnd[2] & ~0x80;
+
+ if(wt_param.flash_partition == 0x0 || wt_param.flash_partition == 0x1)
+ {
+ if (!write_file_fp)
+ {
+ //unit of probatch tool download img is 10MB
+ if (wt_param.flash_partition == 0x0 ) {
+ printk("write mbrec.bin\n");
+ strcpy(write_file_name, "/tmp/mbrec.bin");
+ } else {
+ printk("write uboot.bin\n");
+ strcpy(write_file_name, "/tmp/uboot.bin");
+ }
+ write_file_fp = filp_open(write_file_name, O_RDWR | O_CREAT, 0644);
+ printk("boot:%s\n", write_file_name);
+ update_phy_boot = 1;
+ }
+
+ } else {
+ //if(wt_param.flash_partition != UDISK_ACCESS)
+ //{
+ wt_param.flash_partition -= 2;
+ wt_param.devnum_in_phypart -= 2;
+ //}
+ printk("flash_partition:%d, devnum_in_phypart:%d\n", wt_param.flash_partition, wt_param.devnum_in_phypart);
+ sprintf(format_disk_name, "/dev/act%c", 'a'+wt_param.flash_partition);
+ printk("disk_name = %s\n", format_disk_name);
+ }
+
+
+ op_type = fsg->cmnd[3];
+ if(op_type == 1)
+ {
+ fs_len = fsg->cmnd[4];
+ memcpy(format_fs_name, &(fsg->cmnd[5]), fs_len);
+ format_fs_name[fs_len]=0;
+ for(i=0; i<fs_len; i++)
+ {
+ format_fs_name[i] = tolower(format_fs_name[i]);
+ }
+ //sprintf(format_disk_name, "/dev/act%c", 'a'+wt_param.flash_partition);
+ if ( wt_param.flash_partition >=3 && wt_param.flash_partition < 6 )
+ format_disk_label = disk_label[wt_param.flash_partition-3];
+ else
+ format_disk_label = disk_label[3];
+ printk("format:fs_name:%s, disk_name:%s, disk_label:%s\n", format_fs_name, format_disk_name, format_disk_label);
+
+ set_probatch_phase(PROBATCH_FORMAT);
+ wait_adfus_proc(PROBATCH_FINISH_FORMAT);//sync with upgrade_app
+ goto out;
+ }
+
+ /* Carry out the file writes */
+ get_some_more = 1;
+ usb_offset = ((loff_t) lba) << 9;
+ file_offset = lba; /* unit by sector */
+ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
+ printk("w(sector):len=0x%x, offset=0x%x\n", amount_left_to_write, lba);
+ /*changed by liyong, to add a file operation to write flash*/
+ if(!write_file_fp) {
+ write_file_fp = filp_open(format_disk_name, O_RDWR, 0644);
+ error = PTR_ERR(write_file_fp);
+ if(IS_ERR(write_file_fp)) {
+ printk("open %s error ,error = %d\n", format_disk_name, error);
+ return -1;
+ }
+ }
+
+ if(amount_left_to_write == 0)
+ {
+ read_param.flash_partition = fsg->cmnd[2] & ~0x80;
+ read_param.devnum_in_phypart = fsg->cmnd[2] & ~0x80;
+ printk("image_sectors:0x%x,%d,%d\n", image_sectors, read_param.flash_partition, read_param.devnum_in_phypart);
+ check_image_sectors = image_sectors;
+ image_sectors = 0;
+ if(write_file_fp)
+ {
+ filp_close(write_file_fp, current->files);
+ write_file_fp = NULL;
+ pos = 0;
+ write_file_name[0] = 0;
+ }
+ goto out;
+ }
+ image_sectors += amount_left_to_write>>9;
+ while (amount_left_to_write > 0) {
+
+ /* Queue a request for more data from the host */
+ bh = fsg->next_buffhd_to_fill;
+ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+ /* Figure out how much we want to get:
+ * Try to get the remaining amount.
+ * But don't get more than the buffer size.
+ * And don't try to go past the end of the file.
+ * If we're not at a page boundary,
+ * don't go past the next page.
+ * If this means getting 0, then we were asked
+ * to write past the end of file.
+ * Finally, round down to a block boundary. */
+ amount = min(amount_left_to_req, mod_data.buflen);
+ /*
+ amount = min((loff_t) amount, curlun->file_length -
+ usb_offset);
+ */
+
+ /* move the overflow judge into flash driver? */
+
+ /*
+ partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
+ if (partial_page > 0)
+ amount = min(amount,
+ (unsigned int)PAGE_CACHE_SIZE -
+ partial_page);
+ if (amount == 0) {
+ get_some_more = 0;
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = usb_offset >> 9;
+ curlun->info_valid = 1;
+ continue;
+ }
+ */
+
+
+ /* Get the next buffer */
+ usb_offset += amount; /* for future use(test the boundary) */
+ fsg->usb_amount_left -= amount;
+ amount_left_to_req -= amount;
+ if (amount_left_to_req == 0)
+ get_some_more = 0;
+
+ /* Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
+ */
+ set_bulk_out_req_length(fsg, bh, amount);
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+
+ continue;
+ }
+
+ /* Write the received data to the backing file */
+ bh = fsg->next_buffhd_to_drain;
+ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+ {
+ VLDBG("break:%d,bh->state:%d, BUF_STATE_EMPTY:%d\n",__LINE__, bh->state, BUF_STATE_EMPTY);
+ break; /* We stopped early */
+ }
+
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+ fsg->next_buffhd_to_drain = bh->next;
+ bh->state = BUF_STATE_EMPTY;
+
+ /* Did something go wrong with the transfer? */
+ if (bh->outreq->status != 0) {
+ curlun->sense_data = SS_COMMUNICATION_FAILURE;
+ curlun->sense_data_info = file_offset;
+ curlun->info_valid = 1;
+ VLDBG("break:%d,bh->outreq->status:%d\n",__LINE__, bh->outreq->status);
+ break;
+ }
+
+ amount = bh->outreq->actual; /* unit by sector */
+
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+ //amount = round_down(amount, curlun->blksize);
+
+ /* Perform the write */
+ file_offset_tmp = file_offset;
+
+ VLDBG("Perform the write,wt_param.devnum_in_phypart:0x%x\n", wt_param.devnum_in_phypart);
+// if(wt_param.devnum_in_phypart == 0x1)
+ {
+
+ if(!write_file_fp)
+ {
+
+ //nwritten = adfus_nand_write(file_offset, amount >> 9,
+ //bh->buf, &wt_param);
+ //printk("===================== flip:0x%x, buf:0x%x, amount:0x%x,offset:0x%x\n",curlun->filp,bh->buf, amount >> 9, file_offset_tmp);
+ //nwritten = vfs_write(curlun->filp,bh->buf, amount, &file_offset_tmp);
+ //nwritten = nwritten << 9;
+ //VLDBG("amount:0x%x,nwritten:0x%x,file_offset:0x%x\n", amount, nwritten, (unsigned long)file_offset);
+ nwritten = 0;
+ }
+ else {
+ //printk("amount:0x%x,nwritten:0x%x,pos:0x%x\n", amount, nwritten, (unsigned long)pos);
+ /* reinitialize offset for random write */
+ pos = file_offset << 9;
+ //printk("startw: wlen=0x%x,pos:0x%x\n", amount, (unsigned long)pos);
+ nwritten = write_file_fp->f_op->write(write_file_fp, bh->buf, amount, &pos);
+ //printk("endw: wlen=0x%x\n", nwritten);
+ }
+ }
+
+ if (signal_pending(current)) {
+ printk("return:%d\n",__LINE__);
+ return -EINTR; /* Interrupted! */
+ }
+ if (nwritten < 0) {
+ LDBG(curlun, "error in file write: %d\n",
+ (int)nwritten);
+ nwritten = 0;
+ } else if (nwritten < amount) {
+ LDBG(curlun, "partial file write: %d/%u\n",
+ (int)nwritten, amount);
+ /* Round down to a block */
+ }
+ file_offset += nwritten >> 9;
+ amount_left_to_write -= nwritten;
+ fsg->residue -= nwritten;
+
+ /* If an error occurred, report it and its position */
+ if (nwritten < amount) {
+ curlun->sense_data = SS_WRITE_ERROR;
+ curlun->sense_data_info = file_offset;
+ curlun->info_valid = 1;
+ VLDBG("break:%d\n",__LINE__);
+ break;
+ }
+
+ /* Did the host decide to stop early? */
+ if (bh->outreq->actual != bh->outreq->length) {
+ fsg->short_packet_received = 1;
+ VLDBG("break:%d\n",__LINE__);
+ break;
+ }
+ continue;
+ }
+ else
+ {
+ VLDBG("break:%d,bh->state:%d\n",__LINE__, bh->state);
+ }
+
+ /* Wait for something to happen */
+ rc = sleep_thread(fsg);
+ if (rc) {
+ VLDBG("return:%d\n",__LINE__);
+ return rc;
+ }
+ }
+
+out:
+ no_finish_reply = 1;
+ VLDBG("return:%d\n",__LINE__);
+ return -EIO; /* No default reply */
+}
+
+/* Sync the file data, don't bother with the metadata.
+ * This code was copied from fs/buffer.c:sys_fdatasync(). */
+static int fsync_sub(struct lun *curlun)
+{
+#if 0
+ if (curlun->disk_type == NAND_MEDIUM)
+ {
+ dev_t media_dev_t;
+ struct gendisk *disk;
+ struct block_device *bdev_back;
+ media_dev_t = curlun->devnum;
+ bdev_back = bdget(media_dev_t);
+ disk = bdev_back->bd_disk;
+
+ if (disk == NULL)
+ {
+ bdput(bdev_back);
+ return 0;
+ }
+ if (disk->fops->flush_disk_cache != NULL) {
+ disk->fops->flush_disk_cache();
+ }
+ bdput(bdev_back);
+ }
+ return 0; //when we dont use VFS, we neednt sync
+#else
+ struct file *filp = curlun->filp;
+
+ if (curlun->ro || !filp)
+ return 0;
+ return vfs_fsync(filp, 1);
+
+#endif
+}
+
+static void fsync_all(struct fsg_dev *fsg)
+{
+ int i;
+
+ for (i = 0; i < fsg->nluns; ++i)
+ fsync_sub(&fsg->luns[i]);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+ int rc;
+ rc = fsg_set_halt(fsg, fsg->bulk_in);
+
+ if (rc == -EAGAIN)
+ VDBG(fsg, "delayed bulk-in endpoint halt\n");
+ while (rc != 0) {
+ if (rc != -EAGAIN) {
+ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
+ rc = 0;
+ break;
+ }
+
+ /* Wait for a short time and then try again */
+ if (msleep_interruptible(100) != 0)
+ return -EINTR;
+ rc = usb_ep_set_halt(fsg->bulk_in);
+ }
+ return rc;
+}
+#if 0
+static int halt_bulk_out_endpoint(struct fsg_dev *fsg)
+{
+ int rc;
+ rc = fsg_set_halt(fsg, fsg->bulk_out);
+
+ if (rc == -EAGAIN)
+ VDBG(fsg, "delayed bulk-out endpoint halt\n");
+ while (rc != 0) {
+ if (rc != -EAGAIN) {
+ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
+ rc = 0;
+ break;
+ }
+
+ /* Wait for a short time and then try again */
+ if (msleep_interruptible(100) != 0)
+ return -EINTR;
+ rc = usb_ep_set_halt(fsg->bulk_out);
+ }
+ return rc;
+}
+
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+ int rc;
+
+ DBG(fsg, "bulk-in set wedge\n");
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ if (rc == -EAGAIN)
+ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+ while (rc != 0) {
+ if (rc != -EAGAIN) {
+ WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
+ rc = 0;
+ break;
+ }
+
+ /* Wait for a short time and then try again */
+ if (msleep_interruptible(100) != 0)
+ return -EINTR;
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ }
+ return rc;
+}
+#endif
+static int pad_with_zeros(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
+ u32 nkeep = bh->inreq->length;
+ u32 nsend;
+ int rc;
+ bh->state = BUF_STATE_EMPTY; /* For the first iteration */
+ fsg->usb_amount_left = nkeep + fsg->residue;
+ while (fsg->usb_amount_left > 0) {
+
+ /* Wait for the next buffer to be free */
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+
+ }
+
+ nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen);
+ memset(bh->buf + nkeep, 0, nsend - nkeep);
+ bh->inreq->length = nsend;
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ bh = fsg->next_buffhd_to_fill = bh->next;
+ fsg->usb_amount_left -= nsend;
+ nkeep = 0;
+ }
+ return 0;
+}
+
+static int throw_away_data(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh;
+ u32 amount;
+ int rc;
+
+ while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
+ fsg->usb_amount_left > 0) {
+
+ /* Throw away the data in a filled buffer */
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+ bh->state = BUF_STATE_EMPTY;
+ fsg->next_buffhd_to_drain = bh->next;
+
+ /* A short packet or an error ends everything */
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
+ bh->outreq->status != 0) {
+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+ return -EINTR;
+ }
+ continue;
+ }
+
+ /* Try to submit another request if we need one */
+ bh = fsg->next_buffhd_to_fill;
+ if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
+ amount = min(fsg->usb_amount_left,
+ (u32) mod_data.buflen);
+
+ /* amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size */
+
+ set_bulk_out_req_length(fsg, bh, amount);
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ fsg->usb_amount_left -= amount;
+ continue;
+ }
+
+ /* Otherwise wait for something to happen */
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+
+ }
+ return 0;
+}
+
+extern int finish_reply(struct fsg_dev *fsg);
+int finish_reply(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
+ int rc = 0;
+
+ switch (fsg->data_dir) {
+ case DATA_DIR_NONE:
+ break; /* Nothing to send */
+
+ /* If we don't know whether the host wants to read or write,
+ * this must be CB or CBI with an unknown command. We mustn't
+ * try to send or receive any data. So stall both bulk pipes
+ * if we can and wait for a reset. */
+ case DATA_DIR_UNKNOWN:
+ if (mod_data.can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ rc = halt_bulk_in_endpoint(fsg);
+ }
+ break;
+
+ /* All but the last buffer of data must have already been sent */
+ case DATA_DIR_TO_HOST:
+ if (fsg->data_size == 0)
+ ; /* Nothing to send */
+
+ /* If there's no residue, simply send the last buffer */
+ else if (fsg->residue == 0) {
+ if (!no_finish_reply) {
+ bh->inreq->zero = 0;
+ /* bh->inreq->medium = 0; */
+ start_transfer(fsg, fsg->bulk_in,
+ bh->inreq,
+ &bh->inreq_busy,
+ &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ } else {
+ /* */
+ no_finish_reply = 0;
+ }
+ } else {
+#if 0
+ if (mod_data.can_stall) {
+ bh->inreq->zero = 1;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ rc = halt_bulk_in_endpoint(fsg);
+ } else
+#endif
+ rc = pad_with_zeros(fsg);
+ }
+
+ break;
+
+ /* We have processed all we want
+ * from the data the host has sent.
+ * There may still be outstanding bulk-out requests. */
+ case DATA_DIR_FROM_HOST:
+ if ((fsg->residue == 0) || (no_finish_reply))
+ no_finish_reply = 0; /* Nothing to receive */
+
+ /* Did the host stop sending unexpectedly early? */
+ else if (fsg->short_packet_received) {
+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+ }
+
+ /* We haven't processed all the incoming data. Even though
+ * we may be allowed to stall, doing so would cause a race.
+ * The controller may already have ACK'ed all the remaining
+ * bulk-out packets, in which case the host wouldn't see a
+ * STALL. Not realizing the endpoint was halted, it wouldn't
+ * clear the halt -- leading to problems later on. */
+#if 0
+ else if (mod_data.can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+ rc = -EINTR;
+ }
+#endif
+ else
+ rc = throw_away_data(fsg);
+
+ /* We can't stall. Read in the excess data and throw it
+ * all away. */
+ break;
+ }
+ return rc;
+}
+#if 0
+u32 get_phBaseAddr(void)
+{
+ u32 tmp;
+
+ __asm__ __volatile__ ("mrc p15, 4, %0, c15, c0, 0":"=r"(tmp));
+ return tmp;
+}
+
+// void init_WD_timer(unsigned int load_value, unsigned int auto_reload)
+// Sets up the WD timer
+// r0: initial load value
+// r1: IF 0 (AutoReload) ELSE (SingleShot)
+void init_WD_timer(unsigned int load_value, unsigned int auto_reload)
+{
+ u32 phBaseAddr, wdCountAddr, wdModeAddr, tmp=0;
+
+ phBaseAddr = get_phBaseAddr();
+ wdCountAddr = phBaseAddr+0x620;
+ wdModeAddr = phBaseAddr+0x628;
+
+ writel(load_value, (volatile void *)wdCountAddr);
+ if(auto_reload == 0)
+ {
+ tmp = 0x2;
+ }
+ writel(tmp, (volatile void *)wdModeAddr);
+}
+
+static void WD_is_running(void)
+{
+ u32 phBaseAddr, wdModeAddr;
+
+ phBaseAddr = get_phBaseAddr();
+ wdModeAddr = phBaseAddr+0x628;
+
+ if (readl(wdModeAddr) & 0x8)
+ return ;
+
+ return ;
+}
+
+static void clear_is_running(void)
+{
+ u32 phBaseAddr, wdModeAddr;
+
+ phBaseAddr = get_phBaseAddr();
+ wdModeAddr = phBaseAddr+0x628;
+
+ if (readl(wdModeAddr) & 0x8)
+ return ;
+
+ return ;
+}
+
+extern struct atc260x_dev *atc260x_dev_handle;
+
+static void clear_enteradfu_flag(void)
+{
+ atc260x_set_bits(atc260x_dev_handle, atc2603_PMU_UV_INT_EN, 0x2 , 0x0);
+ mdelay(1);
+ printk(KERN_INFO "atc2603_PMU_UV_INT_EN: %x\n", atc260x_reg_read(atc260x_dev_handle, atc2603_PMU_UV_INT_EN));
+}
+
+static int need_enteradfu(void)
+{
+ return (atc260x_reg_read(atc260x_dev_handle, atc2603_PMU_UV_INT_EN) & 0x2) ? 1 : 0;
+}
+#endif
+
+// void set_WD_mode(unsigned int mode)
+// Sets up the WD timer
+// r0: IF 0 (timer mode) ELSE (watchdog mode)
+// void set_WD_mode(unsigned int mode)
+// {
+// u32 phBaseAddr, wdModeAddr;
+//
+// phBaseAddr = get_phBaseAddr();
+// wdModeAddr = phBaseAddr+0x628;
+//
+// if(mode == 0)
+// {
+// writel((readl(wdModeAddr) & 0xf7) | 0x4, wdModeAddr);
+// }
+// else
+// {
+// writel(readl(wdModeAddr) | 0x8, wdModeAddr);
+// }
+// }
+//
+// void start_WD_timer(void)
+// {
+// u32 phBaseAddr, wdModeAddr;
+//
+// phBaseAddr = get_phBaseAddr();
+// wdModeAddr = phBaseAddr+0x628;
+//
+// writel(readl(wdModeAddr) | 0x1, wdModeAddr);
+// }
+//
+// int wd_restart(void)
+// {
+// printk(KERN_INFO "wd_restart\n");
+//
+// if (need_enteradfu())
+// {
+// printk(KERN_INFO "clear enter adfu flag\n");
+// clear_enteradfu_flag();
+// }
+//
+// msleep(10);
+//
+// //bit26=1,ʹWD0\B8\B4λ\CB\F9\D3\D0cpu\BC\B0\D5\FB\B8\F6ϵͳ(\B3\FD\C1˸\C3bit\BA\CDWDRESET0)\A3\AC\C6\E4\CB\FC\BCĴ\E6\C6\F7ȫ\B2\BF\B8\B4λ
+// writel(readl(SPS_PG_CTL)|0x04000000, SPS_PG_CTL);
+// init_WD_timer(0x98, 0x01);
+// set_WD_mode(1);
+// start_WD_timer();
+// while(1)
+// {
+// };
+// }
+
+//extern unsigned long (*boot_info_read)(unsigned long);
+//extern int (*boot_info_write)(unsigned long, unsigned long);
+static int send_status(struct fsg_dev *fsg)
+{
+ struct lun *curlun = fsg->curlun;
+ struct fsg_buffhd *bh;
+ int rc;
+ u8 status = USB_STATUS_PASS;
+ u32 sd, sdinfo = 0;
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+
+ }
+ if (curlun) {
+ sd = curlun->sense_data;
+ sdinfo = curlun->sense_data_info;
+ } else if (fsg->bad_lun_okay)
+ sd = SS_NO_SENSE;
+ else
+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+ if (fsg->phase_error) {
+ DBG(fsg, "sending phase-error status\n");
+ status = USB_STATUS_PHASE_ERROR;
+ sd = SS_INVALID_COMMAND;
+ } else if (sd != SS_NO_SENSE) {
+ DBG(fsg, "sending command-failure status\n");
+ status = USB_STATUS_FAIL;
+ VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+ " info x%x\n", SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+ }
+ if (transport_is_bbb()) {
+ struct bulk_cs_wrap *csw = bh->buf;
+
+ /* Store and send the Bulk-only CSW */
+ csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
+ csw->Tag = fsg->tag;
+ csw->Residue = cpu_to_le32(fsg->residue);
+ csw->Status = status;
+#if 0
+ printk(KERN_INFO
+ "csw-> SIG: %x Tag:%x Residue:%x Status:%x\n",
+ csw->Signature, csw->Tag, csw->Residue, csw->Status);
+#endif
+ bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+
+ } else if (mod_data.transport_type == USB_PR_CB) {
+
+ /* Control-Bulk transport has no status phase! */
+ return 0;
+
+ } else { /* USB_PR_CBI */
+ struct interrupt_data *buf = bh->buf;
+
+ /* Store and send the Interrupt data. UFI sends the ASC
+ * and ASCQ bytes. Everything else sends a Type (which
+ * is always 0) and the status Value. */
+ if (mod_data.protocol_type == USB_SC_UFI) {
+ buf->bType = ASC(sd);
+ buf->bValue = ASCQ(sd);
+ } else {
+ buf->bType = 0;
+ buf->bValue = status;
+ }
+ fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
+
+ fsg->intr_buffhd = bh; /* Point to the right buffhd */
+ fsg->intreq->buf = bh->inreq->buf;
+ fsg->intreq->context = bh;
+ start_transfer(fsg, fsg->intr_in, fsg->intreq,
+ &fsg->intreq_busy, &bh->state);
+ }
+
+ fsg->next_buffhd_to_fill = bh->next;
+
+// /* when adfu upgrade successful, disconnect and sync */
+// if (unlikely(adfu_success_flag == 1)) {
+// raise_exception(fsg, FSG_STATE_DISCONNECT);
+// adfu_flush_nand_cache();
+//
+// if (boot_info_write && boot_info_read) {
+// boot_info_write(atc2603_PMU_SYS_CTL8, 0x0);
+// boot_info_write(atc2603_PMU_SYS_CTL9, 0x0);
+// printk("\n%s, %d, ctl8: %x, ctl9: %x\n", __func__, __LINE__, boot_info_read(atc2603_PMU_SYS_CTL8), boot_info_read(atc2603_PMU_SYS_CTL9));
+// }
+//
+// printk(KERN_INFO "UPGRADE SUCCESSFULLY\n");
+// if(need_restart == 0)
+// {
+// machine_restart("reboot");
+// }
+// }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Check whether the command is properly formed and whether its data size
+ * and direction agree with the values we already have. */
+static int check_command(struct fsg_dev *fsg, int cmnd_size,
+ enum data_direction data_dir, unsigned int mask,
+ int needs_medium, const char *name)
+{
+ //int i;
+ int lun = fsg->cmnd[1] >> 5;
+ static const char dirletter[4] = { 'u', 'o', 'i', 'n' };
+ char hdlen[20];
+ struct lun *curlun;
+
+
+ /* There's some disagreement as to whether RBC pads commands or not.
+ * We'll play it safe and accept either form. */
+ if (mod_data.protocol_type == USB_SC_RBC) {
+ if (fsg->cmnd_size == 12)
+ cmnd_size = 12;
+
+ /* All the other protocols pad to 12 bytes */
+ } else
+ cmnd_size = 12;
+
+ hdlen[0] = 0;
+ if (fsg->data_dir != DATA_DIR_UNKNOWN)
+ sprintf(hdlen, ", H%c=%u", dirletter[(int)fsg->data_dir],
+ fsg->data_size);
+
+ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
+ name, cmnd_size, dirletter[(int)data_dir],
+ fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
+
+ /* We can't reply at all until we know the correct data direction
+ * and size. */
+ if (fsg->data_size_from_cmnd == 0)
+ data_dir = DATA_DIR_NONE;
+ if (fsg->data_dir == DATA_DIR_UNKNOWN) { /* CB or CBI */
+ fsg->data_dir = data_dir;
+ fsg->data_size = fsg->data_size_from_cmnd;
+
+ } else { /* Bulk-only */
+ if (fsg->data_size < fsg->data_size_from_cmnd) {
+
+ /* Host data size < Device data size is a phase error.
+ * Carry out the command, but only transfer as much
+ * as we are allowed. */
+ fsg->data_size_from_cmnd = fsg->data_size;
+ fsg->phase_error = 1;
+ }
+ }
+ fsg->residue = fsg->usb_amount_left = fsg->data_size;
+
+ /* Conflicting data directions is a phase error */
+ if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
+ fsg->phase_error = 1;
+ return -EINVAL;
+ }
+#if 0
+ /* Verify the length of the command itself */
+ if (cmnd_size != fsg->cmnd_size) {
+
+ /* Special case workaround: There are plenty of buggy SCSI
+ * implementations. Many have issues with cbw->Length
+ * field passing a wrong command size. For those cases we
+ * always try to work around the problem by using the length
+ * sent by the host side provided it is at least as large
+ * as the correct command length.
+ * Examples of such cases would be MS-Windows, which issues
+ * REQUEST SENSE with cbw->Length == 12 where it should
+ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
+ * REQUEST SENSE with cbw->Length == 10 where it should
+ * be 6 as well.
+ */
+ if (cmnd_size <= fsg->cmnd_size) {
+ DBG(fsg, "%s is buggy! Expected length %d "
+ "but we got %d\n", name, cmnd_size, fsg->cmnd_size);
+ cmnd_size = fsg->cmnd_size;
+ } else {
+ fsg->phase_error = 1;
+ return -EINVAL;
+ }
+ }
+#endif
+ /* Check that the LUN values are consistent */
+ if (transport_is_bbb()) {
+ if (fsg->lun != lun)
+ DBG(fsg, "using LUN %d from CBW, "
+ "not LUN %d from CDB\n", fsg->lun, lun);
+ } else
+ fsg->lun = lun; /* Use LUN from the command */
+
+ /* Check the LUN */
+ if (fsg->lun >= 0 && fsg->lun < fsg->nluns) {
+ fsg->curlun = curlun = &fsg->luns[fsg->lun];
+ if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+ } else {
+ fsg->curlun = curlun = NULL;
+ fsg->bad_lun_okay = 0;
+
+ /* INQUIRY and REQUEST SENSE commands are explicitly allowed
+ * to use unsupported LUNs; all others may not. */
+ if (fsg->cmnd[0] != SC_INQUIRY &&
+ fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ DBG(fsg, "unsupported LUN %d\n", fsg->lun);
+ return -EINVAL;
+ }
+ }
+
+ /* If a unit attention condition exists, only INQUIRY and
+ * REQUEST SENSE commands are allowed; anything else must fail. */
+ if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
+ fsg->cmnd[0] != SC_INQUIRY && fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = curlun->unit_attention_data;
+ curlun->unit_attention_data = SS_NO_SENSE;
+ return -EINVAL;
+ }
+#if 0
+ /* Check that only command bytes listed in the mask are non-zero */
+ fsg->cmnd[1] &= 0x1f; /* Mask away the LUN */
+ for (i = 1; i < cmnd_size; ++i) {
+ if (fsg->cmnd[i] && !(mask & (1 << i))) {
+ if (curlun)
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ }
+#endif
+ /* If the medium isn't mounted and the command needs to access
+ * it, return an error. */
+ if (curlun && !backing_file_is_open(curlun) && needs_medium) {
+ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int adfu_do_checksum(struct fsg_dev *fsg)
+{
+ struct file *filp_checksum_flash;
+ u32 checksum_flash;
+ loff_t offset_flash;
+ int checksum_ok = 0;
+ int must_checksum = 0;
+ int i;
+
+
+ u32 *expect_checksum[] = {
+ &misc_checksum,
+ &recovery_checksum,
+ &system_checksum,
+ };
+
+ u32 *need_checksum_p[] = {
+ &write_mbrc,
+ &write_recovery,
+ &write_system,
+ };
+ const char *checksum_file_path[] = {
+ "/sys/block/acta/checksum",
+ "/sys/block/actb/checksum",
+ "/sys/block/actc/checksum",
+ };
+ const int checksum_count = ARRAY_SIZE(checksum_file_path);
+
+ for (i = 0; i < checksum_count; i++) {
+ if ((*expect_checksum[i] != INVALID_ADFU_CHECKSUM)&& (*need_checksum_p[i] != 0) ){
+ must_checksum++;
+ }
+ }
+
+ if (must_checksum == 0) {
+ pr_err("no checksum.bin ???\n");
+ //return -1;
+ }
+
+ for (i = 0; i < checksum_count; i++) {
+ filp_checksum_flash = NULL;
+ checksum_flash = 0;
+ offset_flash = 0;
+
+ if (*expect_checksum[i] == INVALID_ADFU_CHECKSUM) {
+ continue;
+ }
+
+ if (*need_checksum_p[i] == 0) {
+ continue;
+ }
+
+ filp_checksum_flash = filp_open(checksum_file_path[i], O_RDONLY, 0);
+ if (IS_ERR(filp_checksum_flash)) {
+ pr_err("can not open [%s] , err %d.\n", checksum_file_path[i], (int)PTR_ERR(filp_checksum_flash));
+ continue;
+ }
+ else {
+ if (4 == vfs_read(filp_checksum_flash, (char __user *)&checksum_flash, 4, &offset_flash)) {
+ printk("checksum_flash = 0x%08X expect_checksum[%d] = 0x%08X \n", checksum_flash, i , *expect_checksum[i]);
+ if (checksum_flash == *expect_checksum[i]) {
+ checksum_ok++;
+ }
+ }
+ else {
+ pr_err("read [%s] error.\n", checksum_file_path[i]);
+ }
+
+ filp_close(filp_checksum_flash, current->files);
+ }
+ }
+
+ if (checksum_ok == must_checksum)
+ return 0;
+
+ return -1;
+}
+
+static void adfu_sync_bdev(const char *path)
+{
+ struct file *filp;
+
+ pr_err("[adfuserver]sync .. bdev %s\n", path);
+
+ filp = filp_open(path, O_RDWR, 0);
+ if (IS_ERR(filp)) {
+ pr_err("can not open %s\n", path);
+ return;
+ }
+
+ vfs_fsync(filp, 1);
+ filp_close(filp, 0);
+}
+
+extern int do_scsi_command(struct fsg_dev *fsg);
+int do_scsi_command(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh;
+ int rc;
+ int reply = -EINVAL;
+ unsigned char sub_code;
+ static char unknown[16];
+ struct lun *curlun = fsg->curlun;
+
+ dump_cdb(fsg);
+
+ /* Wait for the next buffer to become available for data or status */
+ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+ }
+ fsg->phase_error = 0;
+ fsg->short_packet_received = 0;
+
+ down_read(&fsg->filesem); /* We're using the backing file */
+ printk("fsg->cmnd[0-2] = 0x%x 0x%x 0x%x\n", fsg->cmnd[0], fsg->cmnd[1], fsg->cmnd[2]);
+ switch (fsg->cmnd[0]) {
+
+ case SC_ADFU_UPGRADE:
+ /* printk(KERN_INFO "*******ADFU_UPGRADE_COMMAND:*******\n"); */
+ fsg->lun = 0; /* cheat the OS */
+ fsg->curlun = curlun = &fsg->luns[fsg->lun];
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+
+ sub_code = fsg->cmnd[1];
+ switch (sub_code) {
+
+// case SC_ADFU_FORMAT_FLASH:
+// printk(KERN_INFO "\n****** ERASE THE FLASH ******\n");
+// need_format = 1;
+// fsg->data_dir = DATA_DIR_NONE;
+//
+// break;
+
+// case SC_ADFU_TEST_FLASHRDY:
+// /* printk(KERN_INFO "\n****** TEST FLASH ERASE READY ******\n"); */
+// fsg->data_dir = DATA_DIR_NONE;
+// if (!backing_file_is_open(curlun)) {
+// /* printk(KERN_INFO "\n****** NOT READY ******\n"); */
+// curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+// } else {
+// /* */
+// printk(KERN_INFO "\n****** READY ******\n");
+// }
+//
+// break;
+
+// case SC_ADFU_ACCESS_MBR:
+// /* printk(KERN_INFO "*******ACCESS THE MBR !!*******\n"); */
+// fsg->data_size = 0x400;
+// fsg->residue = fsg->usb_amount_left = fsg->data_size;
+// fsg->data_dir = DATA_DIR_TO_HOST;
+// reply = do_ADFU_acmbr(fsg);
+// break;
+ case SC_ADFU_ACCESS_INTERNAL_RAM:
+ fsg->data_dir = DATA_DIR_FROM_HOST;
+ fsg->data_size_from_cmnd = get_le32(&fsg->cmnd[5]);
+ fsg->residue = fsg->usb_amount_left = fsg->data_size;
+ reply = do_ADFU_access_iram(fsg);
+ break;
+ case SC_ADFU_DOWNLOAD_IMG:
+// printk("*******WRITE THE ROOTFS !!*******\n");
+ /* prepare */
+ /* fsg->data_size = */
+ fsg->data_dir = DATA_DIR_FROM_HOST;
+ fsg->data_size_from_cmnd = (get_le32(&fsg->cmnd[5]))<<9;
+ fsg->residue = fsg->usb_amount_left = fsg->data_size;
+ reply = do_ADFU_wtrootfs(fsg);
+// printk("handle SC_ADFU_WRITE_ROOTFS end\n");
+ break;
+ case SC_ADFU_INFO:
+ fsg->data_dir = DATA_DIR_TO_HOST;
+ fsg->data_size_from_cmnd = get_le32(&fsg->cmnd[5]);
+ fsg->residue = fsg->usb_amount_left = fsg->data_size;
+ reply = do_ADFU_INFO(fsg);
+ break;
+// case SC_ADFU_READ_ROOTFS:
+// /* printk(KERN_INFO "*******READ THE ROOTFS !!*******\n"); */
+// /* prepare */
+// /* fsg->data_size = */
+// fsg->data_dir = DATA_DIR_TO_HOST;
+// fsg->data_size_from_cmnd = get_le32(&fsg->cmnd[9]);
+// fsg->residue = fsg->usb_amount_left = fsg->data_size;
+// reply = do_ADFU_rdrootfs(fsg);
+// break;
+ case SC_ADFU_TFEROVER:
+ printk("SC_ADFU_TFEROVER\n");
+
+ //vfs_fsync(curlun->filp, 1);
+ sys_sync(); //sync all filesystem,avoid the error of checksum
+ mdelay(500);
+ sys_sync();
+ adfu_sync_bdev("/dev/acta");
+ adfu_sync_bdev("/dev/actb");
+ adfu_sync_bdev("/dev/actc");
+
+ adfu_sync_bdev("/dev/actd");
+ adfu_sync_bdev("/dev/acte");
+ adfu_sync_bdev("/dev/actf");
+
+ adfu_sync_bdev("/dev/actg");
+ adfu_sync_bdev("/dev/acth");
+ adfu_sync_bdev("/dev/acti");
+// curlun->filp->f_op->unlocked_ioctl(curlun->filp,BLKFLSBUF,0); //write_back flash buffer
+
+ if (need_checksum) {
+ if (adfu_do_checksum(fsg)) {
+ printk("UPGRADE CHECKSUM ERROR.\n");
+ curlun->sense_data = SS_CHECKSUM_FAIL;
+ }
+ else {
+ printk("UPGRADE CHECKSUM OK.\n");
+ }
+ }
+
+ //update phy if downloading misc.img or updating mbr_info.bin
+ if((update_phy_boot == 1) || (check_partition_flag > 0))
+ {
+ set_probatch_phase(PROBATCH_WRITE_PHY);
+ wait_adfus_proc(PROBATCH_FINISH_WRITE_PHY);
+ }
+
+ //check udisk formatted ?
+ set_probatch_phase(PROBATCH_FINISH);
+ wait_adfus_proc(PROBATCH_FINISH_OK);
+
+ //vfs_fsync(curlun->filp, 1);
+ sys_sync(); //sync all filesystem
+ //adfu_sync_bdev("/dev/actk");
+// curlun->filp->f_op->unlocked_ioctl(curlun->filp,BLKFLSBUF,0); //write_back flash buffer
+ mdelay(1000);
+ break;
+ }
+ break;
+
+ case SC_ADFU_SUCCESSFUL:
+ fsg->curlun = curlun = &fsg->luns[0];
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ adfu_success_flag = 1;
+ //vfs_fsync(curlun->filp, 1);
+// curlun->filp->f_op->unlocked_ioctl(curlun->filp,BLKFLSBUF,0); //write_back flash buffer
+
+ break;
+
+ /* Some mandatory commands that we recognize but don't implement.
+ * They don't mean much in this setting. It's left as an exercise
+ * for anyone interested to implement RESERVE and RELEASE in terms
+ * of Posix locks. */
+ case SC_FORMAT_UNIT:
+ case SC_RELEASE:
+ case SC_RESERVE:
+ case SC_SEND_DIAGNOSTIC:
+ /* printk(KERN_INFO "SC_ENTENSIVE.\n"); */
+
+ default:
+ /* printk(KERN_INFO "SC_UNKNOW.\n"); */
+
+ fsg->data_size_from_cmnd = 0;
+ sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
+ reply = check_command(fsg, fsg->cmnd_size,
+ DATA_DIR_UNKNOWN, 0xff, 0,
+ unknown);
+ if (reply == 0) {
+ fsg->curlun->sense_data = SS_INVALID_COMMAND;
+ reply = -EINVAL;
+ }
+ break;
+ }
+ up_read(&fsg->filesem);
+
+ if (reply == -EINTR || signal_pending(current)) {
+ /* */
+ return -EINTR;
+ }
+ /* Set up the single reply buffer for finish_reply() */
+ if (reply == -EINVAL)
+ reply = 0; /* Error reply length */
+ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
+ reply = min((u32) reply, fsg->data_size_from_cmnd);
+ bh->inreq->length = reply;
+ bh->state = BUF_STATE_FULL;
+ fsg->residue -= reply;
+ } /* Otherwise it's already set */
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+ struct usb_request *req = bh->outreq;
+ struct bulk_cb_wrap *cbw = req->buf;
+ /* Was this a real packet? Should it be ignored? */
+ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
+ return -EINVAL;
+#if 0
+ int k;
+ printk(KERN_INFO "CDB:");
+ for (k = 0; k < MAX_COMMAND_SIZE; k++) {
+ /**/
+ printk(KERN_INFO "%x ", cbw->CDB[k]);
+ }
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "Signature:%x Tag:%x Flags: \
+ %x DataTransferLength:%x\n",
+ cbw->Signature, cbw->Tag, cbw->Flags,
+ le32_to_cpu(cbw->DataTransferLength));
+#endif
+
+#if 0
+ /* Is the CBW valid? */
+ if (req->actual != USB_BULK_CB_WRAP_LEN ||
+ cbw->Signature != __constant_cpu_to_le32(USB_BULK_CB_SIG)) {
+ DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
+ req->actual, le32_to_cpu(cbw->Signature));
+
+ /* The Bulk-only spec says we MUST stall the IN endpoint
+ * (6.6.1), so it's unavoidable. It also says we must
+ * retain this state until the next reset, but there's
+ * no way to tell the controller driver it should ignore
+ * Clear-Feature(HALT) requests.
+ *
+ * We aren't required to halt the OUT endpoint; instead
+ * we can simply accept and discard any data received
+ * until the next reset. */
+ wedge_bulk_in_endpoint(fsg);
+ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+ return -EINVAL;
+ }
+
+ /* Is the CBW meaningful? */
+ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
+ DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
+ "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length);
+
+ /* We can do anything we want here, so let's stall the
+ * bulk pipes if we are allowed to. */
+ if (mod_data.can_stall) {
+ //fsg_set_halt(fsg, fsg->bulk_out);
+ halt_bulk_in_endpoint(fsg);
+ }
+ return -EINVAL;
+ }
+common_use:
+#endif
+ /* Save the command for later */
+ fsg->cmnd_size = cbw->Length;
+ memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
+ if (cbw->Flags & USB_BULK_IN_FLAG)
+ fsg->data_dir = DATA_DIR_TO_HOST;
+ else
+ fsg->data_dir = DATA_DIR_FROM_HOST;
+ fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
+ if (fsg->data_size == 0)
+ fsg->data_dir = DATA_DIR_NONE;
+ fsg->lun = cbw->Lun;
+ fsg->tag = cbw->Tag;
+ return 0;
+}
+
+static int get_next_command(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh;
+ int rc = 0;
+ if (transport_is_bbb()) {
+
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+
+ }
+
+ /* Queue a request to read a Bulk-only CBW */
+ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
+ bh->outreq->short_not_ok = 1;
+ /* printk(KERN_INFO
+ "get command length: %d\n",bh->outreq->length); */
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+
+ /* We will drain the buffer in software, which means we
+ * can reuse it for the next filling. No need to advance
+ * next_buffhd_to_fill. */
+
+ /* Wait for the CBW to arrive */
+ while (bh->state != BUF_STATE_FULL) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+
+ }
+ smp_rmb();
+ rc = received_cbw(fsg, bh);
+ bh->state = BUF_STATE_EMPTY;
+
+ } else { /* USB_PR_CB or USB_PR_CBI */
+
+ unsigned long flag;
+ /* Wait for the next command to arrive */
+ while (fsg->cbbuf_cmnd_size == 0) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+ }
+
+ /* Is the previous status interrupt request still busy?
+ * The host is allowed to skip reading the status,
+ * so we must cancel it. */
+
+ if (fsg->intreq_busy)
+ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
+
+ /* Copy the command and mark the buffer empty */
+ fsg->data_dir = DATA_DIR_UNKNOWN;
+ spin_lock_irqsave(&fsg->lock, flag);
+ fsg->cmnd_size = fsg->cbbuf_cmnd_size;
+ memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
+ fsg->cbbuf_cmnd_size = 0;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+ }
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *d)
+{
+ int rc;
+
+ ep->driver_data = fsg;
+ ep->desc = d;
+ rc = usb_ep_enable(ep);
+ if (rc)
+ ERROR(fsg, "------can't enable %s, result %d\n", ep->name, rc);
+ return rc;
+}
+
+static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
+ struct usb_request **preq)
+{
+ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (*preq)
+ return 0;
+ ERROR(fsg, "can't allocate request for %s\n", ep->name);
+ return -ENOMEM;
+}
+
+/*
+ * Reset interface setting and re-init endpoint state (toggle etc).
+ * Call with altsetting < 0 to disable the interface. The only other
+ * available altsetting is 0, which enables the interface.
+ */
+static int do_set_interface(struct fsg_dev *fsg, int altsetting)
+{
+ int rc = 0;
+ int i;
+ const struct usb_endpoint_descriptor *d;
+
+ if (fsg->running)
+ DBG(fsg, "reset interface\n");
+
+reset:
+ /* Deallocate the requests */
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &fsg->buffhds[i];
+
+ if (bh->inreq) {
+ usb_ep_free_request(fsg->bulk_in, bh->inreq);
+ bh->inreq = NULL;
+ }
+ if (bh->outreq) {
+ usb_ep_free_request(fsg->bulk_out, bh->outreq);
+ bh->outreq = NULL;
+ }
+ }
+ if (fsg->intreq) {
+ usb_ep_free_request(fsg->intr_in, fsg->intreq);
+ fsg->intreq = NULL;
+ }
+
+ /* Disable the endpoints */
+ if (fsg->bulk_in_enabled) {
+ usb_ep_disable(fsg->bulk_in);
+ fsg->bulk_in_enabled = 0;
+ }
+ if (fsg->bulk_out_enabled) {
+ usb_ep_disable(fsg->bulk_out);
+ fsg->bulk_out_enabled = 0;
+ }
+ if (fsg->intr_in_enabled) {
+ usb_ep_disable(fsg->intr_in);
+ fsg->intr_in_enabled = 0;
+ }
+
+ fsg->running = 0;
+ if (altsetting < 0 || rc != 0)
+ return rc;
+
+ DBG(fsg, "set interface %d\n", altsetting);
+
+ /* Enable the endpoints */
+ d = ep_desc(fsg->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc);
+ rc = enable_endpoint(fsg, fsg->bulk_in, d);
+ if (rc != 0)
+ goto reset;
+ fsg->bulk_in_enabled = 1;
+
+ d = ep_desc(fsg->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc);
+ rc = enable_endpoint(fsg, fsg->bulk_out, d);
+ if (rc != 0)
+ goto reset;
+ fsg->bulk_out_enabled = 1;
+ fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+
+ if (transport_is_cbi()) {
+ d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc);
+ rc = enable_endpoint(fsg, fsg->intr_in, d);
+ if (rc != 0)
+ goto reset;
+ fsg->intr_in_enabled = 1;
+ }
+
+ /* Allocate the requests */
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &fsg->buffhds[i];
+ rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq);
+ if (rc != 0)
+ goto reset;
+ rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq);
+ if (rc != 0)
+ goto reset;
+ bh->inreq->buf = bh->outreq->buf = bh->buf;
+ bh->inreq->context = bh->outreq->context = bh;
+ bh->inreq->complete = bulk_in_complete;
+ bh->outreq->complete = bulk_out_complete;
+ }
+ if (transport_is_cbi()) {
+ rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq);
+ if (rc != 0)
+ goto reset;
+ fsg->intreq->complete = intr_in_complete;
+ }
+
+ fsg->running = 1;
+ for (i = 0; i < fsg->nluns; ++i)
+ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+ return rc;
+}
+
+/*
+ * Change our operational configuration. This code must agree with the code
+ * that returns config descriptors, and with interface altsetting code.
+ *
+ * It's also responsible for power management interactions. Some
+ * configurations might not work with our current power sources.
+ * For now we just assume the gadget is always self-powered.
+ */
+static int do_set_config(struct fsg_dev *fsg, u8 new_config)
+{
+ int rc = 0;
+
+ /* Disable the single interface */
+ if (fsg->config != 0) {
+ DBG(fsg, "reset config\n");
+ fsg->config = 0;
+ rc = do_set_interface(fsg, -1);
+ }
+
+ /* Enable the interface */
+ if (new_config != 0) {
+ fsg->config = new_config;
+ rc = do_set_interface(fsg, 0);
+ if (rc != 0)
+ fsg->config = 0; /* Reset on errors */
+ else {
+ char *speed;
+
+ switch (fsg->gadget->speed) {
+ case USB_SPEED_LOW:
+ speed = "low";
+ break;
+ case USB_SPEED_FULL:
+ speed = "full";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "high";
+ break;
+ default:
+ speed = "?";
+ break;
+ }
+ INFO(fsg, "%s speed config #%d\n", speed, fsg->config);
+ }
+ }
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void handle_exception(struct fsg_dev *fsg)
+{
+ siginfo_t info;
+ int sig;
+ int i;
+ int num_active;
+ struct fsg_buffhd *bh;
+ enum fsg_state old_state;
+ u8 new_config;
+ struct lun *curlun;
+ unsigned int exception_req_tag;
+ unsigned long flag;
+ int rc;
+
+ /* Clear the existing signals. Anything but SIGUSR1 is converted
+ * into a high-priority EXIT exception. */
+ for (;;) {
+ sig = dequeue_signal_lock(current, ¤t->blocked, &info);
+ if (!sig)
+ break;
+ if (sig != SIGUSR1) {
+ if (fsg->state < FSG_STATE_EXIT)
+ DBG(fsg, "Main thread exiting on signal\n");
+ raise_exception(fsg, FSG_STATE_EXIT);
+ }
+ }
+
+ /* Cancel all the pending transfers */
+ if (fsg->intreq_busy)
+ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ bh = &fsg->buffhds[i];
+ if (bh->inreq_busy) {
+ printk("bulk in dequeue\n");
+ usb_ep_dequeue(fsg->bulk_in, bh->inreq);
+ }
+ if (bh->outreq_busy) {
+ printk("bulk out dequeue\n");
+ usb_ep_dequeue(fsg->bulk_out, bh->outreq);
+ }
+ }
+
+ /* Wait until everything is idle */
+ for (;;) {
+ num_active = fsg->intreq_busy;
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ bh = &fsg->buffhds[i];
+ num_active += bh->inreq_busy + bh->outreq_busy;
+ }
+ if (num_active == 0)
+ break;
+ if (sleep_thread(fsg))
+ return;
+ }
+
+ /* Clear out the controller's fifos */
+ if (fsg->bulk_in_enabled)
+ usb_ep_fifo_flush(fsg->bulk_in);
+ if (fsg->bulk_out_enabled)
+ usb_ep_fifo_flush(fsg->bulk_out);
+ if (fsg->intr_in_enabled)
+ usb_ep_fifo_flush(fsg->intr_in);
+
+ /* Reset the I/O buffer states and pointers, the SCSI
+ * state, and the exception. Then invoke the handler. */
+ spin_lock_irqsave(&fsg->lock, flag);
+
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ bh = &fsg->buffhds[i];
+ bh->state = BUF_STATE_EMPTY;
+ }
+ fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = &fsg->buffhds[0];
+
+ exception_req_tag = fsg->exception_req_tag;
+ new_config = fsg->new_config;
+ old_state = fsg->state;
+
+ if (old_state == FSG_STATE_ABORT_BULK_OUT)
+ fsg->state = FSG_STATE_STATUS_PHASE;
+ else {
+ for (i = 0; i < fsg->nluns; ++i) {
+ curlun = &fsg->luns[i];
+ curlun->prevent_medium_removal = 0;
+ curlun->sense_data = curlun->unit_attention_data =
+ SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+ fsg->state = FSG_STATE_IDLE;
+ }
+ spin_unlock_irqrestore(&fsg->lock, flag);
+
+ /* Carry out any extra actions required for the exception */
+ switch (old_state) {
+ default:
+ break;
+
+ case FSG_STATE_ABORT_BULK_OUT:
+ send_status(fsg);
+ spin_lock_irqsave(&fsg->lock, flag);
+ if (fsg->state == FSG_STATE_STATUS_PHASE)
+ fsg->state = FSG_STATE_IDLE;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+ break;
+ case FSG_STATE_RESET:
+ /* In case we were forced against our will to halt a
+ * bulk endpoint, clear the halt now. (The SuperH UDC
+ * requires this.) */
+ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
+ usb_ep_clear_halt(fsg->bulk_in);
+
+ if (transport_is_bbb()) {
+ if (fsg->ep0_req_tag == exception_req_tag)
+ ep0_queue(fsg); /* Complete the status stage */
+
+ } else if (transport_is_cbi())
+ send_status(fsg); /* Status by interrupt pipe */
+
+ /* Technically this should go here, but it would only be
+ * a waste of time. Ditto for the INTERFACE_CHANGE and
+ * CONFIG_CHANGE cases. */
+ /* for (i = 0; i < fsg->nluns; ++i)
+ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; */
+ break;
+ case FSG_STATE_INTERFACE_CHANGE:
+ rc = do_set_interface(fsg, 0);
+ if (fsg->ep0_req_tag != exception_req_tag)
+ break;
+ if (rc != 0) { /* STALL on errors */
+ fsg_set_halt(fsg, fsg->ep0);
+ } else /* Complete the status stage */
+ ep0_queue(fsg);
+ break;
+
+ case FSG_STATE_CONFIG_CHANGE:
+ rc = do_set_config(fsg, new_config);
+ if (fsg->ep0_req_tag != exception_req_tag)
+ break;
+ if (rc != 0) { /* STALL on errors */
+ fsg_set_halt(fsg, fsg->ep0);
+ } else /* Complete the status stage */
+ ep0_queue(fsg);
+ break;
+
+ case FSG_STATE_DISCONNECT:
+ fsync_all(fsg);
+ do_set_config(fsg, 0); /* Unconfigured state */
+ if (unlikely(adfu_success_flag == 1)) {
+ usb_gadget_disconnect(fsg->gadget);
+
+ if(need_restart == 1) //shutdown
+ {
+ kernel_restart("upgrade_halt");
+ }
+ else if(need_restart == 2) //reboot
+ {
+ kernel_restart("reboot");
+ }
+ else
+ {
+ //do nothing
+ }
+ }
+ break;
+
+ case FSG_STATE_EXIT:
+ case FSG_STATE_TERMINATED:
+ do_set_config(fsg, 0); /* Free resources */
+ spin_lock_irqsave(&fsg->lock, flag);
+ fsg->state = FSG_STATE_TERMINATED; /* Stop the thread */
+ spin_unlock_irqrestore(&fsg->lock, flag);
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int fsg_main_thread(void *fsg_)
+{
+ struct fsg_dev *fsg = fsg_;
+ unsigned long flag;
+ /* Allow the thread to be killed by a signal, but set the signal mask
+ * to block everything but INT, TERM, KILL, and USR1. */
+ allow_signal(SIGINT);
+ allow_signal(SIGTERM);
+ allow_signal(SIGKILL);
+ allow_signal(SIGUSR1);
+
+ /* Allow the thread to be frozen */
+ set_freezable();
+
+ /* Arrange for userspace references to be interpreted as kernel
+ * pointers. That way we can pass a kernel pointer to a routine
+ * that expects a __user pointer and it will work okay. */
+ set_fs(get_ds());
+
+ /* The main loop */
+ while (fsg->state != FSG_STATE_TERMINATED) {
+
+ if (exception_in_progress(fsg) || signal_pending(current)) {
+ handle_exception(fsg);
+ continue;
+ }
+
+ if (!fsg->running) {
+ sleep_thread(fsg);
+ continue;
+ }
+
+ if (get_next_command(fsg))
+ continue;
+
+ spin_lock_irqsave(&fsg->lock, flag);
+ if (!exception_in_progress(fsg))
+ fsg->state = FSG_STATE_DATA_PHASE;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+
+ if (do_scsi_command(fsg) || finish_reply(fsg))
+ continue;
+
+ spin_lock_irqsave(&fsg->lock, flag);
+ if (!exception_in_progress(fsg))
+ fsg->state = FSG_STATE_STATUS_PHASE;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+
+ if (send_status(fsg))
+ continue;
+
+ spin_lock_irqsave(&fsg->lock, flag);
+ if (!exception_in_progress(fsg))
+ fsg->state = FSG_STATE_IDLE;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+ }
+
+ spin_lock_irqsave(&fsg->lock, flag);
+ fsg->thread_task = NULL;
+ spin_unlock_irqrestore(&fsg->lock, flag);
+
+ /* In case we are exiting because of a signal, unregister the
+ * gadget driver and close the backing file. */
+ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) {
+ usb_gadget_unregister_driver(&fsg_driver);
+ close_all_backing_files(fsg);
+ }
+
+ /* Let the unbind and cleanup routines know the thread has exited */
+ complete_and_exit(&fsg->thread_notifier, 0);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* If the next two routines are called while the gadget is registered,
+ * the caller must own fsg->filesem for writing. */
+#if 0
+static int open_backing_file(struct lun *curlun, const char *filename)
+{
+ int ro;
+ struct file *filp = NULL;
+ int rc = -EINVAL;
+ struct inode *inode = NULL;
+ loff_t size;
+ loff_t num_sectors;
+
+ /* R/W if we can, R/O if we must */
+ ro = curlun->ro;
+ if (!ro) {
+ filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
+ if (-EROFS == PTR_ERR(filp))
+ ro = 1;
+ }
+ if (ro)
+ filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ LINFO(curlun, "unable to open backing file: %s\n", filename);
+ return PTR_ERR(filp);
+ }
+
+ if (!(filp->f_mode & FMODE_WRITE))
+ ro = 1;
+
+ if (filp->f_path.dentry)
+ inode = filp->f_path.dentry->d_inode;
+ if (inode && S_ISBLK(inode->i_mode)) {
+ if (bdev_read_only(inode->i_bdev))
+ ro = 1;
+ } else if (!inode || !S_ISREG(inode->i_mode)) {
+ LINFO(curlun, "invalid file type: %s\n", filename);
+ goto out;
+ }
+
+ /* If we can't read the file, it's no good.
+ * If we can't write the file, use it read-only. */
+ if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
+ LINFO(curlun, "file not readable: %s\n", filename);
+ goto out;
+ }
+ if (!(filp->f_op->write || filp->f_op->aio_write))
+ ro = 1;
+
+ size = i_size_read(inode->i_mapping->host);
+ if (size < 0) {
+ LINFO(curlun, "unable to find file size: %s\n", filename);
+ rc = (int)size;
+ goto out;
+ }
+ num_sectors = size >> 9; /* File size in 512-byte sectors */
+ if (num_sectors == 0) {
+ LINFO(curlun, "file too small: %s\n", filename);
+ rc = -ETOOSMALL;
+ goto out;
+ }
+
+ get_file(filp);
+
+ curlun->devnum = filp->f_path.dentry->d_inode->i_rdev;
+ /* add by wlt, disk type decided */
+ if (MAJOR(filp->f_path.dentry->d_inode->i_rdev) == MAJOR_OF_CARD) {
+ printk("device num:MAJOR: %u MINOR: %u\n",
+ MAJOR(filp->f_path.dentry->d_inode->i_rdev),
+ MINOR(filp->f_path.dentry->d_inode->i_rdev));
+ curlun->disk_type = CARD_MEDIUM;
+ card_dirty_flag = 0;
+ }
+ else if (MAJOR(filp->f_path.dentry->d_inode->i_rdev) == MAJOR_OF_NAND) {
+ printk("device num:MAJOR: %u MINOR: %u\n",
+ MAJOR(filp->f_path.dentry->d_inode->i_rdev),
+ MINOR(filp->f_path.dentry->d_inode->i_rdev));
+ curlun->disk_type = NAND_MEDIUM;
+ nand_dirty_flag = 0;
+ }
+ else if (MAJOR(filp->f_path.dentry->d_inode->i_rdev) == MAJOR_OF_MMS) {
+ printk("device num:MAJOR: %u MINOR: %u\n",
+ MAJOR(filp->f_path.dentry->d_inode->i_rdev),
+ MINOR(filp->f_path.dentry->d_inode->i_rdev));
+ curlun->disk_type = MMS_MEDIUM;
+ card_dirty_flag = 0;
+ }
+ curlun->ro = ro;
+ curlun->filp = filp;
+ curlun->file_length = size;
+ curlun->num_sectors = num_sectors;
+ LDBG(curlun, "open backing file: %s\n", filename);
+ rc = 0;
+
+out:
+ filp_close(filp, current->files);
+ return rc;
+}
+#endif
+static void close_backing_file(struct lun *curlun)
+{
+ if (curlun->filp) {
+ LDBG(curlun, "close backing file\n");
+ fput(curlun->filp);
+ curlun->filp = NULL;
+ }
+}
+
+static void close_all_backing_files(struct fsg_dev *fsg)
+{
+ int i;
+
+ for (i = 0; i < fsg->nluns; ++i)
+ close_backing_file(&fsg->luns[i]);
+}
+
+static ssize_t show_ro(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lun *curlun = dev_to_lun(dev);
+
+ return sprintf(buf, "%d\n", curlun->ro);
+}
+
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lun *curlun = dev_to_lun(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
+ char *p;
+ ssize_t rc;
+
+ down_read(&fsg->filesem);
+ if (backing_file_is_open(curlun)) { /* Get the complete pathname */
+ p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
+ if (IS_ERR(p))
+ rc = PTR_ERR(p);
+ else {
+ rc = strlen(p);
+ memmove(buf, p, rc);
+ buf[rc] = '\n'; /* Add a newline */
+ buf[++rc] = 0;
+ }
+ } else { /* No file, return 0 bytes */
+ *buf = 0;
+ rc = 0;
+ }
+ up_read(&fsg->filesem);
+ return rc;
+}
+
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t rc = count;
+ struct lun *curlun = dev_to_lun(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
+ int i;
+
+ if (sscanf(buf, "%d", &i) != 1)
+ return -EINVAL;
+
+ /* Allow the write-enable status to change only while the backing file
+ * is closed. */
+ down_read(&fsg->filesem);
+ if (backing_file_is_open(curlun)) {
+ LDBG(curlun, "read-only status change prevented\n");
+ rc = -EBUSY;
+ } else {
+ curlun->ro = !!i;
+ LDBG(curlun, "read-only status set to %d\n", curlun->ro);
+ }
+ up_read(&fsg->filesem);
+ return rc;
+}
+
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return count;
+#if 0
+ struct lun *curlun = dev_to_lun(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
+ int rc = 0;
+#if 0
+ if (curlun->prevent_medium_removal
+ && backing_file_is_open(curlun)) {
+ LDBG(curlun, "eject attempt prevented\n");
+ return -EBUSY;
+ /* "Door is locked" */
+ }
+#endif
+ /* Remove a trailing newline */
+ if (count > 0 && buf[count - 1] == '\n')
+ ((char *)buf)[count - 1] = 0;
+ /* Ugh! */
+
+ /* Eject current medium */
+ down_write(&fsg->filesem);
+ if (backing_file_is_open(curlun)) {
+ close_backing_file(curlun);
+ curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+ }
+
+ /* Load new medium */
+ if (count > 0 && buf[0]) {
+ rc = open_backing_file(curlun, buf);
+ if (rc == 0)
+ curlun->unit_attention_data =
+ SS_NOT_READY_TO_READY_TRANSITION;
+ }
+ up_write(&fsg->filesem);
+ return rc < 0 ? rc : count;
+#endif
+}
+
+/* The write permissions and store_xxx pointers are set in fsg_bind() */
+static DEVICE_ATTR(ro, 0444, show_ro, NULL);
+static DEVICE_ATTR(file, 0444, show_file, NULL);
+
+
+static ssize_t show_need_format(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d", need_format);
+}
+
+static ssize_t store_need_format(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ /* for future use */
+ return 0;
+}
+
+static DEVICE_ATTR(need_format, 0444, show_need_format, NULL);
+
+static ssize_t show_fs_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s", format_fs_name);
+}
+
+static ssize_t show_disk_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s", format_disk_name);
+}
+
+static ssize_t show_mbrc_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s", mbrc_name);
+}
+
+static ssize_t show_disk_label(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s", format_disk_label);
+}
+
+static DEVICE_ATTR(format_fs_name, 0444, show_fs_name, NULL);
+static DEVICE_ATTR(format_disk_name, 0444, show_disk_name, NULL);
+static DEVICE_ATTR(format_disk_label, 0444, show_disk_label, NULL);
+static DEVICE_ATTR(mbrc_name, 0444, show_mbrc_name, NULL);
+/*-------------------------------------------------------------------------*/
+
+static void fsg_release(struct kref *ref)
+{
+ struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
+
+ kfree(fsg->luns);
+ kfree(fsg);
+}
+
+static void lun_release(struct device *dev)
+{
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
+
+ kref_put(&fsg->ref, fsg_release);
+}
+
+static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
+{
+ struct fsg_dev *fsg = get_gadget_data(gadget);
+ int i;
+ struct lun *curlun;
+ struct usb_request *req = fsg->ep0req;
+
+ DBG(fsg, "unbind\n");
+ clear_bit(REGISTERED, &fsg->atomic_bitflags);
+
+ /* Unregister the sysfs attribute files and the LUNs */
+ for (i = 0; i < fsg->nluns; ++i) {
+ curlun = &fsg->luns[i];
+ if (curlun->registered) {
+ device_remove_file(&curlun->dev, &dev_attr_ro);
+ device_remove_file(&curlun->dev, &dev_attr_file);
+ device_unregister(&curlun->dev);
+ curlun->registered = 0;
+ }
+ }
+
+ /* If the thread isn't already dead, tell it to exit now */
+ if (fsg->state != FSG_STATE_TERMINATED) {
+ raise_exception(fsg, FSG_STATE_EXIT);
+ wait_for_completion(&fsg->thread_notifier);
+
+ /* The cleanup routine waits for this completion also */
+ complete(&fsg->thread_notifier);
+ }
+
+ /* Free the data buffers */
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ /* kfree(fsg->buffhds[i].buf); */
+ struct fsg_buffhd *bh = &fsg->buffhds[i];
+ if (bh->buf)
+ kfree(bh->buf);
+ }
+ /* Free the request and buffer for endpoint 0 */
+ if (req) {
+ kfree(req->buf);
+ usb_ep_free_request(fsg->ep0, req);
+ }
+
+ set_gadget_data(gadget, NULL);
+}
+
+static int __init check_parameters(struct fsg_dev *fsg)
+{
+ int prot;
+ int gcnum;
+
+ /* Store the default values */
+ mod_data.transport_type = USB_PR_BULK;
+ mod_data.transport_name = "Bulk-only";
+ mod_data.protocol_type = USB_SC_8070;
+ mod_data.protocol_name = "8070i";
+
+ if (gadget_is_at91(fsg->gadget))
+ mod_data.can_stall = 0;
+
+ if (mod_data.release == 0xffff) { /* Parameter wasn't set */
+ gcnum = get_default_bcdDevice(); //usb_gadget_controller_number(fsg->gadget);
+ if (gcnum >= 0)
+ mod_data.release = 0x0300 + gcnum;
+ else {
+ WARNING(fsg, "controller '%s' not recognized\n",
+ fsg->gadget->name);
+ mod_data.release = 0x0399;
+ }
+ }
+
+ prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
+ return 0;
+}
+
+/* just for test */
+#if 0
+static int do_ADFU_acmbr(struct fsg_dev *fsg)
+{
+ struct lun *curlun = fsg->curlun;
+ u32 lba;
+ struct fsg_buffhd *bh;
+ int rc;
+ u32 amount_left;
+ loff_t file_offset, file_offset_tmp;
+ unsigned int amount;
+ unsigned int partial_page;
+ ssize_t nread;
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+ lba = 0;
+ file_offset = ((loff_t) lba) << 9;
+
+ /* Carry out the file reads */
+ amount_left = fsg->data_size_from_cmnd = 0x400;
+ if (unlikely(amount_left == 0))
+ return -EIO; /* No default reply */
+
+ for (;;) {
+
+ /* Figure out how much we need to read:
+ * Try to read the remaining amount.
+ * But don't read more than the buffer size.
+ * And don't try to read past the end of the file.
+ * Finally, if we're not at a page boundary, don't read past
+ * the next page.
+ * If this means reading 0 then we were asked to read past
+ * the end of file. */
+ amount = min((unsigned int)amount_left, mod_data.buflen);
+ amount = min((loff_t) amount,
+ curlun->file_length - file_offset);
+ partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
+ if (partial_page > 0)
+ amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
+ partial_page);
+
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg);
+ if (rc)
+ return rc;
+ }
+
+ /* If we were asked to read past the end of file,
+ * end with an empty buffer. */
+ if (amount == 0) {
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
+ bh->inreq->length = 0;
+ bh->state = BUF_STATE_FULL;
+ break;
+ }
+
+ /* Perform the read */
+ file_offset_tmp = file_offset;
+ nread = vfs_read(curlun->filp,
+ (char __user *)bh->buf,
+ amount, &file_offset_tmp);
+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+ (unsigned long long)file_offset, (int)nread);
+ if (signal_pending(current))
+ return -EINTR;
+
+ if (nread < 0) {
+ LDBG(curlun, "error in file read: %d\n", (int)nread);
+ nread = 0;
+ } else if (nread < amount) {
+ LDBG(curlun, "partial file read: %d/%u\n",
+ (int)nread, amount);
+ nread -= (nread & 511); /* Round down to a block */
+ }
+ file_offset += nread;
+ amount_left -= nread;
+ fsg->residue -= nread;
+ bh->inreq->length = nread;
+ bh->state = BUF_STATE_FULL;
+
+ /* If an error occurred, report it and its position */
+ if (nread < amount) {
+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+ curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
+ break;
+ }
+
+ if (amount_left == 0)
+ break; /* No more left to read */
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ fsg->next_buffhd_to_fill = bh->next;
+ }
+
+ return -EIO; /* No default reply */
+}
+#endif
+
+static int fsg_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver)
+{
+ struct fsg_dev *fsg = the_fsg;
+ int rc;
+ int i;
+ struct lun *curlun;
+ struct usb_ep *ep;
+ struct usb_request *req;
+ char *pathbuf, *p;
+
+ fsg->gadget = gadget;
+ set_gadget_data(gadget, fsg);
+ fsg->ep0 = gadget->ep0;
+ fsg->ep0->driver_data = fsg;
+ rc = check_parameters(fsg);
+ if (rc != 0)
+ goto out;
+
+ if (mod_data.removable) { /* Enable the store_xxx attributes */
+ dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644;
+ dev_attr_ro.store = store_ro;
+ dev_attr_file.store = store_file;
+ }
+
+ dev_attr_need_format.store = store_need_format;
+
+ /* Find out how many LUNs there should be */
+ i = mod_data.nluns;
+ if (i == 0)
+ i = max(mod_data.num_filenames, 1u);
+ if (i > MAX_LUNS) {
+ ERROR(fsg, "invalid number of LUNs: %d\n", i);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Create the LUNs, open their backing files, and register the
+ * LUN devices in sysfs. */
+ fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL);
+ if (!fsg->luns) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ fsg->nluns = i;
+
+ mod_data.file[0] = "/dev/actb";
+ mod_data.file[1] = "/dev/acta";
+
+ for (i = 0; i < fsg->nluns; ++i) {
+ curlun = &fsg->luns[i];
+ curlun->ro = mod_data.ro[i];
+ curlun->dev.release = lun_release;
+ curlun->dev.parent = &gadget->dev;
+ curlun->dev.driver = &fsg_driver.driver;
+ dev_set_drvdata(&curlun->dev, fsg);
+ dev_set_name(&curlun->dev, "%s-lun%d",
+ dev_name(&gadget->dev), i);
+ rc = device_register(&curlun->dev);
+ if (rc != 0) {
+ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
+ goto out;
+ }
+ if ((rc = device_create_file(&curlun->dev, &dev_attr_ro)) != 0 ||
+ (rc = device_create_file(&curlun->dev, &dev_attr_file)) != 0) {
+ device_unregister(&curlun->dev);
+ goto out;
+ }
+
+ /* when used for adfu, we should create a sysfile to support format nand */
+ rc = device_create_file(&curlun->dev, &dev_attr_need_format);
+ rc = device_create_file(&curlun->dev, &dev_attr_format_fs_name);
+ rc = device_create_file(&curlun->dev, &dev_attr_format_disk_name);
+ rc = device_create_file(&curlun->dev, &dev_attr_format_disk_label);
+
+ rc = device_create_file(&curlun->dev, &dev_attr_mbrc_name);
+
+ curlun->registered = 1;
+ kref_get(&fsg->ref);
+#if 0
+ if (mod_data.file[i] && *mod_data.file[i]) {
+ rc = open_backing_file(curlun, mod_data.file[i]);
+ if (rc != 0)
+ goto out;
+ } else if (!mod_data.removable) {
+ ERROR(fsg, "no file given for LUN%d\n", i);
+ rc = -EINVAL;
+ goto out;
+ }
+#endif
+ }
+
+ /* Find all the endpoints we will use */
+ usb_ep_autoconfig_reset(gadget);
+ ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+ ep->driver_data = fsg; /* claim the endpoint */
+ fsg->bulk_in = ep;
+
+ ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc);
+ if (!ep)
+ goto autoconf_fail;
+ ep->driver_data = fsg; /* claim the endpoint */
+ fsg->bulk_out = ep;
+
+ if (transport_is_cbi()) {
+ ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+ ep->driver_data = fsg; /* claim the endpoint */
+ fsg->intr_in = ep;
+ }
+
+ /* Fix up the descriptors */
+ device_desc.idVendor = cpu_to_le16(mod_data.vendor);
+ device_desc.idProduct = cpu_to_le16(mod_data.product);
+ device_desc.bcdDevice = cpu_to_le16(mod_data.release);
+
+ i = (transport_is_cbi() ? 3 : 2); /* Number of endpoints */
+ intf_desc.bNumEndpoints = i;
+ intf_desc.bInterfaceSubClass = mod_data.protocol_type;
+ intf_desc.bInterfaceProtocol = mod_data.transport_type;
+ fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+ if (act_gadget_is_dualspeed(gadget)) {
+ hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+
+ /* Assume endpoint addresses are the same for both speeds */
+ hs_bulk_in_desc.bEndpointAddress =
+ fs_bulk_in_desc.bEndpointAddress;
+ hs_bulk_out_desc.bEndpointAddress =
+ fs_bulk_out_desc.bEndpointAddress;
+ hs_intr_in_desc.bEndpointAddress =
+ fs_intr_in_desc.bEndpointAddress;
+ }
+
+ if (gadget_is_otg(gadget))
+ otg_desc.bmAttributes |= USB_OTG_HNP;
+
+ rc = -ENOMEM;
+
+ /* Allocate the request and buffer for endpoint 0 */
+ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
+ if (!req)
+ goto out;
+ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
+ if (!req->buf)
+ goto out;
+ req->complete = ep0_complete;
+
+ /* Allocate the data buffers */
+ for (i = 0; i < NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &fsg->buffhds[i];
+
+ /* Allocate for the bulk-in endpoint. We assume that
+ * the buffer will also work with the bulk-out (and
+ * interrupt-in) endpoint. */
+ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
+ if (!bh->buf)
+ goto out;
+ bh->next = bh + 1;
+ }
+ fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0];
+
+ /* This should reflect the actual gadget power source */
+ usb_gadget_set_selfpowered(gadget);
+
+ snprintf(manufacturer, sizeof manufacturer, "Actions Disk");
+#if 0
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+#endif
+ /* On a real device, serial[] would be loaded from permanent
+ * storage. We just encode it from the driver version string. */
+ if (uniSerial == 0)
+ {
+ for (i = 0; i < sizeof(serial) - 2; i += 2) {
+ sprintf(&serial[i], "%02X", '0');
+ }
+ serial[0] = 0x2C; //invalid serial
+ }
+ /* printk("Now The Serial is %s\n", serial); */
+ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+ "file-storage-gadget");
+ if (IS_ERR(fsg->thread_task)) {
+ rc = PTR_ERR(fsg->thread_task);
+ goto out;
+ }
+#if 0
+ INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+ INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
+#endif
+ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+ for (i = 0; i < fsg->nluns; ++i) {
+ curlun = &fsg->luns[i];
+ if (backing_file_is_open(curlun)) {
+ p = NULL;
+ if (pathbuf) {
+ p = d_path(&curlun->filp->f_path,
+ pathbuf, PATH_MAX);
+ if (IS_ERR(p))
+ p = NULL;
+ }
+ LINFO(curlun, "ro=%d, file: %s\n",
+ curlun->ro, (p ? p : "(error)"));
+ }
+ }
+ kfree(pathbuf);
+
+ DBG(fsg, "transport=%s (x%02x)\n",
+ mod_data.transport_name, mod_data.transport_type);
+ DBG(fsg, "protocol=%s (x%02x)\n",
+ mod_data.protocol_name, mod_data.protocol_type);
+ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
+ mod_data.vendor, mod_data.product, mod_data.release);
+ DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
+ mod_data.removable, mod_data.can_stall, mod_data.buflen);
+ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
+
+ set_bit(REGISTERED, &fsg->atomic_bitflags);
+
+ /* Tell the thread to start working */
+ wake_up_process(fsg->thread_task);
+
+ return 0;
+
+autoconf_fail:
+ ERROR(fsg, "unable to autoconfigure all endpoints\n");
+ rc = -ENOTSUPP;
+
+out:
+ fsg->state = FSG_STATE_TERMINATED; /* The thread is dead */
+ fsg_unbind(gadget);
+ close_all_backing_files(fsg);
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void fsg_suspend(struct usb_gadget *gadget)
+{
+ struct fsg_dev *fsg = get_gadget_data(gadget);
+
+ DBG(fsg, "suspend\n");
+ set_bit(SUSPENDED, &fsg->atomic_bitflags);
+}
+
+static void fsg_resume(struct usb_gadget *gadget)
+{
+ struct fsg_dev *fsg = get_gadget_data(gadget);
+
+ DBG(fsg, "resume\n");
+ clear_bit(SUSPENDED, &fsg->atomic_bitflags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver fsg_driver = {
+ .max_speed = USB_SPEED_HIGH,
+ .function = (char *)longname,
+ .bind = fsg_bind,
+ .unbind = fsg_unbind,
+ .disconnect = fsg_disconnect,
+ .setup = fsg_setup,
+ .suspend = fsg_suspend,
+ .resume = fsg_resume,
+
+ .driver = {
+ .name = (char *)shortname,
+ .owner = THIS_MODULE,
+ /* .release = ... */
+ /* .suspend = ... */
+ /* .resume = ... */
+ },
+};
+
+static int __init fsg_alloc(void)
+{
+ struct fsg_dev *fsg;
+
+ fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+ if (!fsg)
+ return -ENOMEM;
+ spin_lock_init(&fsg->lock);
+ init_rwsem(&fsg->filesem);
+ kref_init(&fsg->ref);
+ init_completion(&fsg->thread_notifier);
+
+ the_fsg = fsg;
+ return 0;
+}
+
+extern int owl_get_boot_mode(void);
+int __init fsg_init(void)
+{
+ int rc;
+ struct fsg_dev *fsg;
+
+
+ if(owl_get_boot_mode() != OWL_BOOT_MODE_UPGRADE)
+ return -EACCES;
+ adfu_success_flag = 0;
+
+ no_finish_reply = 0;
+
+ rc = fsg_alloc();
+ if (rc != 0)
+ return rc;
+ fsg = the_fsg;
+ rc = usb_gadget_probe_driver(&fsg_driver);
+ if (rc != 0)
+ kref_put(&fsg->ref, fsg_release);
+ usb_gadget_connect(fsg->gadget);
+ return rc;
+}
+module_init(fsg_init);
+
+void __exit fsg_cleanup(void)
+{
+ struct fsg_dev *fsg = the_fsg;
+ printk("file-storage unload ... \n");
+ /* Unregister the driver iff the thread hasn't already done so */
+ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
+ usb_gadget_unregister_driver(&fsg_driver);
+
+ /* Wait for the thread to finish up */
+ wait_for_completion(&fsg->thread_notifier);
+
+ close_all_backing_files(fsg);
+ kref_put(&fsg->ref, fsg_release);
+}
+module_exit(fsg_cleanup);
diff --git a/drivers/usb/gadget/legacy/adfuserver.h b/drivers/usb/gadget/legacy/adfuserver.h
new file mode 100644
index 0000000..cac29bb
--- /dev/null
+++ b/drivers/usb/gadget/legacy/adfuserver.h
@@ -0,0 +1,85 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Actions Semi Inc.
+*/
+/******************************************************************************/
+
+/******************************************************************************/
+#ifndef __MBR_INFO_H__
+#define __MBR_INFO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_PARTITION 12
+#define HDCP_KEY_SIZE 308 //bytes
+#define SERIAL_NO_SIZE 16 //bytes
+#define PARTITION_TBL_SIZE (MAX_PARTITION * sizeof(partition_info_t))
+
+
+#define RECOVERY_ACCESS 0
+#define MISC_ACCESS 1
+#define ROOTFS_ACCESS 2
+#define ANDROID_DATA_ACCESS 3
+#define ANDROID_CACHE_ACCESS 4
+
+#define SNAPSHOT_ACCESS 5
+#define WHD_ACCESS 6
+
+#define CONFIG_RW_ACCESS 7
+
+
+#define UDISK_ACCESS 10
+
+typedef struct
+{
+ unsigned char flash_ptn; //flash partition number
+ unsigned char partition_num; //ÿ\B8\F6\B7\D6\C7\F8\B6\D4Ӧ\C6\E4\CB\F9\D4ڵ\C4flash partition\B5ı\E0\BA\C5
+ unsigned short reserved; //reserved\A3\BA\BD\AB\CD\D8չ\B3ɸ÷\D6\C7\F8\B5\C4\CA\F4\D0\D4
+ unsigned int partition_cap; //\B6\D4Ӧ\B7\D6\C7\F8\B5Ĵ\F3С
+}__attribute__ ((packed)) partition_info_t;
+
+
+typedef struct
+{
+ unsigned char flash_ptn; //flash partition number
+ unsigned char partition_num; //ÿ\B8\F6\B7\D6\C7\F8\B6\D4Ӧ\C6\E4\CB\F9\D4ڵ\C4flash partition\B5ı\E0\BA\C5
+ unsigned short phy_info; //reserved\A3\BA\BD\AB\CD\D8չ\B3ɸ÷\D6\C7\F8\B5\C4\CA\F4\D0\D4
+ unsigned int partition_cap; //\B6\D4Ӧ\B7\D6\C7\F8\B5Ĵ\F3С
+}__attribute__ ((packed)) CapInfo_t;
+
+
+/*
+ * don't re-order
+ */
+typedef struct
+{
+ partition_info_t partition_info[MAX_PARTITION]; //\B7\D6\C7\F8\D0\C5Ϣ\B1\ED
+ unsigned char HdcpKey[HDCP_KEY_SIZE];
+ unsigned char SerialNo[SERIAL_NO_SIZE];
+ unsigned char reserved[0x400 - PARTITION_TBL_SIZE - HDCP_KEY_SIZE - SERIAL_NO_SIZE]; //mbr_info_t\A3\AC\B4\F3СΪ1k\A3\ACΪ\D2Ժ\F3\C0\A9չ
+}__attribute__ ((packed)) mbr_info_t;
+
+
+
+/********************************************************************
+\B7\D6\C7\F8\B7\BDʽ\A3\ACԭ\D4\F2\C9Ϸ\D6\C7\F8\B0\B4˳\D0\F2\C5\C5\C1У\BA
+ flash_ptn partition_num partition_cap\B5ĵ\A5λ
+mbrc: 0 0 block
+vmlinux 0 1 M
+rootfs 1 0 M
+configfs 1 1 M
+others 2 0~n M
+
+\D2\D4partition_numΪ0xff\B1\ED\C3\F7\D7\EE\BA\F3һ\B8\F6\B7\D6\C7\F8
+*********************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
old mode 100644
new mode 100755
index 73a4dfb..f2c5d8d
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -14,9 +14,54 @@
#include <linux/string.h>
#include <linux/device.h>
#include <linux/nls.h>
+#include <linux/fs.h>
+#include <linux/of.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <asm/uaccess.h>
+
+#define UNIFIED_ASCII_SERIALNUM 0 //
+#define UNIFIED_UNICODE_SERIALNUM 1 //?\A1\ECa3?\A1\EC???unicode??
+#define NOUNIFIED_UNICODE_SERIALNUM 2 //??\A8\A8??\A1\ECa3?\A1\EC???unicode??
+#define NOUNIFIED_ASCII_SERIALNUM 3 //
+#define USB3_UMON_FDT_COMPATIBLE_ATM7039C "actions,atm7039c-usb"
+#define USB3_UMON_FDT_COMPATIBLE_ATM7059A "actions,atm7059tc-usb"
+#define DEFAULT_SERIAL_NO "0123456789ABCDEF"
+
+char usbserialnumber[33];
+int HAVE_SERIALNUM = 1;
+
+//extern int get_config(const char *key, char *buff, int len);
+
+int usbgadget_get_serialnumber(void)
+{
+ struct file *filp = NULL;
+ mm_segment_t old_fs;
+ loff_t file_offset =0;
+ int length;
+
+ /*get usb serialnumber from */
+ filp = filp_open("/data/usb_serialnumber", O_RDONLY, 0);
+ if(IS_ERR(filp)) {
+ printk("open usb_serialnumber ERR\n");
+ HAVE_SERIALNUM =0;
+ return PTR_ERR(filp);
+ }
+
+ HAVE_SERIALNUM =1;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ length = vfs_read(filp, usbserialnumber, 32, &file_offset);
+ set_fs(old_fs);
+
+ filp_close(filp, NULL);
+
+ usbserialnumber[32] = '\0';
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usbgadget_get_serialnumber);
/**
@@ -40,7 +85,10 @@ int
usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
{
struct usb_string *s;
- int len;
+ int len, value;
+ char key[33];
+ struct device_node *fdt_node;
+ const __be32 *property;
/* descriptor 0 has the language id */
if (id == 0) {
@@ -59,12 +107,62 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
return -EINVAL;
/* string descriptors have length, tag, then UTF16-LE text */
- len = min ((size_t) 126, strlen (s->s));
- len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
- (wchar_t *) &buf[2], 126);
- if (len < 0)
- return -EINVAL;
- buf [0] = (len + 1) * 2;
+ if(id == 4) {
+ fdt_node = of_find_compatible_node(NULL, NULL, USB3_UMON_FDT_COMPATIBLE_ATM7039C);
+ if (NULL == fdt_node) {
+ fdt_node = of_find_compatible_node(NULL, NULL, USB3_UMON_FDT_COMPATIBLE_ATM7059A);
+ if (NULL == fdt_node) {
+ printk("<usbstring>err: no usb3-fdt-compatible\n");
+ return -EINVAL;
+ }
+ }
+ property = of_get_property(fdt_node, "usb_serialnumber_config", NULL);
+ value = be32_to_cpup(property);
+
+ if(!HAVE_SERIALNUM){
+ printk("there is no serialnum file store. use UNIFIED_UNICODE_SN forcely\n");
+ value = UNIFIED_UNICODE_SERIALNUM;
+ }
+ printk("usb serialnumber config is %d\n", value);
+ switch(value) {
+ case UNIFIED_UNICODE_SERIALNUM:
+ len = min ((size_t) 126, strlen (DEFAULT_SERIAL_NO));
+ len = utf8s_to_utf16s(DEFAULT_SERIAL_NO, len, UTF16_LITTLE_ENDIAN,
+ (wchar_t *) &buf[2], 126);
+ if (len < 0)
+ return -EINVAL;
+ buf [0] = (len + 1) * 2;
+ break;
+
+ case NOUNIFIED_UNICODE_SERIALNUM:
+ len = sizeof(usbserialnumber) / 2;
+ memcpy(key, usbserialnumber, len);
+ key[len] = '\0';
+ len = utf8s_to_utf16s(usbserialnumber, len, UTF16_LITTLE_ENDIAN,
+ (wchar_t *) &buf[2], 126);
+ if (len < 0)
+ return -EINVAL;
+ buf [0] = (len + 1) * 2;
+ break;
+ case NOUNIFIED_ASCII_SERIALNUM:
+ case UNIFIED_ASCII_SERIALNUM:
+ default:
+ len = min ((size_t) 126, strlen (DEFAULT_SERIAL_NO));
+ strncpy(&buf[2], DEFAULT_SERIAL_NO, len);
+ for(; len < 32; len++)
+ buf[len] = 0x2e;
+ buf [0] = 32;
+ break;
+
+ }
+ }else {
+ len = min ((size_t) 126, strlen (s->s));
+ len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, (wchar_t *) &buf[2], 126);
+ if (len < 0)
+ return -EINVAL;
+ buf [0] = (len + 1) * 2;
+ }
+
buf [1] = USB_DT_STRING;
return buf [0];
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
old mode 100644
new mode 100755
index 197a6a3..f2ad838
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -188,6 +188,13 @@ config USB_EHCI_HCD_STI
Enable support for the on-chip EHCI controller found on
STMicroelectronics consumer electronics SoC's.
+config USB_EHCI_HCD_SYNOPSYS
+ tristate "Support for Synopsys Host-AHB USB 2.0 controller"
+ depends on USB_EHCI_HCD
+ ---help---
+ Enable support for onchip USB controllers based on DesignWare USB 2.0
+ Host-AHB Controller IP from Synopsys.
+
config USB_EHCI_HCD_AT91
tristate "Support for Atmel on-chip EHCI USB controller"
depends on USB_EHCI_HCD && ARCH_AT91
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
old mode 100644
new mode 100755
index da03d8b..6d69301
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -14,7 +14,7 @@ xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-y += xhci-trace.o
-xhci-plat-hcd-y := xhci-plat.o
+xhci-plat-hcd-y := xhci-plat.o uhost_hotplug_handle.o
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
xhci-plat-hcd-y += xhci-mvebu.o
endif
@@ -33,6 +33,7 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o
+obj-$(CONFIG_USB_EHCI_HCD_SYNOPSYS) += ehci-h20ahb.o
obj-$(CONFIG_USB_EHCI_HCD_STI) += ehci-st.o
obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o
@@ -74,3 +75,5 @@ 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
+obj-$(CONFIG_USB_AOTG_HCD) += acts_hub.o
+acts_hub-y := aotg_debug.o aotg_ring.o aotg_hcd.o aotg_mon.o
diff --git a/drivers/usb/host/aotg_debug.c b/drivers/usb/host/aotg_debug.c
new file mode 100644
index 0000000..1bddc82
--- /dev/null
+++ b/drivers/usb/host/aotg_debug.c
@@ -0,0 +1,985 @@
+/*
+ * (C) Copyright www.actions-semi.com 2012-2014
+ * Written by houjingkun. <houjingkun at actions-semi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
+#include <linux/timer.h>
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/../../fs/proc/internal.h>
+
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+
+#include "aotg_hcd.h"
+#include "aotg_regs.h"
+#include "aotg_plat_data.h"
+//#include "aotg_dma.h"
+#include "aotg_debug.h"
+
+
+char aotg_hcd_proc_sign = 'n';
+unsigned int aotg_trace_onff = 0;
+
+void aotg_dbg_proc_output_ep(void)
+{
+ return;
+}
+
+void aotg_dbg_put_info(char *info0, unsigned int info1, unsigned int info2, unsigned int info3)
+{
+ return;
+}
+
+void aotg_dbg_output_info(void)
+{
+ return;
+}
+
+void aotg_dbg_put_q(struct aotg_queue *q, unsigned int num, unsigned int type, unsigned int len)
+{
+ return;
+}
+
+void aotg_dbg_finish_q(struct aotg_queue *q)
+{
+ return;
+}
+
+void aotg_dump_ep_reg(struct aotg_hcd *acthcd, int ep_index, int is_out)
+{
+ int index_multi = ep_index - 1;
+ if (NULL == acthcd) {
+ ACT_HCD_ERR
+ return;
+ }
+
+ if (ep_index > 15) {
+ printk("ep_index : %d too big, err!\n", ep_index);
+ return;
+ }
+
+ printk("=== dump hc-%s ep%d reg info ===\n",
+ is_out ? "out" : "in", ep_index);
+
+ if (ep_index == 0) {
+ printk(" HCIN0BC(0x%p) : 0x%X\n",
+ acthcd->base + HCIN0BC, usb_readb(acthcd->base + HCIN0BC));
+ printk(" EP0CS(0x%p) : 0x%X\n",
+ acthcd->base + EP0CS, usb_readb(acthcd->base + EP0CS));
+ printk(" HCOUT0BC(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT0BC, usb_readb(acthcd->base + HCOUT0BC));
+ printk(" HCEP0CTRL(0x%p) : 0x%X\n",
+ acthcd->base + HCEP0CTRL, usb_readb(acthcd->base + HCEP0CTRL));
+ printk(" HCIN0ERR(0x%p) : 0x%X\n",
+ acthcd->base + HCIN0ERR, usb_readb(acthcd->base + HCIN0ERR));
+ return;
+ }
+
+ if (is_out) {
+ printk(" HCOUT%dBC(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1BC + index_multi * 0x8,
+ usb_readw(acthcd->base + HCOUT1BC+ index_multi *0x8));
+ printk(" HCOUT%dCON(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1CON + index_multi * 0x8,
+ usb_readb(acthcd->base + HCOUT1CON + index_multi *0x8));
+ printk(" HCOUT%dCS(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1CS + index_multi * 0x8,
+ usb_readb(acthcd->base + HCOUT1CS + index_multi *0x8));
+ printk(" HCOUT%dCTRL(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1CTRL + index_multi * 0x4,
+ usb_readb(acthcd->base + HCOUT1CTRL + index_multi *0x4));
+ printk(" HCOUT%dERR(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1ERR + index_multi * 0x4,
+ usb_readb(acthcd->base + HCOUT1ERR + index_multi *0x4));
+ printk(" HCOUT%dSTADDR(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1STADDR + index_multi * 0x4,
+ usb_readl(acthcd->base + HCOUT1STADDR + index_multi * 0x4));
+ printk(" HCOUT%dMAXPCK(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1MAXPCK + index_multi * 0x2,
+ usb_readw(acthcd->base + HCOUT1MAXPCK + index_multi * 0x2));
+
+ printk(" HCOUT%dDMASTADDR(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1DMASTADDR + index_multi * 0x8,
+ usb_readl(acthcd->base + HCOUT1DMASTADDR + index_multi * 0x8));
+ printk(" HCOUT%dDMACOUNTER(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCOUT1DMACOUNTER + index_multi * 0x8,
+ usb_readl(acthcd->base + HCOUT1DMACOUNTER + index_multi * 0x8));
+ } else {
+ printk(" HCIN%dBC(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1BC + index_multi * 0x8,
+ usb_readw(acthcd->base + HCIN1BC + index_multi *0x8));
+ printk(" HCIN%dCON(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1CON+ index_multi * 0x8,
+ usb_readb(acthcd->base + HCIN1CON+ index_multi *0x8));
+ printk(" HCIN%dCS(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1CS + index_multi * 0x8,
+ usb_readb(acthcd->base + HCIN1CS + index_multi *0x8));
+ printk(" HCIN%dCS(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1CTRL + index_multi * 0x4,
+ usb_readb(acthcd->base + HCIN1CTRL+ index_multi *0x4));
+ printk(" HCIN%dERR(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1ERR + index_multi * 0x4,
+ usb_readb(acthcd->base + HCIN1ERR + index_multi *0x4));
+ printk(" HCIN%dSTADDR(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1STADDR + index_multi * 0x4,
+ usb_readl(acthcd->base + HCIN1STADDR + index_multi *0x4));
+ printk(" HCIN%dMAXPCK(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1MAXPCK + index_multi * 0x2,
+ usb_readw(acthcd->base + HCIN1MAXPCK + index_multi * 0x2));
+
+ printk(" HCIN%dDMASTADDR(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1DMASTADDR + index_multi * 0x8,
+ usb_readl(acthcd->base + HCIN1DMASTADDR + index_multi * 0x8));
+ printk(" HCIN%dDMACOUNTER(0x%p) : 0x%X\n", ep_index,
+ acthcd->base + HCIN1DMACOUNTER + index_multi * 0x8,
+ usb_readl(acthcd->base + HCIN1DMACOUNTER + index_multi * 0x8));
+ }
+
+}
+
+#ifdef AOTG_REG_DUMP
+void aotg_dbg_regs(struct aotg_hcd *acthcd)
+{
+ struct aotg_plat_data *data = acthcd->port_specific;
+#if 1
+ int i = 0;
+
+ do {
+ printk(" USB reg(0x%p):0x%X ", acthcd->base + i, usb_readl(acthcd->base + i));
+ i += 4;
+ printk(":0x%X ", usb_readl(acthcd->base + i));
+ i += 4;
+ printk(":0x%X ", usb_readl(acthcd->base + i));
+ i += 4;
+ printk(":0x%X ", usb_readl(acthcd->base + i));
+ i += 4;
+ printk("\n");
+ } while (i < 0x600);
+#endif
+ dev_info(acthcd->dev, "============== aotg regs ==================\n");
+
+ printk("usbecs:0x%X ", usb_readl(data->usbecs));
+#if 1
+ printk(" USBEIRQ(0x%p) : 0x%X\n",
+ acthcd->base + USBEIRQ, usb_readb(acthcd->base + USBEIRQ));
+ printk(" USBEIEN(0x%p) : 0x%X\n",
+ acthcd->base + USBEIEN, usb_readb(acthcd->base + USBEIEN));
+ printk(" SRPCTRL(0x%p) : 0x%X\n",
+ acthcd->base + SRPCTRL, usb_readb(acthcd->base + SRPCTRL));
+
+ printk("HCINxSHORTPCKIRQ0(0x%p) : 0x%X\n",
+ acthcd->base + HCINxSHORTPCKIRQ0 , usb_readb(acthcd->base + HCINxSHORTPCKIRQ0 ));
+ printk("HCINxSHORTPCKIRQ1 (0x%p) : 0x%X\n",
+ acthcd->base + HCINxSHORTPCKIRQ1 , usb_readb(acthcd->base + HCINxSHORTPCKIRQ1 ));
+ printk("HCINxSHORTPCKIEN0 (0x%p) : 0x%X\n",
+ acthcd->base + HCINxSHORTPCKIEN0 , usb_readb(acthcd->base + HCINxSHORTPCKIEN0 ));
+ printk("HCINxSHORTPCKIEN1 (0x%p) : 0x%X\n",
+ acthcd->base + HCINxSHORTPCKIEN1 , usb_readb(acthcd->base + HCINxSHORTPCKIEN1 ));
+
+ printk("HCINxERRIRQ0(0x%p) : 0x%X\n",
+ acthcd->base + HCINxERRIRQ0, usb_readw(acthcd->base + HCINxERRIRQ0));
+
+ printk(" OTGIRQ(0x%p) : 0x%X\n",
+ acthcd->base + OTGIRQ, usb_readb(acthcd->base + OTGIRQ));
+ printk(" OTGSTATE(0x%p) : 0x%X\n",
+ acthcd->base + OTGSTATE, usb_readb(acthcd->base + OTGSTATE));
+ printk(" OTGCTRL(0x%p) : 0x%X\n",
+ acthcd->base + OTGCTRL, usb_readb(acthcd->base + OTGCTRL));
+ printk(" OTGSTATUS(0x%p) : 0x%X\n",
+ acthcd->base + OTGSTATUS, usb_readb(acthcd->base + OTGSTATUS));
+ printk(" OTGIEN(0x%p) : 0x%X\n",
+ acthcd->base + OTGIEN, usb_readb(acthcd->base + OTGIEN));
+ printk("\n");
+ printk(" BKDOOR(0x%p) : 0x%X\n",
+ acthcd->base + BKDOOR, usb_readb(acthcd->base + BKDOOR));
+ printk(" USBIRQ(0x%p) : 0x%X\n",
+ acthcd->base + USBIRQ, usb_readb(acthcd->base + USBIRQ));
+ printk(" USBIEN(0x%p) : 0x%X\n",
+ acthcd->base + USBIEN, usb_readb(acthcd->base + USBIEN));
+ printk("\n");
+#endif
+
+ printk("HCINxPNGIEN0:%x\n", (u32)usb_readb(acthcd->base + HCINxPNGIEN0));
+ printk(" HCIN1DMACOUNTER(0x%p) : 0x%X\n",
+ acthcd->base + HCIN1DMACOUNTER, usb_readb(acthcd->base + HCIN1DMACOUNTER));
+ printk(" HCIN2DMASTADDR(0x%p) : 0x%X\n",
+ acthcd->base + HCIN2DMASTADDR, usb_readb(acthcd->base + HCIN2DMASTADDR));
+
+ printk(" HCOUTxIRQ0(0x%p) : 0x%X\n",
+ acthcd->base + HCOUTxIRQ0, usb_readb(acthcd->base + HCOUTxIRQ0));
+ printk(" HCOUTxIEN0(0x%p) : 0x%X\n",
+ acthcd->base + HCOUTxIEN0, usb_readb(acthcd->base + HCOUTxIEN0));
+ printk(" HCINxIRQ0(0x%p) : 0x%X\n",
+ acthcd->base + HCINxIRQ0, usb_readb(acthcd->base + HCINxIRQ0));
+ printk(" HCINxIEN0(0x%p) : 0x%X\n",
+ acthcd->base + HCINxIEN0, usb_readb(acthcd->base + HCINxIEN0));
+ printk("\n");
+#if 1
+ printk(" HCIN0BC(0x%p) : 0x%X\n",
+ acthcd->base + HCIN0BC, usb_readb(acthcd->base + HCIN0BC));
+ printk(" EP0CS(0x%p) : 0x%X\n",
+ acthcd->base + EP0CS, usb_readb(acthcd->base + EP0CS));
+ printk(" HCOUT0BC(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT0BC, usb_readb(acthcd->base + HCOUT0BC));
+ printk(" HCEP0CTRL(0x%p) : 0x%X\n",
+ acthcd->base + HCEP0CTRL, usb_readb(acthcd->base + HCEP0CTRL));
+ printk("\n");
+ printk(" HCIN1BC(0x%p) : 0x%X\n",
+ acthcd->base + HCIN1BCL, usb_readw(acthcd->base + HCIN1BCL));
+ printk(" HCIN1CON(0x%p) : 0x%X\n",
+ acthcd->base + HCIN1CON, usb_readb(acthcd->base + HCIN1CON));
+ printk(" HCIN1CS(0x%p) : 0x%X\n",
+ acthcd->base + HCIN1CS, usb_readb(acthcd->base + HCIN1CS));
+ printk(" HCIN1CTRL(0x%p) : 0x%X\n",
+ acthcd->base + HCIN1CTRL, usb_readb(acthcd->base + HCIN1CTRL));
+ printk(" HCIN2BC(0x%p) : 0x%X\n",
+ acthcd->base + HCIN2BCL, usb_readw(acthcd->base + HCIN2BCL));
+ printk(" HCIN2CON(0x%p) : 0x%X\n",
+ acthcd->base + HCIN2CON, usb_readb(acthcd->base + HCIN2CON));
+ printk(" HCIN2CS(0x%p) : 0x%X\n",
+ acthcd->base + HCIN2CS, usb_readb(acthcd->base + HCIN2CS));
+ printk(" HCIN2CTRL(0x%p) : 0x%X\n",
+ acthcd->base + HCIN2CTRL, usb_readb(acthcd->base + HCIN2CTRL));
+ printk("\n");
+ printk(" HCIN4DMASTADDR(0x%p) : 0x%X\n",
+ acthcd->base + HCIN4DMASTADDR, usb_readw(acthcd->base + HCIN4DMASTADDR));
+ printk(" HCIN4DMACOUNTER(0x%p) : 0x%X\n",
+ acthcd->base + HCIN4DMACOUNTER, usb_readw(acthcd->base + HCIN4DMACOUNTER));
+ //printk(" HCINCTRL(0x%p) : 0x%X\n", acthcd->base + HCINCTRL, usb_readb(acthcd->base + HCINCTRL));
+ printk("\n");
+#endif
+ printk(" HCOUT1BC(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT1BCL, usb_readw(acthcd->base + HCOUT1BCL));
+ printk(" HCOUT1CON(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT1CON, usb_readb(acthcd->base + HCOUT1CON));
+ printk(" HCOUT1CS(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT1CS, usb_readb(acthcd->base + HCOUT1CS));
+ printk(" HCOUT1CTRL(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT1CTRL, usb_readb(acthcd->base + HCOUT1CTRL));
+ printk(" HCOUT2BC(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT2BCL, usb_readw(acthcd->base + HCOUT2BCL));
+ printk(" HCOUT2CON(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT2CON, usb_readb(acthcd->base + HCOUT2CON));
+ printk(" HCOUT2CS(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT2CS, usb_readb(acthcd->base + HCOUT2CS));
+ printk(" HCOUT2CTRL(0x%p) : 0x%X\n",
+ acthcd->base + HCOUT2CTRL, usb_readb(acthcd->base + HCOUT2CTRL));
+ printk("\n");
+ printk("\n");
+ return;
+}
+
+#else /* AOTG_REG_DUMP */
+
+void aotg_dbg_regs(struct aotg_hcd *acthcd)
+{
+ /* fpga5209 dump */
+ printk("dump gl5209 reg\n");
+
+/*
+ printk("CMU_USBPLL(0x%p) : 0x%X\n",
+ acthcd->base + CMU_USBPLL, usb_readl(acthcd->base + CMU_USBPLL));
+ printk("CMU_DEVRST1(0x%p) : 0x%X\n",
+ acthcd->base + CMU_DEVRST1, usb_readl(acthcd->base + CMU_DEVRST1));
+ printk("HCDMABCKDOOR(0x%p) : 0x%X\n",
+ acthcd->base + HCDMABCKDOOR, usb_readl(acthcd->base + HCDMABCKDOOR));
+ printk("USBH_0ECS(0x%p) : 0x%X\n",
+ acthcd->base + USBH_0ECS, usb_readl(acthcd->base + USBH_0ECS));
+*/
+ printk(" USBEIEN(0x%p) : 0x%X\n",
+ acthcd->base + USBEIEN, usb_readb(acthcd->base + USBEIEN));
+ printk(" OTGIRQ(0x%p) : 0x%X\n",
+ acthcd->base + OTGIRQ, usb_readb(acthcd->base + OTGIRQ));
+ printk(" OTGSTATE(0x%p) : 0x%X\n",
+ acthcd->base + OTGSTATE, usb_readb(acthcd->base + OTGSTATE));
+ printk(" OTGCTRL(0x%p) : 0x%X\n",
+ acthcd->base + OTGCTRL, usb_readb(acthcd->base + OTGCTRL));
+ printk(" OTGSTATUS(0x%p) : 0x%X\n",
+ acthcd->base + OTGSTATUS, usb_readb(acthcd->base + OTGSTATUS));
+ printk(" OTGIEN(0x%p) : 0x%X\n",
+ acthcd->base + OTGIEN, usb_readb(acthcd->base + OTGIEN));
+
+ return;
+}
+
+#endif /* AOTG_REG_DUMP */
+
+
+#ifdef AOTG_DEBUG_FILE
+
+int aotg_dbg_proc_output_ep_state1(struct aotg_hcd *acthcd)
+{
+ struct aotg_hcep *tmp_ep;
+ int i;
+ struct aotg_queue *q, *next;
+ struct aotg_hcep *ep;
+ struct urb *urb;
+
+ ep = acthcd->active_ep0;
+ if (ep) {
+ printk("------------- active ep0 queue: \n");
+ printk("urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ printk("urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ printk("urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ printk("urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ printk("dma[0]: ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->ep0[i];
+ if (ep) {
+ printk("------------- ep0 list index:%d queue: \n", i);
+ printk("urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ printk("urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ printk("urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ printk("urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+ printk("ep->epnum:%d\n", ep->epnum);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ printk("ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+ }
+
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ tmp_ep = acthcd->inep[i];
+ if (tmp_ep) {
+ //if (tmp_ep->urb_enque_cnt > (tmp_ep->urb_endque_cnt + tmp_ep->urb_stop_stran_cnt))
+ {
+ printk("inep:%d\n", i);
+ printk("urb_enque_cnt:%d\n", tmp_ep->urb_enque_cnt);
+ printk("urb_endque_cnt:%d\n", tmp_ep->urb_endque_cnt);
+ printk("urb_stop_stran_cnt:%d\n", tmp_ep->urb_stop_stran_cnt);
+ printk("urb_unlinked_cnt:%d\n", tmp_ep->urb_unlinked_cnt);
+
+ printk("index:%d\n", tmp_ep->index);
+ printk("maxpacket:%d\n", tmp_ep->maxpacket);
+ printk("epnum:%d\n", tmp_ep->epnum);
+ }
+ }
+ }
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ tmp_ep = acthcd->outep[i];
+ if (tmp_ep) {
+ //if (tmp_ep->urb_enque_cnt > (tmp_ep->urb_endque_cnt + tmp_ep->urb_stop_stran_cnt))
+ {
+ printk("outep:%d\n", i);
+ printk("urb_enque_cnt:%d\n", tmp_ep->urb_enque_cnt);
+ printk("urb_endque_cnt:%d\n", tmp_ep->urb_endque_cnt);
+ printk("urb_stop_stran_cnt:%d\n", tmp_ep->urb_stop_stran_cnt);
+ printk("urb_unlinked_cnt:%d\n", tmp_ep->urb_unlinked_cnt);
+
+ printk("index:%d\n", tmp_ep->index);
+ printk("maxpacket:%d\n", tmp_ep->maxpacket);
+ printk("epnum:%d\n", tmp_ep->epnum);
+ }
+ }
+ }
+
+ printk("in hcd enqueue list: \n");
+ list_for_each_entry_safe(q, next, &acthcd->hcd_enqueue_list, enqueue_list) {
+ urb = q->urb;
+ ep = q->ep;
+ printk("ep->epnum:%d ", ep->epnum);
+ printk("urb->transfer_buffer_length:%d ", urb->transfer_buffer_length);
+ printk("usb_pipein(urb->pipe):%x\n", usb_pipein(urb->pipe));
+ printk("usb_pipetype(urb->pipe):%x\n", usb_pipetype(urb->pipe));
+ }
+ return 0;
+}
+
+int aotg_dbg_proc_output_ep_state(struct aotg_hcd *acthcd)
+{
+ struct aotg_queue *q, *next;
+ struct aotg_hcep *ep;
+ struct urb *urb;
+ int i = 0;
+
+ list_for_each_entry_safe(q, next, &acthcd->hcd_enqueue_list, enqueue_list) {
+ urb = q->urb;
+ ep = q->ep;
+ i++;
+ }
+
+ if (i>2) {
+ printk("error, more enque.\n");
+ //aotg_dbg_output_info();
+ //aotg_dbg_regs(acthcd);
+ //BUG_ON(1);
+ }
+ if (i <= 1) {
+ i = 0;
+ }
+ aotg_dbg_proc_output_ep_state1(acthcd);
+ return i;
+}
+
+int aotg_dump_regs(struct aotg_hcd *acthcd)
+{
+ int i;
+ struct aotg_hcep *ep;
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ if (ep) {
+ aotg_dump_linklist_reg_2(acthcd, ep->mask);
+ }
+ }
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ if (ep) {
+ aotg_dump_linklist_reg_2(acthcd, ep->mask);
+ }
+ }
+
+ return 0;
+
+}
+
+void __dump_ring_info(struct aotg_hcep *ep)
+{
+ int i;
+ struct aotg_ring *ring = NULL;
+ struct aotg_td *td, *next;
+ struct urb *urb;
+ struct aotg_trb *trb;
+
+ //struct aotg_trb trb_val;
+
+ if (!ep)
+ return;
+ printk("\n------------- current %s ep%d ring : \n", ep->is_out ? "OUT" : "IN",
+ ep->index);
+ printk("urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ printk("urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ printk("urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ printk("urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+ printk("ep_num:%d\n", ep->epnum);
+ printk("ep_type:%d\n", ep->type);
+
+ ring = ep->ring;
+
+ i=0;
+ if (ring) {
+ trb = ring->first_trb;
+ while(trb <= ring->last_trb) {
+ printk("%d hw_buf_ptr:%x,hw_buf_len:%x,hw_buf_remain:%x,hw_token:%x\n",i, \
+ trb->hw_buf_ptr,trb->hw_buf_len,trb->hw_buf_remain,trb->hw_token);
+ trb++;
+ i++;
+ }
+
+ }
+
+ if (ring) {
+ printk("-----\n");
+ printk("enring_cnt:%d\n", ring->enring_cnt);
+ printk("dering_cnt:%d\n", ring->dering_cnt);
+ printk("num_trbs_free:%d\n", (u32)atomic_read(&ring->num_trbs_free));
+ printk("first_trb:0x%p, dma:0x%x\n", ring->first_trb,
+ ring_trb_virt_to_dma(ring, ring->first_trb));
+ printk("last_trb:0x%x, dma:0x%x\n", (u32)(ring->last_trb),
+ ring_trb_virt_to_dma(ring, ring->last_trb));
+ printk("ring_enqueue:0x%x(%d)\n", (u32)(ring->enqueue_trb),
+ ring->enqueue_trb - ring->first_trb);
+ printk("ring_dequeue:0x%x(%d)\n", (u32)(ring->dequeue_trb),
+ ring->dequeue_trb - ring->first_trb);
+ printk("reg_linkaddr(0x%p):0x%x\n", ring->reg_dmalinkaddr,
+ usb_readl(ring->reg_dmalinkaddr));
+ printk("reg_curradr(0x%p):0x%x\n", ring->reg_curaddr,
+ usb_readl(ring->reg_curaddr));
+ printk("reg_dmactrl(0x%p):0x%x\n", ring->reg_dmactrl,
+ usb_readl(ring->reg_dmactrl));
+
+ printk( "in eq_enqueue_td list: \n");
+ i = 0;
+ list_for_each_entry_safe(td, next, &ep->queue_td_list, queue_list) {
+ urb = td->urb;
+ i++;
+ printk("-----\n");
+ printk("urb->transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+ printk("usb_pipein(urb->pipe):%x\n", usb_pipein(urb->pipe));
+ printk("usb_pipetype(urb->pipe):%x\n", usb_pipetype(urb->pipe));
+ }
+ if (i) {
+ i = 0;
+ printk("======td in queue num : %d\n", i);
+ }
+
+ printk( "in eq_enring_td list: \n");
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ //trb_val = *(td->trb_vaddr);
+ printk("-----\n");
+ i++;
+ trb = td->trb_vaddr;
+ if (td->urb)
+ printk("urb:%p\n",td->urb);
+ printk("hw_buf_ptr:%x,hw_buf_len:%x,hw_buf_remain:%x,hw_token:%x\n", \
+ trb->hw_buf_ptr,trb->hw_buf_len,trb->hw_buf_remain,trb->hw_token);
+ printk("num_trbs:%d\n", td->num_trbs);
+ //printk("trb_dma:0x%x\n", td->trb_dma);
+ //printk("trb_vaddr:0x%x\n", td->trb_vaddr);
+ //printk("trb_dma:0x%x\n", td->trb_dma);
+ //printk("cross_ring:0x%d\n", td->cross_ring);
+
+ //aotg_hcd_dump_td(ring, td);
+ //printk("hw_buf_ptr : 0x%x\n", trb_val.hw_buf_ptr);
+ //printk("hw_buf_len : %d\n", trb_val.hw_buf_len);
+ //printk("hw_buf_remain : %d\n", trb_val.hw_buf_remain);
+ //printk("hw_token : 0x%x\n", trb_val.hw_token);
+ //printk("in_dma_irq:0x%x\n",usb_readw(USBH_BASE0 + HCINxDMAIRQ0));
+ }
+ if (i) {
+ printk("======td in ring num : %d\n", i);
+ }
+ }
+
+/*
+ seq_printf(s, "------------- current IN ep%d ring : \n", i);
+ seq_printf(s, "urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ seq_printf(s, "urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ seq_printf(s, "urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ seq_printf(s, "urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+ seq_printf(s, "ep->epnum:%d\n", ep->epnum);
+
+ ring = ep->ring;
+ if (ring) {
+ seq_printf(s, "enring_cnt:%d\n", ring->enring_cnt);
+ seq_printf(s, "dering_cnt:%d\n", ring->dering_cnt);
+ seq_printf(s, "num_trbs_free:%d\n", ring->num_trbs_free);
+ seq_printf(s, "ring_enqueue_ptr:0x%x", ring->enqueue_trb);
+ seq_printf(s, "ring_dequeue_ptr:0x%x", ring->dequeue_trb);
+
+ seq_printf(s, "in eq_enqueue_td list: \n");
+ list_for_each_entry_safe(td, next, &ep->queue_td_list, queue_td_list) {
+ urb = td->urb;
+ seq_printf(s, "urb->transfer_buffer_length:%d ", urb->transfer_buffer_length);
+ seq_printf(s, "usb_pipein(urb->pipe):%x\n", usb_pipein(urb->pipe));
+ seq_printf(s, "usb_pipetype(urb->pipe):%x\n", usb_pipetype(urb->pipe));
+ }
+
+ seq_printf(s, "in eq_enring_td list: \n");
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ seq_printf(s, "num_trbs:%d\n", td->num_trbs);
+ seq_printf(s, "trb_vaddr:0x%x\n", td->trb_vaddr);
+ seq_printf(s, "trb_dma:0x%x\n", td->trb_dma);
+ seq_printf(s, "cross_ring:0x%d\n", td->cross_ring);
+ }
+ }
+*/
+}
+
+static int aotg_hcd_show_ring_info(struct aotg_hcd *acthcd)
+{
+ int i;
+ struct aotg_hcep *ep;
+ struct aotg_queue *q;
+
+ ep = acthcd->active_ep0;
+ if (ep) {
+ printk("------------- active ep0 queue: \n");
+ printk("urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ printk("urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ printk("urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ printk("urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ printk("dma[0]: ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ __dump_ring_info(ep);
+ }
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ __dump_ring_info(ep);
+ }
+
+ return 0;
+}
+#if 0
+static int aotg_hcd_show_enque_info(struct seq_file *s, struct aotg_hcd *acthcd)
+{
+ int i;
+ struct aotg_queue *q, *next;
+ struct aotg_hcep *ep;
+
+ for (i = 0; i < AOTG_QUEUE_POOL_CNT; i++) {
+ if (acthcd->queue_pool[i] != NULL) {
+ seq_printf(s, "queue_pool[%d]->in_using: %d\n",
+ i, acthcd->queue_pool[i]->in_using);
+ }
+ }
+
+ seq_printf(s, "current dma queue: \n");
+
+ ep = acthcd->active_ep0;
+ if (ep) {
+ seq_printf(s, "------------- active ep0 queue: \n");
+ seq_printf(s, "urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ seq_printf(s, "urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ seq_printf(s, "urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ seq_printf(s, "urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ seq_printf(s, "dma[0]: ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->ep0[i];
+ if (ep) {
+ seq_printf(s, "------------- ep0 list index:%d queue: \n", i);
+ seq_printf(s, "urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ seq_printf(s, "urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ seq_printf(s, "urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ seq_printf(s, "urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+ seq_printf(s, "ep->epnum:%d\n", ep->epnum);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ seq_printf(s, "ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+ }
+
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ if (ep) {
+ seq_printf(s, "------------- current IN ep%d queue: \n", i);
+ seq_printf(s, "urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ seq_printf(s, "urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ seq_printf(s, "urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ seq_printf(s, "urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+ seq_printf(s, "ep->epnum:%d\n", ep->epnum);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ seq_printf(s, "ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+ }
+
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ if (ep) {
+ seq_printf(s, "------------- current OUT ep%d queue: \n", i);
+ seq_printf(s, "urb_enque_cnt:%d\n", ep->urb_enque_cnt);
+ seq_printf(s, "urb_endque_cnt:%d\n", ep->urb_endque_cnt);
+ seq_printf(s, "urb_stop_stran_cnt:%d\n", ep->urb_stop_stran_cnt);
+ seq_printf(s, "urb_unlinked_cnt:%d\n", ep->urb_unlinked_cnt);
+ seq_printf(s, "ep->epnum:%d\n", ep->epnum);
+
+ if (ep->q != NULL) {
+ q = ep->q;
+ seq_printf(s, "ep->index: %d, type: %d, dir : %s, transfer_buffer_length: %d, actual_length:%d\n",
+ q->ep->index,
+ usb_pipetype(q->urb->pipe), usb_pipeout(q->urb->pipe)?"out":"in",
+ q->urb->transfer_buffer_length, q->urb->actual_length);
+ }
+ }
+ }
+
+ seq_printf(s, "\n");
+ seq_printf(s, "in hcd enqueue list: \n");
+ list_for_each_entry_safe(q, next, &acthcd->hcd_enqueue_list, enqueue_list) {
+ ep = q->ep;
+ seq_printf(s, "ep->epnum:%d ", ep->epnum);
+ seq_printf(s, "urb->transfer_buffer_length:%d ", q->urb->transfer_buffer_length);
+ seq_printf(s, "usb_pipein(urb->pipe):%x\n", usb_pipein(q->urb->pipe));
+ seq_printf(s, "usb_pipetype(urb->pipe):%x\n", usb_pipetype(q->urb->pipe));
+ }
+ return 0;
+}
+#endif
+/*
+ * echo a value to controll the cat /proc/aotg_hcd output content.
+ * echo h>/proc/aotg_hcd.0 to see help info.
+ */
+ssize_t aotg_hcd_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ char c = 'n';
+
+ if (count) {
+ if (get_user(c, buf))
+ return -EFAULT;
+ aotg_hcd_proc_sign = c;
+ }
+ if (c == 'h') {
+ printk(" a ---- all. \n");
+ printk(" b ---- backup info. \n");
+ printk(" d ---- dma related. \n");
+ printk(" e ---- enque and outque info. \n");
+ printk(" f ---- trace in info. \n");
+ printk(" h ---- help info. \n");
+ printk(" n ---- normal. \n");
+ printk(" r ---- register info. \n");
+ printk(" s ---- aotg state. \n");
+ printk(" t ---- trace out info. \n");
+ printk(" z ---- stop stace. \n");
+ }
+ return count;
+}
+
+int aotg_hcd_proc_show(struct seq_file *s, void *unused)
+{
+ struct aotg_hcd *acthcd = s->private;
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+ //struct aotg_plat_data *data = acthcd->port_specific;
+
+ if (aotg_hcd_proc_sign == 'd') {
+ // todo.
+ }
+
+ if (aotg_hcd_proc_sign == 's') {
+ aotg_dbg_proc_output_ep_state(acthcd);
+ seq_printf(s, "hcd state : 0x%08X\n", hcd->state);
+ }
+
+ if (aotg_hcd_proc_sign == 'r') {
+ //aotg_dbg_regs(acthcd);
+ aotg_dump_regs(acthcd);
+ }
+
+ if (aotg_hcd_proc_sign == 'e') {
+ //aotg_hcd_show_enque_info(s, acthcd);
+ aotg_hcd_show_ring_info(acthcd);
+ }
+
+ if (aotg_hcd_proc_sign == 'b') {
+ aotg_dbg_proc_output_ep();
+ aotg_dbg_output_info();
+ }
+
+ if (aotg_hcd_proc_sign == 'a') {
+ }
+
+ seq_printf(s, "\n");
+ return 0;
+}
+
+
+static int aotg_hcd_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, aotg_hcd_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations proc_ops = {
+ .open = aotg_hcd_proc_open,
+ .read = seq_read,
+ .write = aotg_hcd_proc_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void create_debug_file(struct aotg_hcd *acthcd)
+{
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+
+ acthcd->pde = proc_create_data(dev_name(dev), 0, NULL, &proc_ops, acthcd);
+ return;
+}
+
+void remove_debug_file(struct aotg_hcd *acthcd)
+{
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+
+ if (acthcd->pde)
+ remove_proc_entry(dev_name(dev), NULL);
+ return;
+}
+
+#else /* AOTG_DEBUG_FILE */
+
+void create_debug_file(struct aotg_hcd *acthcd)
+{
+ return;
+}
+
+void remove_debug_file(struct aotg_hcd *acthcd)
+{
+ return;
+}
+
+#endif /* AOTG_DEBUG_FILE */
+
+
+void aotg_print_xmit_cnt(char * info, int cnt)
+{
+ if (aotg_hcd_proc_sign == 'e') {
+ printk("%s cnt:%d\n", info, cnt);
+ }
+ //printk("\n");
+ //aotg_dbg_proc_output_ep();
+ //aotg_dbg_regs(p_aotg_hcd0);
+ //aotg_dbg_output_info();
+
+ return;
+}
+//EXPORT_SYMBOL(aotg_print_xmit_cnt);
+
+
+static struct proc_dir_entry *acts_hub_pde = NULL;
+
+int acts_hcd_proc_show(struct seq_file *s, void *unused)
+{
+ seq_printf(s, "hcd_ports_en_ctrl: %d\n", hcd_ports_en_ctrl);
+ return 0;
+}
+
+static int acts_hub_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, acts_hcd_proc_show, PDE(inode)->data);
+}
+
+static ssize_t acts_hub_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ char c = 'n';
+
+ if (count) {
+ if (get_user(c, buf))
+ return -EFAULT;
+ }
+ if ((c >= '0') && (c <= '3')) {
+ hcd_ports_en_ctrl = c - '0';
+ printk("hcd_hub en:%d\n", hcd_ports_en_ctrl);
+ }
+ if (c == 'h') {
+ printk(" num ---- 0-all enable, 1-usb0 enable, 2-usb1 enable, 3-reversed. \n");
+ printk("o ---- hcd_hub power on\n");
+ printk("f ---- hcd_hub power off\n");
+ printk("a ---- hcd_hub aotg0 add\n");
+ printk("b ---- hcd_hub aotg0 remove\n");
+ printk("c ---- hcd_hub aotg1 add\n");
+ printk("d ---- hcd_hub aotg1 remove\n");
+ }
+
+ if (c == 'a') {
+ printk("hcd_hub aotg0 add\n");
+ //aotg0_device_init(0);
+ aotg_hub_register(0);
+ }
+ if (c == 'b') {
+ printk("hcd_hub aotg0 remove\n");
+ //aotg0_device_exit(0);
+ aotg_hub_unregister(0);
+ }
+
+ if (c == 'c') {
+ printk("hcd_hub aotg1 add\n");
+ //aotg1_device_init(0);
+ aotg_hub_register(1);
+ }
+ if (c == 'd') {
+ printk("hcd_hub aotg1 remove\n");
+ //aotg1_device_exit(0);
+ aotg_hub_unregister(1);
+ }
+
+ if (c == 'e') {
+ aotg_trace_onff = 1;
+ }
+ if (c == 'f') {
+ aotg_trace_onff = 0;
+ }
+
+ if (c == 'g') {
+ aotg_dbg_regs(act_hcd_ptr[0]);
+ }
+
+ if (c == 'i') {
+ aotg_dbg_regs(act_hcd_ptr[1]);
+ }
+ return count;
+}
+
+static const struct file_operations acts_hub_proc_ops = {
+ .open = acts_hub_proc_open,
+ .read = seq_read,
+ .write = acts_hub_proc_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void create_acts_hcd_proc(void)
+{
+ acts_hub_pde = proc_create_data("acts_hub", S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH, NULL, &acts_hub_proc_ops, acts_hub_pde);
+ return;
+}
+
+void remove_acts_hcd_proc(void)
+{
+ if (acts_hub_pde) {
+ remove_proc_entry("acts_hub", NULL);
+ acts_hub_pde = NULL;
+ }
+ return;
+}
+
diff --git a/drivers/usb/host/aotg_debug.h b/drivers/usb/host/aotg_debug.h
new file mode 100644
index 0000000..73493da
--- /dev/null
+++ b/drivers/usb/host/aotg_debug.h
@@ -0,0 +1,88 @@
+#ifndef __LINUX_USB_AOTG_DEBUG_H__
+#define __LINUX_USB_AOTG_DEBUG_H__
+
+//#define DEBUG_HCD
+//#define DEBUG_HUB
+//#define DEBUG_SETUP_DATA
+//#define DEBUG_EP_CONFIG
+//#define IN_PROCESS_DEBUG
+//#define DEBUG_IN_DATA
+//#define OUT_PROCESS_DEBUG
+//#define DEBUG_OUT_DATA
+//#define DEBUG_DMA
+#define AOTG_REG_DUMP
+//#define AOTG_DEBUG_RECORD_URB
+#define AOTG_DEBUG_FILE
+#define DEBUG_LINKLIST_DMA
+
+#define ACT_HCD_ERR printk("%s:%d, err!\n", __func__, __LINE__);
+#define ACT_HCD_DBG printk("%s:%d, dbg!\n", __func__, __LINE__);
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
+
+#ifdef DEBUG_HUB
+#define HUB_DEBUG(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define HUB_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_HCD
+#define HCD_DEBUG(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define HCD_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef IN_PROCESS_DEBUG //ep1, ep2
+#define IN_DEBUG(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define IN_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef OUT_PROCESS_DEBUG
+#define OUT_DEBUG(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define OUT_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_DMA
+#define ACT_DMA_DEBUG(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define ACT_DMA_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_LINKLIST_DMA
+#define ACT_LINKLIST_DMA_DEBUG(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define ACT_LINKLIST_DMA_DEBUG(fmt,args...) do {} while(0)
+#endif
+
+#define HCD_WARN(fmt, args...) printk(KERN_WARNING fmt, ## args)
+#define HCD_WARNING(fmt, args...) printk(KERN_WARNING fmt, ## args)
+
+extern unsigned int aotg_trace_onff;
+#define AOTG_TRACE_ERR_PLACE if (aotg_trace_onff) printk("-%d\n", __LINE__);
+
+void aotg_dbg_put_info(char *info0, unsigned int info1, unsigned int info2, unsigned int info3);
+void aotg_dbg_output_info(void);
+
+void aotg_dbg_put_q(struct aotg_queue *q, unsigned int num, unsigned int type, unsigned int len);
+void aotg_dbg_finish_q(struct aotg_queue *q);
+
+void aotg_dbg_proc_output_ep(void);
+int aotg_dbg_proc_output_ep_state(struct aotg_hcd *acthcd);
+
+void create_debug_file(struct aotg_hcd *acthcd);
+void remove_debug_file(struct aotg_hcd *acthcd);
+
+void aotg_dbg_regs(struct aotg_hcd *acthcd);
+
+void create_acts_hcd_proc(void);
+void remove_acts_hcd_proc(void);
+void aotg_dump_ep_reg(struct aotg_hcd *acthcd, int ep_index, int is_out);
+
+
+#endif /* __LINUX_USB_AOTG_DEBUG_H__ */
+
diff --git a/drivers/usb/host/aotg_hcd.c b/drivers/usb/host/aotg_hcd.c
new file mode 100644
index 0000000..c14c89a
--- /dev/null
+++ b/drivers/usb/host/aotg_hcd.c
@@ -0,0 +1,4168 @@
+/*
+ * (C) Copyright www.actions-semi.com 2012-2014
+ * Written by houjingkun. <houjingkun at actions-semi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include <asm/irq.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/hardware.h>
+#include <linux/clk.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
+#include <mach/debug.h>
+#include <asm/prom.h>
+#include <mach/gpio.h>
+#include <linux/kallsyms.h>
+#include <mach/powergate.h>
+#include <mach/module-owl.h>
+
+#include "aotg_hcd.h"
+#include "aotg_plat_data.h"
+#include "aotg_debug.h"
+#include "aotg_mon.h"
+
+static int aotg0_slew_rate = -1;
+module_param(aotg0_slew_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(aotg0_slew_rate, "aotg0_slew_rate");
+static int aotg0_tx_bias = -1;
+module_param(aotg0_tx_bias, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(aotg0_tx_bias, "aotg0_tx_bias");
+
+static int aotg1_slew_rate = -1;
+module_param(aotg1_slew_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(aotg1_slew_rate, "aotg1_slew_rate");
+static int aotg1_tx_bias = -1;
+module_param(aotg1_tx_bias, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(aotg1_tx_bias, "aotg1_tx_bias");
+
+#define DRIVER_DESC "AOTG USB Host Controller Driver"
+
+struct aotg_hcd *act_hcd_ptr[2] = {NULL};
+
+static int handle_setup_packet(struct aotg_hcd *acthcd, struct aotg_queue *q);
+static void handle_hcep0_in(struct aotg_hcd *acthcd);
+static void handle_hcep0_out(struct aotg_hcd *acthcd);
+//static int aotg_hcd_flush_queue(struct aotg_hcd *acthcd);
+#if 0
+#ifdef CONFIG_PM
+static void aotg_hcd_register_earlysuspend(struct aotg_hcd *acthcd);
+static void aotg_hcd_unregister_earlysuspend(struct aotg_hcd *acthcd);
+static void aotg_hcd_early_suspend(struct early_suspend *h);
+static void aotg_hcd_late_resume(struct early_suspend *h);
+
+typedef int (* aotg_hcd_reset_device_f)(struct usb_device *udev);
+aotg_hcd_reset_device_f aotg_hcd_reset_device = NULL;
+void aotg_hcd_reset_and_verify_device(struct aotg_hcd *acthcd, int reset_device);
+#endif
+#endif
+
+#define MAX_PACKET(x) ((x)&0x7FF)
+
+/* because usb0 and usb1's pll is all controlled together,
+ * we couldn't enable aotg0 and aotg1 seperately.
+ */
+//static int hcd_2clk_bits_en = 0;
+/* 0 is all enable, 1 -- just usb0 enable, 2 -- usb1 enable,
+ * 3 -- usb0 and usb1 enable,but reversed.
+ */
+int hcd_ports_en_ctrl = 0;
+//static unsigned int aotg_registered_map = 0;
+int vbus_otg_en_gpio[2][2];
+static struct platform_device *aotg_dev[2] = {NULL};
+static int aotg_initialized[2] = {0};
+int is_ls_device[2] = {0}; /*if detect low speed device plug in,must disable usbh high speed*/
+struct mutex aotg_onoff_mutex;
+
+static u64 hcd_dmamask = DMA_BIT_MASK(32);
+static struct aotg_plat_data aotg_data0 = {
+ .usbecs = (void __iomem *)IO_ADDRESS(USBH0_ECS),
+ .usbpll = (void __iomem *)IO_ADDRESS(CMU_USBPLL),
+ .usbpll_bits = CMU_USBPLL_USBPLL0EN,
+ .devrst = (void __iomem *)IO_ADDRESS(CMU_DEVRST1),
+ .devrst_bits = CMU_DEVRST1_USBH0,
+ .no_hs = 0,
+};
+
+static struct aotg_plat_data aotg_data1 = {
+ .usbecs = (void __iomem *)IO_ADDRESS(USBH1_ECS),
+ .usbpll = (void __iomem *)IO_ADDRESS(CMU_USBPLL),
+ .usbpll_bits = CMU_USBPLL_USBPLL1EN,
+ .devrst = (void __iomem *)IO_ADDRESS(CMU_DEVRST1),
+ .devrst_bits = CMU_DEVRST1_USB1,
+ .no_hs = 0,
+};
+#if 0
+/* forbid to enter suspend when driver is installed. */
+//struct wake_lock acts_hcd_wakelock;
+
+#ifdef CONFIG_PM
+
+static void aotg_hcd_register_earlysuspend(struct aotg_hcd *acthcd)
+{
+ if (!acthcd) {
+ ACT_HCD_ERR
+ return;
+ }
+
+ acthcd->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 10;
+ acthcd->earlysuspend.suspend = aotg_hcd_early_suspend;
+ acthcd->earlysuspend.resume = aotg_hcd_late_resume;
+ register_early_suspend(&acthcd->earlysuspend);
+
+ acthcd->lr_flag = 0;
+
+ return;
+}
+
+static void aotg_hcd_unregister_earlysuspend(struct aotg_hcd *acthcd)
+{
+ if (acthcd->earlysuspend.suspend)
+ unregister_early_suspend(&acthcd->earlysuspend);
+
+ acthcd->earlysuspend.suspend = NULL;
+ acthcd->earlysuspend.resume = NULL;
+
+ return;
+}
+
+static void aotg_hcd_early_suspend(struct early_suspend *h)
+{
+ printk(KERN_DEBUG"%s do nothing!\n", __FUNCTION__);
+
+ return;
+}
+
+static void aotg_hcd_late_resume(struct early_suspend *h)
+{
+ struct aotg_hcd *acthcd = container_of(h, struct aotg_hcd, earlysuspend);
+ if (!acthcd) {
+ printk(KERN_ERR"%s err, acthcd is NULL pointer!\n", __FUNCTION__);
+ return;
+ }
+
+ if (acthcd->lr_flag) {
+ acthcd->lr_flag = 0;
+ printk(KERN_DEBUG"%s, %d\n", __FUNCTION__, __LINE__);
+// if(hcd_suspend_en==0)
+ aotg_hcd_reset_and_verify_device(acthcd, USB_RESET_AND_VERIFY_DEVICE);
+ }
+
+ return;
+}
+
+#if 0
+static void aotg_hcd_resume_disconnect(struct aotg_hcd *acthcd)
+{
+ //printk("uhost%d, usb device inserted : %d, otg state : 0x%02X\n", acthcd->id, acthcd->inserted, usb_readb(acthcd->base + OTGSTATE) );
+ if ( (acthcd->inserted ==1) &&
+ (usb_readb(acthcd->base + OTGSTATE) != AOTG_STATE_A_HOST)) {
+ printk("uhost%d,usb device disconnect in suspend, so, now disconnect it!\n", acthcd->id);
+ acthcd->discon_happened = 1;
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1));
+ }
+}
+#endif
+
+void aotg_hcd_reset_and_verify_device(struct aotg_hcd *acthcd, int reset_device)
+{
+ int i, ret = 0;
+ unsigned long jiffies_expire = jiffies + HZ;
+ struct usb_device *udev = NULL;
+
+ printk (KERN_DEBUG"* %s, %d *\n", __FUNCTION__, __LINE__);
+
+ if (acthcd == NULL){
+ ACT_HCD_ERR
+ return;
+ }
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ if (acthcd->ep0[i] != NULL) {
+ break;
+ }
+ }
+
+ if (i == MAX_EP_NUM) {
+ printk(KERN_ERR"%s, usb device is NULL!\n", __FUNCTION__);
+ }
+ else
+ udev = acthcd->ep0[i]->udev;
+
+ if (udev == NULL) {
+ printk(KERN_ERR"%s, udev is NULL, can't reset device here!\n", __FUNCTION__);
+ return;
+ }
+
+ while (!usb_trylock_device(udev)) {
+ if (time_after(jiffies, jiffies_expire)){
+ ret = -1;
+ break;
+ }
+ msleep(15);
+ }
+
+ if (ret == 0) {
+ if (reset_device){
+ printk (KERN_DEBUG"usb_reset_and_verify_device\n");
+ aotg_hcd_reset_device = (aotg_hcd_reset_device_f)kallsyms_lookup_name("usb_reset_and_verify_device");
+ if (aotg_hcd_reset_device != NULL)
+ aotg_hcd_reset_device(udev);
+ else
+ printk(KERN_ERR"Get reset_device fail!\n");
+ } else {
+ printk (KERN_DEBUG"usb_reset_device\n");
+ usb_reset_device(udev);
+ }
+ mutex_unlock(&(udev->dev).mutex);
+ } else {
+ printk (KERN_ERR"Fail to reset usb device!\n");
+ }
+}
+
+EXPORT_SYMBOL_GPL (aotg_hcd_reset_and_verify_device);
+#endif
+#endif
+
+typedef void (* aotg_hub_symbol_func_t)(int);
+aotg_hub_symbol_func_t aotg_hub_notify_func = NULL;
+
+void aotg_power_onoff(int id,int on_off)
+{
+ if(port_host_plug_detect[id] == 2)
+ return;
+ if(port_host_plug_detect[id] == 3){
+ if(act_hcd_ptr[1-id] != NULL)//if the other port is working;don't change vbus status
+ return;
+ }
+ if (vbus_otg_en_gpio[id][0] >= 0)
+ gpio_set_value(vbus_otg_en_gpio[id][0], !(on_off^vbus_otg_en_gpio[id][1]));
+}
+
+
+static void aotg_hub_notify_hcd_exit(int state)
+{
+ static int is_first_call = 1;
+
+ if (is_first_call) {
+ is_first_call = 0;
+ aotg_hub_notify_func = (aotg_hub_symbol_func_t)kallsyms_lookup_name("aotg_hub_notify_exit");
+ }
+ if (aotg_hub_notify_func) {
+ aotg_hub_notify_func(state);
+ }
+ return;
+}
+
+static ulong get_fifo_addr(struct aotg_hcd *acthcd, int size)
+{
+ int i, j;
+ ulong addr = 0;
+ int mul = size / ALLOC_FIFO_UNIT;
+ int max_unit = AOTG_MAX_FIFO_SIZE/ALLOC_FIFO_UNIT;
+ int find_next = 0;
+
+ if (mul == 0)
+ mul = 1;
+
+ for (i = 2; i < max_unit;) {
+ if (acthcd->fifo_map[i] != 0) {
+ i++;
+ continue; //find first unused addr
+ }
+
+ for (j = i; j < max_unit; j++) {
+ if ((j - i + 1) == mul)
+ break;
+
+ if (acthcd->fifo_map[j]) {
+ i = j;
+ find_next = 1;
+ break;
+ }
+ }
+
+ if (j == 64) {
+ break;
+ } else if (find_next) {
+ find_next = 0;
+ continue;
+ } else {
+ int k;
+ for (k = i; k <= j; k++) {
+ acthcd->fifo_map[k] = (1 << 31) | (i * 64);
+ }
+ addr = i * ALLOC_FIFO_UNIT;
+ break;
+ }
+ }
+
+ return addr;
+}
+
+static void release_fifo_addr(struct aotg_hcd *acthcd, ulong addr)
+{
+ int i;
+
+ for (i = addr/ALLOC_FIFO_UNIT; i < AOTG_MAX_FIFO_SIZE/ALLOC_FIFO_UNIT ; i++) {
+ if ((acthcd->fifo_map[i] & 0x7FFFFFFF) == addr)
+ acthcd->fifo_map[i] = 0;
+ else
+ break;
+ }
+ return;
+}
+
+static struct aotg_queue * aotg_hcd_get_queue(struct aotg_hcd *acthcd, struct urb *urb, unsigned mem_flags)
+{
+ int i;
+ int empty_idx = -1;
+ struct aotg_queue *q = NULL;
+
+ for (i = 0; i < AOTG_QUEUE_POOL_CNT; i++) {
+ if (acthcd->queue_pool[i] != NULL) {
+ if (acthcd->queue_pool[i]->in_using == 0) {
+ q = acthcd->queue_pool[i];
+ break;
+ }
+ } else {
+ if (empty_idx < 0) {
+ empty_idx = i;
+ }
+ }
+ }
+ if (i == AOTG_QUEUE_POOL_CNT) {
+ q = kzalloc(sizeof(*q), GFP_ATOMIC);
+ if (unlikely(!q)) {
+ dev_err(acthcd->dev, "aotg_hcd_get_queue failed\n");
+ return NULL;
+ }
+ if ((empty_idx >= 0) && (empty_idx < AOTG_QUEUE_POOL_CNT)) {
+ acthcd->queue_pool[empty_idx] = q;
+ }
+ }
+
+ memset(q, 0, sizeof(*q));
+ q->length = 0;
+ q->td.trb_vaddr = NULL;
+ INIT_LIST_HEAD(&q->enqueue_list);
+ INIT_LIST_HEAD(&q->dequeue_list);
+ INIT_LIST_HEAD(&q->finished_list);
+
+ q->in_using = 1;
+ return q;
+}
+
+static void aotg_hcd_release_queue(struct aotg_hcd *acthcd, struct aotg_queue *q)
+{
+ int i;
+
+ if (NULL == q)
+ return;
+
+ q->td.trb_vaddr = NULL;
+
+ /* release all */
+ if (q == NULL) {
+ for (i = 0; i < AOTG_QUEUE_POOL_CNT; i++) {
+ if (acthcd->queue_pool[i] != NULL) {
+ kfree(acthcd->queue_pool[i]);
+ acthcd->queue_pool[i] = NULL;
+ }
+ }
+ return;
+ }
+
+ for (i = 0; i < AOTG_QUEUE_POOL_CNT; i++) {
+ if (acthcd->queue_pool[i] == q) {
+ acthcd->queue_pool[i]->in_using = 0;
+ return;
+ }
+ }
+
+ kfree(q);
+ return;
+}
+
+static __inline__ int is_epfifo_busy(struct aotg_hcep *ep, int is_in)
+{
+
+ if (is_in)
+ return(EPCS_BUSY & readb(ep->reg_hcepcs)) == 0;
+ else
+ return (EPCS_BUSY & readb(ep->reg_hcepcs)) != 0;
+}
+
+static __inline__ void ep_setup(struct aotg_hcep *ep, u8 type, u8 buftype)
+{
+ ep->buftype = buftype;
+ writeb(type | buftype, ep->reg_hcepcon);
+}
+
+static __inline__ void pio_irq_disable(struct aotg_hcd *acthcd, u8 mask)
+{
+ u8 is_out = mask & USB_HCD_OUT_MASK;
+ u8 ep_num = mask & 0x0f;
+
+ if (is_out) {
+ usb_clearbitsw(1 << ep_num, acthcd->base + HCOUTxIEN0);
+ } else {
+ usb_clearbitsw(1 << ep_num, acthcd->base + HCINxIEN0);
+ }
+ return;
+}
+
+static __inline__ void pio_irq_enable(struct aotg_hcd *acthcd, u8 mask)
+{
+ u8 is_out = mask & USB_HCD_OUT_MASK;
+ u8 ep_num = mask & 0x0f;
+
+ if (is_out) {
+ usb_setbitsw(1 << ep_num, acthcd->base + HCOUTxIEN0);
+ } else {
+ usb_setbitsw(1 << ep_num, acthcd->base + HCINxIEN0);
+ }
+ return;
+}
+
+static __inline__ void pio_irq_clear(struct aotg_hcd *acthcd, u8 mask)
+{
+ u8 is_out = mask & USB_HCD_OUT_MASK;
+ u8 ep_num = mask & 0x0f;
+
+ if (is_out) {
+ writew(1 << ep_num, acthcd->base + HCOUTxIRQ0);
+ }
+ else {
+ writew(1 << ep_num, acthcd->base + HCINxIRQ0);
+ }
+ return;
+}
+
+static __inline__ void ep_enable(struct aotg_hcep *ep)
+{
+ usb_setbitsb(0x80, ep->reg_hcepcon);
+}
+
+static __inline__ void ep_disable(struct aotg_hcep *ep)
+{
+ usb_clearbitsb(0x80, ep->reg_hcepcon);
+}
+
+static __inline__ void aotg_sofirq_on(struct aotg_hcd *acthcd)
+{
+ usb_setbitsb((1 << 1), acthcd->base + USBIEN);
+}
+
+static __inline__ void aotg_sofirq_off(struct aotg_hcd *acthcd)
+{
+ usb_clearbitsb(1 << 1, acthcd->base + USBIEN);
+}
+
+static __inline__ int get_subbuffer_count(u8 buftype)
+{
+ int count = 0;
+
+ switch (buftype) {
+ case EPCON_BUF_SINGLE:
+ count = 1;
+ break;
+ case EPCON_BUF_DOUBLE:
+ count = 2;
+ break;
+ case EPCON_BUF_TRIPLE:
+ count = 3;
+ break;
+ case EPCON_BUF_QUAD:
+ count = 4;
+ break;
+ }
+
+ return count;
+}
+
+static __inline__ void aotg_enable_irq(struct aotg_hcd *acthcd)
+{
+ //usb_setbitsb(USBEIRQ_USBIEN | USBEIRQ_CON_DISCONIEN, acthcd->base + USBEIRQ);
+ writeb(USBEIRQ_USBIEN, acthcd->base + USBEIRQ);
+ usb_setbitsb(USBEIRQ_USBIEN, acthcd->base + USBEIEN);
+ usb_setbitsb(0x1<<2, acthcd->base + OTGIEN);
+//DEBUG
+// usb_setbitsb(0x1<<4,acthcd->base + USBEIEN);
+
+ printk("USBEIEN(0x%p): 0x%02X\n", acthcd->base + USBEIEN, readb(acthcd->base + USBEIEN));
+ usb_setbitsb(OTGCTRL_BUSREQ, acthcd->base + OTGCTRL);
+}
+
+static __inline__ void aotg_disable_irq(struct aotg_hcd *acthcd)
+{
+ //usb_setbitsb(USBEIRQ_USBIEN | USBEIRQ_CON_DISCONIEN, acthcd->base + USBEIRQ);
+ writeb(USBEIRQ_USBIEN, acthcd->base + USBEIRQ);
+ usb_clearbitsb(USBEIRQ_USBIEN, acthcd->base + USBEIEN);
+ usb_clearbitsb(0x1<<2, acthcd->base + OTGIEN);
+ usb_clearbitsb(OTGCTRL_BUSREQ, acthcd->base + OTGCTRL);
+}
+
+static inline void aotg_config_hub_addr(struct urb *urb, struct aotg_hcep *ep)
+{
+ if (ep->has_hub) {
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ writeb(usb_pipedevice(urb->pipe), ep->reg_hcep_dev_addr);
+ writeb(urb->dev->portnum, ep->reg_hcep_port);
+ } else {
+ writeb((0x80 | usb_pipedevice(urb->pipe)), ep->reg_hcep_dev_addr);
+ if (urb->dev->speed == USB_SPEED_LOW) {
+ writeb(0x80 | urb->dev->portnum, ep->reg_hcep_port);
+ } else {
+ writeb(urb->dev->portnum, ep->reg_hcep_port);
+ }
+ }
+ //writeb(0, ep->reg_hcep_splitcs);
+ } else {
+ writeb(usb_pipedevice(urb->pipe), ep->reg_hcep_dev_addr);
+ writeb(urb->dev->portnum, ep->reg_hcep_port);
+ }
+}
+
+#if (1)
+static void aotg_start_ring_transfer(struct aotg_hcd *acthcd, struct aotg_hcep *ep,
+ struct urb *urb)
+{
+ u32 addr;
+ struct aotg_trb *trb;
+ struct aotg_ring *ring = ep->ring;
+
+ aotg_config_hub_addr(urb, ep);
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ writeb(ep->interval, ep->reg_hcep_interval);
+ if (ring->is_out) {
+ trb = ring->dequeue_trb;
+ trb->hw_buf_ptr = urb->transfer_dma;
+ trb->hw_buf_len = urb->transfer_buffer_length;
+ }
+
+ }
+ ep_enable(ep);
+ addr = ring_trb_virt_to_dma(ring, ring->dequeue_trb);
+ aotg_start_ring(ring, addr);
+}
+
+#else
+static void aotg_start_ring_transfer(struct aotg_hcd *acthcd, struct aotg_hcep *ep,
+ struct urb *urb)
+{
+ u32 addr;
+ struct aotg_ring *ring = ep->ring;
+
+ aotg_config_hub_addr(urb, ep);
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ writeb(ep->interval, ep->reg_hcep_interval);
+ addr = ring_trb_virt_to_dma(ring, ring->first_trb);
+ } else {
+ addr = ring_trb_virt_to_dma(ring, ring->dequeue_trb);
+ }
+ ep_enable(ep);
+ aotg_start_ring(ring, addr);
+}
+#endif
+/*
+static void aotg_stop_ring_transfer(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ struct aotg_ring *ring = ep->ring;
+
+ ep_disable(ep);
+ aotg_stop_ring(ring);
+}
+*/
+static int aotg_hcep_config_iso(struct aotg_hcd *acthcd, struct aotg_hcep *ep,
+ u8 type, u8 buftype, int is_out)
+{
+ int index = 0;
+ ulong addr = 0;
+ int get_ep = 0;
+ int subbuffer_count;
+ //u8 fifo_ctrl;
+
+ if (0 == (subbuffer_count = get_subbuffer_count(buftype))) {
+ dev_err(acthcd->dev, "error buftype: %02X, %s, %d\n", buftype, __func__, __LINE__);
+ return -EPIPE;
+ }
+
+ if (is_out) {
+ for (index = 1; index < MAX_EP_NUM; index++) {
+ if (acthcd->outep[index] == NULL) {
+ ep->is_out = 1;
+ ep->index = index;
+ ep->mask = (u8) (USB_HCD_OUT_MASK | index);
+ acthcd->outep[index] = ep;
+ get_ep = 1;
+ break;
+ }
+ }
+ } else {
+ for (index = 1; index < MAX_EP_NUM; index++) {
+ if (acthcd->inep[index] == NULL) {
+ ep->is_out = 0;
+ ep->index = index;
+ ep->mask = (u8) index;
+ acthcd->inep[index] = ep;
+ get_ep = 1;
+ break;
+ }
+ }
+ }
+
+ if (!get_ep) {
+ dev_err(acthcd->dev, "%s: no more available space for ep\n", __func__);
+ return -ENOSPC;
+ }
+
+ addr = get_fifo_addr(acthcd, subbuffer_count * MAX_PACKET(ep->maxpacket));
+ if (addr == 0) {
+ dev_err(acthcd->dev, "buffer configuration overload!! addr: %08X, subbuffer_count: %d, ep->maxpacket: %u\n",
+ (u32)addr, subbuffer_count, MAX_PACKET(ep->maxpacket));
+ if (is_out) {
+ acthcd->outep[ep->index] = NULL;
+ }
+ else {
+ acthcd->inep[ep->index] = NULL;
+ }
+ return -ENOSPC;
+ }
+ else {
+ ep->fifo_addr = addr;
+ }
+
+ ep->reg_hcepcon = get_hcepcon_reg(is_out,
+ acthcd->base + HCOUT1CON,
+ acthcd->base + HCIN1CON,
+ ep->index);
+ ep->reg_hcepcs = get_hcepcs_reg(is_out,
+ acthcd->base + HCOUT1CS,
+ acthcd->base + HCIN1CS,
+ ep->index);
+ ep->reg_hcepbc = get_hcepbc_reg(is_out,
+ acthcd->base + HCOUT1BCL,
+ acthcd->base + HCIN1BCL,
+ ep->index);
+ ep->reg_hcepctrl = get_hcepctrl_reg(is_out,
+ acthcd->base + HCOUT1CTRL,
+ acthcd->base + HCIN1CTRL,
+ ep->index);
+ ep->reg_hcmaxpck = get_hcepmaxpck_reg(is_out,
+ acthcd->base + HCOUT1MAXPCKL,
+ acthcd->base + HCIN1MAXPCKL,
+ ep->index);
+ ep->reg_hcepaddr = get_hcepaddr_reg(is_out,
+ acthcd->base + HCOUT1STADDR,
+ acthcd->base + HCIN1STADDR,
+ ep->index);
+ ep->reg_hcep_dev_addr = get_hcep_dev_addr_reg(is_out,
+ acthcd->base + HCOUT1ADDR,
+ acthcd->base + HCIN1ADDR,
+ ep->index);
+ ep->reg_hcep_port = get_hcep_port_reg(is_out,
+ acthcd->base + HCOUT1PORT,
+ acthcd->base + HCIN1PORT,
+ ep->index);
+ ep->reg_hcep_splitcs = get_hcep_splitcs_reg(is_out,
+ acthcd->base + HCOUT1SPILITCS,
+ acthcd->base + HCIN1SPILITCS,
+ ep->index);
+
+ //ep->reg_hcfifo = get_hcfifo_reg(acthcd->base + FIFO1DATA, ep->index);
+ if (!is_out) {
+ ///* 5202 is just for write, read's HCINXCOUNT address is not the same with write address. */
+ //ep->reg_hcincount_wt = acthcd->base + HCIN1_COUNTL + (ep->index - 1) * 4;
+ //ep->reg_hcincount_rd = acthcd->base + HCIN1_COUNTL + (ep->index - 1) * 2;
+ ep->reg_hcerr = acthcd->base + HCIN0ERR + ep->index * 0x4;
+ ep->reg_hcep_interval = acthcd->base + HCEP0BINTERVAL + ep->index * 0x8;
+ }
+ else {
+ ep->reg_hcerr = acthcd->base + HCOUT0ERR + ep->index * 0x4;
+ ep->reg_hcep_interval = acthcd->base + HCOUT1BINTERVAL + (ep->index - 1) * 0x8;
+ }
+
+#ifdef DEBUG_EP_CONFIG
+ dev_info(acthcd->dev, "== ep->index: %d, is_out: %d, fifo addr: %08X\n", ep->index, is_out, (u32)addr);
+ dev_info(acthcd->dev, "== reg_hcepcon: %08lX, reg_hcepcs: %08lX, reg_hcepbc: %08lX, reg_hcepctrl: %08lX, reg_hcmaxpck: %08lX, ep->reg_hcepaddr: %08lX\n",
+ ep->reg_hcepcon,
+ ep->reg_hcepcs,
+ ep->reg_hcepbc,
+ ep->reg_hcepctrl,
+ ep->reg_hcmaxpck,
+ ep->reg_hcepaddr);
+#endif
+
+ /*allocate buffer address of ep fifo */
+ writel(addr, ep->reg_hcepaddr);
+ writew(ep->maxpacket, ep->reg_hcmaxpck);
+ ep_setup(ep, type, buftype); /*ep setup */
+
+ /*reset this ep */
+ usb_settoggle(ep->udev, ep->epnum, is_out, 0);
+ aotg_hcep_reset(acthcd, ep->mask, ENDPRST_FIFORST | ENDPRST_TOGRST);
+ writeb(ep->epnum, ep->reg_hcepctrl);
+
+ return 0;
+}
+
+//support 3 bulk, 1 interrupt
+static int aotg_hcep_config(struct aotg_hcd *acthcd,
+ struct aotg_hcep *ep,
+ u8 type, u8 buftype, int is_out)
+{
+ int index = 0;
+ ulong addr = 0;
+ int get_ep = 0;
+ int subbuffer_count;
+ //u8 fifo_ctrl;
+
+ if (0 == (subbuffer_count = get_subbuffer_count(buftype))) {
+ dev_err(acthcd->dev, "error buftype: %02X, %s, %d\n", buftype, __func__, __LINE__);
+ return -EPIPE;
+ }
+
+ if (is_out) {
+ for (index = 1; index < MAX_EP_NUM; index++) {
+ if (acthcd->outep[index] == NULL) {
+ ep->is_out = 1;
+ ep->index = index;
+ ep->mask = (u8) (USB_HCD_OUT_MASK | index);
+ acthcd->outep[index] = ep;
+ get_ep = 1;
+ break;
+ }
+ }
+ } else {
+ for (index = 1; index < MAX_EP_NUM; index++) {
+ if (acthcd->inep[index] == NULL) {
+ ep->is_out = 0;
+ ep->index = index;
+ ep->mask = (u8) index;
+ acthcd->inep[index] = ep;
+ get_ep = 1;
+ break;
+ }
+ }
+ }
+
+ if (!get_ep) {
+ dev_err(acthcd->dev, "%s: no more available space for ep\n", __func__);
+ return -ENOSPC;
+ }
+
+ addr = get_fifo_addr(acthcd, subbuffer_count * MAX_PACKET(ep->maxpacket));
+ if (addr == 0) {
+ dev_err(acthcd->dev, "buffer configuration overload!! addr: %08X, subbuffer_count: %d, ep->maxpacket: %u\n",
+ (u32)addr, subbuffer_count, MAX_PACKET(ep->maxpacket));
+ if (is_out) {
+ acthcd->outep[ep->index] = NULL;
+ }
+ else {
+ acthcd->inep[ep->index] = NULL;
+ }
+ return -ENOSPC;
+ }
+ else {
+ ep->fifo_addr = addr;
+ }
+
+ ep->reg_hcepcon = get_hcepcon_reg(is_out,
+ acthcd->base + HCOUT1CON,
+ acthcd->base + HCIN1CON,
+ ep->index);
+ ep->reg_hcepcs = get_hcepcs_reg(is_out,
+ acthcd->base + HCOUT1CS,
+ acthcd->base + HCIN1CS,
+ ep->index);
+ ep->reg_hcepbc = get_hcepbc_reg(is_out,
+ acthcd->base + HCOUT1BCL,
+ acthcd->base + HCIN1BCL,
+ ep->index);
+ ep->reg_hcepctrl = get_hcepctrl_reg(is_out,
+ acthcd->base + HCOUT1CTRL,
+ acthcd->base + HCIN1CTRL,
+ ep->index);
+ ep->reg_hcmaxpck = get_hcepmaxpck_reg(is_out,
+ acthcd->base + HCOUT1MAXPCKL,
+ acthcd->base + HCIN1MAXPCKL,
+ ep->index);
+ ep->reg_hcepaddr = get_hcepaddr_reg(is_out,
+ acthcd->base + HCOUT1STADDR,
+ acthcd->base + HCIN1STADDR,
+ ep->index);
+ ep->reg_hcep_dev_addr = get_hcep_dev_addr_reg(is_out,
+ acthcd->base + HCOUT1ADDR,
+ acthcd->base + HCIN1ADDR,
+ ep->index);
+ ep->reg_hcep_port = get_hcep_port_reg(is_out,
+ acthcd->base + HCOUT1PORT,
+ acthcd->base + HCIN1PORT,
+ ep->index);
+ ep->reg_hcep_splitcs = get_hcep_splitcs_reg(is_out,
+ acthcd->base + HCOUT1SPILITCS,
+ acthcd->base + HCIN1SPILITCS,
+ ep->index);
+
+ //ep->reg_hcfifo = get_hcfifo_reg(acthcd->base + FIFO1DATA, ep->index);
+ if (!is_out) {
+ ///* 5202 is just for write, read's HCINXCOUNT address is not the same with write address. */
+ //ep->reg_hcincount_wt = acthcd->base + HCIN1_COUNTL + (ep->index - 1) * 4;
+ //ep->reg_hcincount_rd = acthcd->base + HCIN1_COUNTL + (ep->index - 1) * 2;
+ ep->reg_hcerr = acthcd->base + HCIN0ERR + ep->index * 0x4;
+ ep->reg_hcep_interval = acthcd->base + HCEP0BINTERVAL + ep->index * 0x8;
+ }
+ else {
+ ep->reg_hcerr = acthcd->base + HCOUT0ERR + ep->index * 0x4;
+ ep->reg_hcep_interval = acthcd->base + HCOUT1BINTERVAL + (ep->index - 1) * 0x8;
+ }
+
+#ifdef DEBUG_EP_CONFIG
+ dev_info(acthcd->dev, "== ep->index: %d, is_out: %d, fifo addr: %08X\n", ep->index, is_out, (u32)addr);
+ dev_info(acthcd->dev, "== reg_hcepcon: %08lX, reg_hcepcs: %08lX, reg_hcepbc: %08lX, reg_hcepctrl: %08lX, reg_hcmaxpck: %08lX, ep->reg_hcepaddr: %08lX\n",
+ ep->reg_hcepcon,
+ ep->reg_hcepcs,
+ ep->reg_hcepbc,
+ ep->reg_hcepctrl,
+ ep->reg_hcmaxpck,
+ ep->reg_hcepaddr);
+#endif
+
+ pio_irq_disable(acthcd, ep->mask);
+ pio_irq_clear(acthcd, ep->mask);
+
+ ep_disable(ep);
+
+ /*allocate buffer address of ep fifo */
+ writel(addr, ep->reg_hcepaddr);
+ writew(ep->maxpacket, ep->reg_hcmaxpck);
+ ep_setup(ep, type, buftype); /*ep setup */
+
+ /*reset this ep */
+ usb_settoggle(ep->udev, ep->epnum, is_out, 0);
+ aotg_hcep_reset(acthcd, ep->mask, ENDPRST_FIFORST | ENDPRST_TOGRST);
+ writeb(ep->epnum, ep->reg_hcepctrl);
+
+ //fifo_ctrl = (1<<5) | ((!!is_out) << 4) | ep->index; //set auto fifo
+ //writeb(fifo_ctrl, acthcd->base + FIFOCTRL);
+ //pio_irq_enable(acthcd, ep->mask);
+
+ return 0;
+}
+
+static int aotg_hcep_set_split_micro_frame(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ static const u8 split_val[] = {0x31, 0x42, 0x53, 0x64, 0x75, 0x17, 0x20};
+ int i, index;
+ u8 set_val, rd_val;
+
+ for (i=0; i<sizeof(split_val); i++) {
+ set_val = split_val[i];
+
+ for (index=0; index<MAX_EP_NUM; index++) {
+ if (acthcd->inep[index] != NULL) {
+ rd_val = acthcd->inep[index]->reg_hcep_splitcs_val;
+
+ if ((0 == rd_val) || (set_val != rd_val)) {
+ continue;
+ }
+ if (set_val == rd_val)
+ set_val = 0;
+ break;
+ }
+ }
+ if (set_val == 0)
+ continue;
+
+ for (index=0; index<MAX_EP_NUM; index++) {
+ if (acthcd->outep[index] != NULL) {
+ rd_val = acthcd->outep[index]->reg_hcep_splitcs_val;
+
+ if ((0 == rd_val) || (set_val != rd_val)) {
+ continue;
+ }
+ if (set_val == rd_val)
+ set_val = 0;
+ break;
+ }
+ }
+
+ if (set_val != 0)
+ break;
+ }
+
+ if (set_val != 0) {
+ ep->reg_hcep_splitcs_val = set_val;
+ writeb(set_val, ep->reg_hcep_splitcs);
+ printk("====reg_hcep_splitcs_val:%x, index:%d\n", set_val, ep->index);
+ }
+ return 0;
+}
+
+static void finish_request(struct aotg_hcd *acthcd,
+ struct aotg_queue *q,
+ int status)
+{
+ struct urb *urb = q->urb;
+
+ if (unlikely((acthcd == NULL) || (q == NULL) || (urb == NULL))) {
+ WARN_ON(1);
+ return;
+ }
+
+ q->status = status;
+ if (list_empty(&q->finished_list)) {
+ list_add_tail(&q->finished_list, &acthcd->hcd_finished_list);
+ } else {
+ ACT_HCD_ERR
+ }
+ tasklet_hi_schedule(&acthcd->urb_tasklet);
+ return;
+}
+
+static void tasklet_finish_request(struct aotg_hcd *acthcd,
+ struct aotg_queue *q,
+ int status)
+{
+ struct urb *urb = q->urb;
+ struct aotg_hcep *ep = q->ep;
+
+ if (unlikely((acthcd == NULL) || (q == NULL) || (urb == NULL))) {
+ WARN_ON(1);
+ return;
+ }
+
+ if ((q != NULL) && (ep != NULL)) {
+ if (ep->q == NULL) {
+ ACT_HCD_ERR
+ } else {
+ if (ep->q == q) {
+ ep->q = NULL;
+ }
+ }
+ } else {
+ ACT_HCD_ERR
+ return;
+ }
+
+ if (status == 0) {
+ q->err_count = 0;
+ }
+
+ if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+ if ((acthcd->active_ep0 != NULL) && (acthcd->active_ep0 == q->ep)) {
+ if (acthcd->active_ep0->q == NULL) {
+ acthcd->active_ep0 = NULL;
+ } else {
+ ACT_HCD_ERR
+ }
+ } else {
+ ACT_HCD_ERR
+ }
+ }
+#if 0
+ if (q->td.trb_vaddr && q->td.trb_num) {
+ dma_free_coherent(aotg_to_hcd(acthcd)->self.controller,
+ q->td.trb_num * sizeof(struct aotg_trb),
+ q->td.trb_vaddr, q->td.trb_dma);
+ }
+#endif
+ aotg_dbg_finish_q(q);
+ aotg_hcd_release_queue(acthcd, q);
+ //usb_hcd_unlink_urb_from_ep(hcd, urb);
+ //usb_hcd_giveback_urb(hcd, urb, status);
+
+ ep->urb_endque_cnt++;
+ //ep->fifo_busy = 0;
+ //if (usb_pipeint(urb->pipe))
+ return;
+}
+
+static __inline__ void handle_status(struct aotg_hcd *acthcd, struct aotg_hcep *ep, int is_out)
+{
+ /*status always DATA1,set 1 to ep0 toggle */
+ writeb(EP0CS_HCSETTOOGLE, acthcd->base + EP0CS);
+
+ if (is_out) {
+ writeb(0, acthcd->base + HCIN0BC); //recv 0 packet
+ }
+ else {
+ writeb(0, acthcd->base + HCOUT0BC); //send 0 packet
+ }
+}
+
+static void write_hcep0_fifo(struct aotg_hcd *acthcd, struct aotg_hcep *ep, struct urb *urb)
+{
+ u32 *buf;
+ int length, count;
+ void __iomem *addr = acthcd->base + EP0INDATA_W0;
+
+ if (!(readb(acthcd->base + EP0CS) & EP0CS_HCOUTBSY)) {
+ buf = (u32 *) (urb->transfer_buffer + urb->actual_length);
+ prefetch(buf);
+
+ /* how big will this packet be? */
+ length = min((int)ep->maxpacket, (int)urb->transfer_buffer_length - (int)urb->actual_length);
+
+ count = length >> 2; /*wirte in DWORD */
+ if (length & 0x3) count++;
+
+ while (likely(count--)) {
+ writel(*buf, addr);
+ buf++;
+ addr += 4;
+ }
+
+ ep->length = length;
+ writeb(length, acthcd->base + HCOUT0BC);
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), 1);
+ } else {
+ dev_err(acthcd->dev, "<CTRL>OUT data is not ready\n");
+ }
+}
+
+static void read_hcep0_fifo(struct aotg_hcd *acthcd, struct aotg_hcep *ep, struct urb *urb)
+{
+ u8 *buf;
+ unsigned overflag, is_short, shorterr, is_last;
+ unsigned length, count;
+ struct usb_device *udev;
+ void __iomem *addr = acthcd->base + EP0OUTDATA_W0; //HCEP0INDAT0;
+ unsigned bufferspace;
+
+ overflag = 0;
+ is_short = 0;
+ shorterr = 0;
+ is_last = 0;
+ udev = ep->udev;
+
+ if (readb(acthcd->base + EP0CS) & EP0CS_HCINBSY) {
+ dev_err(acthcd->dev, "<CTRL>IN data is not ready\n");
+ return;
+ } else {
+ usb_dotoggle(udev, ep->epnum, 0);
+ buf = urb->transfer_buffer + urb->actual_length;
+ bufferspace = urb->transfer_buffer_length - urb->actual_length;
+ //prefetch(buf);
+
+ length = count = readb(acthcd->base + HCIN0BC);
+ if (length > bufferspace) {
+ count = bufferspace;
+ urb->status = -EOVERFLOW;
+ overflag = 1;
+ }
+
+ urb->actual_length += count;
+ while (count--) {
+ *buf++ = readb(addr);
+#if 0
+ buf--;
+ printk("ep0in:%x, cnt:%d\n", (unsigned int)*buf, count);
+ buf++;
+#endif
+ addr++;
+ }
+
+ if (urb->actual_length >= urb->transfer_buffer_length) {
+ ep->nextpid = USB_PID_ACK;
+ is_last = 1;
+ handle_status(acthcd, ep, 0);
+ } else if (length < ep->maxpacket) {
+ is_short = 1;
+ is_last = 1;
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ urb->status = -EREMOTEIO;
+ shorterr = 1;
+ }
+ ep->nextpid = USB_PID_ACK;
+ handle_status(acthcd, ep, 0);
+ }
+ else {
+ writeb(0, acthcd->base + HCIN0BC);
+ }
+ }
+}
+
+static int handle_setup_packet(struct aotg_hcd *acthcd, struct aotg_queue *q)
+{
+ struct urb *urb = q->urb;
+ struct aotg_hcep *ep = q->ep;
+ u32 *buf;
+ void __iomem *addr = acthcd->base + EP0INDATA_W0;
+ int i = 0;
+
+#ifdef DEBUG_SETUP_DATA
+ u16 w_value, w_index, w_length;
+ struct usb_ctrlrequest *ctrlreq;
+
+ ctrlreq = (struct usb_ctrlrequest *)urb->setup_packet;
+ w_value = le16_to_cpu(ctrlreq->wValue);
+ w_index = le16_to_cpu(ctrlreq->wIndex);
+ w_length = le16_to_cpu(ctrlreq->wLength);
+ dev_info(acthcd->dev, "<CTRL>SETUP stage %02x.%02x V%04x I%04x L%04x\n ",
+ ctrlreq->bRequestType, ctrlreq->bRequest, w_value, w_index,
+ w_length);
+#endif
+ if ((q->is_xfer_start) || (ep->q)) {
+ ACT_HCD_DBG
+ printk("q->is_xfer_start:%d\n", q->is_xfer_start);
+ return 0;
+ }
+ if (unlikely(!HC_IS_RUNNING(aotg_to_hcd(acthcd)->state))) {
+ ACT_HCD_DBG
+ return -ESHUTDOWN;
+ }
+ if (acthcd->active_ep0 != NULL) {
+ ACT_HCD_ERR
+ return -EBUSY;
+ }
+
+ writeb(ep->epnum, acthcd->base + HCEP0CTRL);
+ writeb((u8)ep->maxpacket, acthcd->base + HCIN0MAXPCK);
+
+ acthcd->active_ep0 = ep;
+ ep->q = q;
+ q->is_xfer_start = 1;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), 1, 1);
+ ep->nextpid = USB_PID_SETUP;
+ buf = (u32 *) urb->setup_packet;
+
+ /*initialize the setup stage */
+ writeb(EP0CS_HCSET, acthcd->base + EP0CS);
+ while (readb(acthcd->base + EP0CS) & EP0CS_HCOUTBSY) {
+ writeb(EP0CS_HCSET, acthcd->base + EP0CS);
+ i++;
+ if (i > 2000000) {
+ printk("handle_setup timeout!\n");
+ break;
+ }
+ }
+
+ if (!(readb(acthcd->base + EP0CS) & EP0CS_HCOUTBSY)) {
+ /*fill the setup data in fifo */
+ writel(*buf, addr);
+ addr += 4;
+ buf++;
+ writel(*buf, addr);
+ writeb(8, acthcd->base + HCOUT0BC);
+ }
+ else {
+ dev_warn(acthcd->dev, "setup ep busy!!!!!!!\n");
+ }
+
+ return 0;
+}
+
+static void handle_hcep0_out(struct aotg_hcd *acthcd)
+{
+ struct aotg_hcep *ep;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct aotg_queue *q;
+
+ ep = acthcd->active_ep0;
+
+ if (unlikely(!ep)) {
+ ACT_HCD_ERR
+ return;
+ }
+ q = ep->q;
+ if (q == NULL) {
+ ACT_HCD_ERR
+ return;
+ }
+
+ urb = q->urb;
+ udev = ep->udev;
+
+ switch (ep->nextpid) {
+ case USB_PID_SETUP:
+ if (urb->transfer_buffer_length == urb->actual_length) {
+ ep->nextpid = USB_PID_ACK;
+ handle_status(acthcd, ep, 1); /*no-data transfer */
+ } else if (usb_pipeout(urb->pipe)) {
+ usb_settoggle(udev, 0, 1, 1);
+ ep->nextpid = USB_PID_OUT;
+ write_hcep0_fifo(acthcd, ep, urb);
+ } else {
+ usb_settoggle(udev, 0, 0, 1);
+ ep->nextpid = USB_PID_IN;
+ writeb(0, acthcd->base + HCIN0BC);
+ }
+ break;
+ case USB_PID_OUT:
+ urb->actual_length += ep->length;
+ usb_dotoggle(udev, ep->epnum, 1);
+ if (urb->actual_length >= urb->transfer_buffer_length) {
+ ep->nextpid = USB_PID_ACK;
+ handle_status(acthcd, ep, 1); /*control write transfer */
+ }
+ else {
+ ep->nextpid = USB_PID_OUT;
+ write_hcep0_fifo(acthcd, ep, urb);
+ }
+ break;
+ case USB_PID_ACK:
+ finish_request(acthcd, q, 0);
+ break;
+ default:
+ dev_err(acthcd->dev, "<CTRL>ep0 out ,odd pid %d, %s, %d\n",
+ ep->nextpid, __func__, __LINE__);
+ }
+}
+
+static void handle_hcep0_in(struct aotg_hcd *acthcd)
+{
+ struct aotg_hcep *ep;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct aotg_queue *q;
+
+ ep = acthcd->active_ep0;
+ if (unlikely(!ep)) {
+ return;
+ }
+ q = ep->q;
+ if (q == NULL) {
+ ACT_HCD_ERR
+ return;
+ }
+
+ urb = q->urb;
+ udev = ep->udev;
+
+ switch (ep->nextpid) {
+ case USB_PID_IN:
+ read_hcep0_fifo(acthcd, ep, urb);
+ break;
+ case USB_PID_ACK:
+ finish_request(acthcd, q, 0);
+ break;
+ default:
+ dev_err(acthcd->dev, "<CTRL>ep0 out ,odd pid %d\n", ep->nextpid);
+ }
+}
+
+static void aotg_hcd_err_handle(struct aotg_hcd *acthcd, u32 irqvector,
+ int ep_num, int is_in)
+{
+ struct urb *urb;
+ struct aotg_queue *q;
+ struct aotg_hcep *ep = NULL;
+ struct aotg_ring *ring = NULL;
+ struct aotg_td *td = NULL;
+ int status = -EOVERFLOW;
+ u8 err_val = 0;
+ u8 err_type = 0;
+ u8 reset = 0;
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+
+ printk("hcd ep err ep_num:%d, is_in:%d\n", ep_num, is_in);
+
+ if (ep_num == 0) {
+ ep = acthcd->active_ep0;
+ if (ep == NULL) {
+ ACT_HCD_ERR
+ return;
+ }
+ q = ep->q;
+ if (is_in) {
+ ep->reg_hcerr = acthcd->base + HCIN0ERR;
+ } else {
+ ep->reg_hcerr = acthcd->base + HCOUT0ERR;
+ }
+ } else {
+ if (is_in) {
+ ep = acthcd->inep[ep_num];
+ } else {
+ ep = acthcd->outep[ep_num];
+ }
+ if (ep == NULL) {
+ ACT_HCD_ERR
+ printk("is_in:%d, ep_num:%d\n", is_in, ep_num);
+ return;
+ }
+ ring = ep->ring;
+ if (!ring) {
+ ACT_HCD_ERR
+ return;
+ }
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td) {
+ aotg_stop_ring(ring);
+ ACT_HCD_ERR
+ return;
+ }
+ }
+
+ err_val = readb(ep->reg_hcerr);
+ if (is_in) {
+ writew(1 << ep_num, acthcd->base + HCINxERRIRQ0);
+ } else {
+ writew(1 << ep_num, acthcd->base + HCOUTxERRIRQ0);
+ }
+
+ err_type = err_val & HCINxERR_TYPE_MASK;
+ printk("err_type:%x\n",err_type>>2);
+ switch (err_type) {
+ case HCINxERR_NO_ERR:
+ case HCINxERR_OVER_RUN:
+ status = -EOVERFLOW;
+ break;
+ case HCINxERR_UNDER_RUN:
+ status = -EREMOTEIO;
+ break;
+ case HCINxERR_STALL:
+ status = -EPIPE;
+ break;
+ case HCINxERR_TIMEOUT:
+ status = -ETIMEDOUT;
+ break;
+ case HCINxERR_CRC_ERR:
+ case HCINxERR_TOG_ERR:
+ case HCINxERR_PID_ERR:
+ status = -EPROTO;
+ break;
+ //case HCINxERR_SPLIET:
+ default:
+ printk("err_val:0x%x, err_type:%d\n", err_val, err_type);
+ if (is_in) {
+ printk("HCINEP%dSPILITCS:0x%x\n", ep_num,
+ readb(acthcd->base + ep_num * 8 + HCEP0SPILITCS));
+ } else {
+ printk("HCOUTEP%dSPILITCS:0x%x\n", ep_num,
+ readb(acthcd->base + (ep_num - 1) * 8 + HCOUT1SPILITCS));
+ }
+ status = -EPIPE;
+ break;
+
+ //default:
+ // printk("err_type:%x\n", err_type);
+ // status = -EOVERFLOW;
+ // reset = ENDPRST_FIFORST | ENDPRST_TOGRST;
+ }
+
+ if (!(acthcd->port & USB_PORT_STAT_ENABLE)
+ || (acthcd->port & (USB_PORT_STAT_C_CONNECTION << 16))
+ || (acthcd->hcd_exiting != 0)
+ || (acthcd->inserted == 0)
+ || !HC_IS_RUNNING(hcd->state)) {
+ dev_err(acthcd->dev, "usbport, dead, port:%x, hcd_exiting:%d \n", acthcd->port, acthcd->hcd_exiting);
+ status = -ENODEV;
+ }
+
+ if (ep->index == 0) {
+ q = ep->q;
+ urb = q->urb;
+ if ((status == -EPIPE) || (status == -ENODEV))
+ writeb(HCINxERR_RESEND, ep->reg_hcerr); /* resend. */
+ finish_request(acthcd, q, status);
+ dev_info(acthcd->dev, "%s ep %d error [0x%02X] error type [0x%02X], reset it...\n",
+ usb_pipeout(urb->pipe)?"HC OUT":"HC IN", ep->index, err_val, (err_val>>2)&0x7);
+ } else {
+ if ((status != -EPIPE) && (status != -ENODEV)) {
+ printk("td->err_count:%d\n", td->err_count);
+ td->err_count++;
+
+ if (td->err_count < MAX_ERROR_COUNT) {
+ writeb(HCINxERR_RESEND, ep->reg_hcerr); /* resend. */
+ return;
+ }
+ }
+ if (status == -ETIMEDOUT || status == -EPIPE) {
+ ep->error_count++;
+ }
+
+ reset = ENDPRST_FIFORST | ENDPRST_TOGRST;
+ ep_disable(ep);
+ if (is_in) {
+ aotg_hcep_reset(acthcd, ep->mask, reset);
+ } else {
+ aotg_hcep_reset(acthcd, ep->mask | USB_HCD_OUT_MASK, reset);
+ }
+
+ /*if (usb_pipeout(urb->pipe)) {
+ aotg_hcep_reset(acthcd, ep->mask | USB_HCD_OUT_MASK, reset);
+ } else {
+ aotg_hcep_reset(acthcd, ep->mask, reset);
+ }*/
+
+ aotg_stop_ring(ring);
+ urb = td->urb;
+ //writel(DMACTRL_DMACC,ep->ring->reg_dmactrl);
+ if (ep->type == PIPE_INTERRUPT)
+ dequeue_intr_td(ring, td);
+ else
+ dequeue_td(ring, td, TD_IN_FINISH);
+
+ if (urb) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ }
+ else
+ {
+ ERR("urb not exist!\n");
+ }
+
+ /*
+ * after, need to rewrite port_num, dev_addr when using hub ?
+ */
+ /*if ((urb) && (!list_empty(&ep->enring_td_list)) &&
+ !is_ring_running(ring)) {
+ ACT_HCD_DBG
+ ep_enable(ep);
+ addr = ring_trb_virt_to_dma(ring, ring->dequeue_trb);
+ aotg_start_ring(ring, addr);
+ }*/
+ dev_info(acthcd->dev, "%s ep %d error [0x%02X] error type [0x%02X], reset it...\n",
+ is_in?"HC IN":"HC OUT", ep->index, err_val, (err_val>>2)&0x7);
+ }
+
+ return;
+}
+#if 0
+static void aotg_hcd_error(struct aotg_hcd *acthcd, u32 irqvector, int ep_num, int is_in)
+{
+ struct aotg_queue *q;
+ struct aotg_hcep *ep = NULL;
+ struct urb *urb;
+ int status;
+ u8 error = 0;
+ u8 reset = 0;
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+
+ printk("hcd ep err ep_num:%d, is_in:%d\n", ep_num, is_in);
+
+ if (ep_num == 0) {
+ ep = acthcd->active_ep0;
+ if (ep == NULL) {
+ ACT_HCD_ERR
+ return;
+ }
+ q = ep->q;
+ if (is_in) {
+ ep->reg_hcerr = acthcd->base + HCIN0ERR;
+ } else {
+ ep->reg_hcerr = acthcd->base + HCOUT0ERR;
+ }
+ } else {
+ if (is_in) {
+ ep = acthcd->inep[ep_num];
+ } else {
+ ep = acthcd->outep[ep_num];
+ }
+ if (ep == NULL) {
+ ACT_HCD_ERR
+ printk("is_in:%d, ep_num:%d\n", is_in, ep_num);
+ return;
+ }
+ q = ep->q;
+ }
+
+ if (is_in) {
+ writew(1 << ep_num, acthcd->base + HCINxERRIRQ0);
+ } else {
+ writew(1 << ep_num, acthcd->base + HCOUTxERRIRQ0);
+ }
+ error = readb(ep->reg_hcerr);
+
+ if (q) {
+ urb = q->urb;
+
+ switch (error & HCINxERR_TYPE_MASK) {
+ case HCINxERR_NO_ERR:
+ status = 0;
+ break;
+
+ case HCINxERR_STALL:
+ status = -EPIPE;
+ reset = ENDPRST_FIFORST | ENDPRST_TOGRST;
+ break;
+
+ case HCINxERR_TIMEOUT:
+ status = -ETIMEDOUT;
+ reset = ENDPRST_FIFORST | ENDPRST_TOGRST;
+ break;
+
+ default:
+ printk("error:%x\n", ((error & HCINxERR_TYPE_MASK) >> 2));
+ status = -EIO;
+ reset = ENDPRST_FIFORST | ENDPRST_TOGRST;
+ }
+
+ if (!(acthcd->port & USB_PORT_STAT_ENABLE)
+ || (acthcd->port & (USB_PORT_STAT_C_CONNECTION << 16))
+ || (acthcd->hcd_exiting != 0)
+ || (acthcd->inserted == 0)
+ || !HC_IS_RUNNING(hcd->state)) {
+ dev_err(acthcd->dev, "usbport, dead, port:%x, hcd_exiting:%d \n", acthcd->port, acthcd->hcd_exiting);
+ status = -ENODEV;
+ }
+
+ if (status < 0) {
+ ACT_HCD_DBG
+ printk("status:%d\n", status);
+
+ if (ep->index > 0 && (status != -EPIPE) && (status != -ENODEV)) {
+ printk("q->err_count:%d\n", q->err_count);
+ q->err_count++;
+ writeb(HCINxERR_RESEND, ep->reg_hcerr); /* resend. */
+
+ if ((q->err_count % MAX_ERROR_COUNT) < (MAX_ERROR_COUNT - 1)) {
+ return;
+ }
+ if (q->err_count > MAX_ERROR_COUNT * 3) {
+ ACT_HCD_DBG
+ q->err_count = 0;
+ acthcd->discon_happened = 1;
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1));
+ return;
+ }
+ }
+
+ if ((ep->index == 0) && ((status == -EPIPE) || (status == -ENODEV))) {
+ writeb(HCINxERR_RESEND, ep->reg_hcerr); /* resend. */
+ }
+
+ if (ep->index > 0) {
+ if (usb_pipeout(urb->pipe)) {
+ aotg_hcep_reset(acthcd, ep->mask | USB_HCD_OUT_MASK, reset);
+ } else {
+ ep_disable(ep);
+ aotg_hcep_reset(acthcd, ep->mask, reset);
+ }
+ }
+ dev_info(acthcd->dev, "%s ep %d error [0x%02X] error type [0x%02X], reset it...\n",
+ usb_pipeout(urb->pipe)?"HC OUT":"HC IN", ep->index, error, (error>>2)&0x7);
+#if 0
+ if (AOTG_GET_DMA_NUM(q->dma_no)) {
+ ACT_HCD_DBG
+ __clear_dma(acthcd, q);
+ }
+#endif
+ finish_request(acthcd, q, status);
+ }
+ }
+ tasklet_hi_schedule(&acthcd->urb_tasklet);
+
+ return;
+}
+#endif
+
+void aotg_hcd_abort_urb(struct aotg_hcd *acthcd)
+{
+ int cnt;
+ struct aotg_hcep *ep;
+ struct urb *urb;
+ struct aotg_ring *ring;
+ struct aotg_td *td;
+ unsigned long flags;
+// struct aotg_queue *q;
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+
+/* if (HC_IS_SUSPENDED(hcd->state)) {
+ usb_hcd_resume_root_hub(hcd);
+ }
+ //ACT_HCD_DBG
+ //aotg_hcd_flush_queue(acthcd);
+ usb_hcd_poll_rh_status(hcd);*/
+
+ spin_lock_irqsave(&acthcd->lock, flags);
+ /*ep = acthcd->active_ep0;
+ if (ep && ep->q) {
+ q = ep->q;
+ urb = q->urb;
+ q->status = -ENODEV;
+ //printk("%s in ep 0\n",__func__);
+ aotg_hcd_release_queue(acthcd, q);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(hcd, urb, -ENODEV);
+ spin_lock(&acthcd->lock);
+ }*/
+
+ for (cnt=1; cnt<MAX_EP_NUM; cnt++) {
+ ep = acthcd->inep[cnt];
+ if (ep) {
+ ring = ep->ring;
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td)
+ continue;
+ urb = td->urb;
+ if (!urb)
+ continue;
+ if (ep->type == PIPE_INTERRUPT)
+ dequeue_intr_td(ring, td);
+ else
+ dequeue_td(ring, td, TD_IN_FINISH);
+ //printk("%s in ep %d\n",__func__,cnt);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(hcd, urb, -ENODEV);
+ spin_lock(&acthcd->lock);
+ }
+ }
+
+ for (cnt=1; cnt<MAX_EP_NUM; cnt++) {
+ ep = acthcd->outep[cnt];
+ if (ep) {
+ ring = ep->ring;
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td)
+ continue;
+ urb = td->urb;
+ if (!urb)
+ continue;
+ if (ep->type == PIPE_INTERRUPT)
+ dequeue_intr_td(ring, td);
+ else
+ dequeue_td(ring, td, TD_IN_FINISH);
+ //printk("%s out ep %d\n",__func__,cnt);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(hcd, urb, -ENODEV);
+ spin_lock(&acthcd->lock);
+ }
+ }
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+}
+
+static irqreturn_t aotg_hub_irq(struct usb_hcd *hcd)
+{
+ struct platform_device *pdev;
+ unsigned int port_no;
+ u32 irqvector;
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ u8 eirq_mask = readb(acthcd->base + USBEIEN);
+ u8 eirq_pending = readb(acthcd->base + USBEIRQ);
+ u8 otg_state;
+
+ /* take cate to use lock, because in irq -> dma_handler -> finish_request ->
+ * usb_hcd_giveback_urb -> urb->complete(), it maybe call enqueue and get spin_lock again.
+ */
+ //spin_lock(&acthcd->lock);
+ pdev = to_platform_device(hcd->self.controller);
+ port_no = pdev->id & 0xff;
+#if(0)
+ int i = 0;
+ irqvector = (u32)readb(acthcd->base + IVECT);
+ printk("USBEIEN:0x%x, USBEIRQ:0x%x, ivec:0x%x\n", readb(acthcd->base + USBEIEN),
+ readb(acthcd->base + USBEIRQ), irqvector);
+ printk("HCINxDMAIRQ0:0x%x, HCOUTxDMAIRQ0:0x%x\n",
+ readw(acthcd->base + HCINxDMAIRQ0),
+ readw(acthcd->base + HCOUTxDMAIRQ0));
+ for (i = 0; i <= 0x1d; i++) {
+ printk("0x%p : 0x%x\n", acthcd->base + 0x500 + i,
+ readb(acthcd->base + 0x500 + i));
+ }
+#endif
+
+ if (eirq_pending & USBEIRQ_USBIRQ) {
+ irqvector = (u32)readb(acthcd->base + IVECT);
+ writeb(eirq_mask | USBEIRQ_USBIRQ, acthcd->base + USBEIRQ);
+// HUB_DEBUG("irqvector:%d, 0x%x\n", irqvector, irqvector);
+
+ switch (irqvector) {
+ //case UIV_OTGIRQ:
+ case UIV_IDLE:
+ case UIV_SRPDET:
+ case UIV_LOCSOF:
+ case UIV_VBUSERR:
+ case UIV_PERIPH:
+ if (readb(acthcd->base + OTGIRQ) & (0x1<<2)) {
+ writeb(0x1<<2, acthcd->base + OTGIRQ);
+ otg_state = readb(acthcd->base + OTGSTATE);
+
+ printk("port_no:%d OTG IRQ, OTGSTATE: 0x%02X, USBIRQ:0x%02X\n",
+ port_no, otg_state,
+ readb(acthcd->base + USBIRQ));
+
+ if (otg_state == 0x4) {
+ return IRQ_HANDLED;
+ }
+
+ if ((otg_state == 0x02) && port_host_plug_detect[acthcd->id]) {
+ aotg_disable_irq(acthcd);
+ acthcd->hcd_exiting = 1;
+ aotg_hcd_abort_urb(acthcd);
+ aotg_dev_plugout_msg(acthcd->id);
+ return IRQ_HANDLED;
+ }
+ acthcd->put_aout_msg = 0;
+ if (otg_state == AOTG_STATE_A_HOST) {
+ /*if (acthcd->inserted != 0) {
+ acthcd->discon_happened = 1;
+ }*/
+
+ //if (acthcd->port & (USB_PORT_STAT_C_CONNECTION << 16)) {
+ // mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1000));
+ //} else {
+ if (acthcd->discon_happened == 1) {
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(500));
+ } else {
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1));
+ }
+ //}
+ } else {
+ acthcd->discon_happened = 1;
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1));
+ }
+ } else {
+ printk("port_no:%d error OTG irq! OTGIRQ: 0x%02X\n",
+ port_no, readb(acthcd->base + OTGIRQ));
+ }
+ break;
+ case UIV_SOF:
+ writeb(USBIRQ_SOF, acthcd->base + USBIRQ);
+#if 0
+ {
+ u16 index;
+ struct aotg_hcep *ep;
+
+ index = acthcd->frame;
+ ep = acthcd->periodic[index];
+ aotg_hcd_period_transfer(acthcd, ep);
+
+ acthcd->frame++;
+ acthcd->frame = acthcd->frame % PERIODIC_SIZE;
+ }
+#endif
+ break;
+ case UIV_USBRESET:
+ if (acthcd->port & (USB_PORT_STAT_POWER | USB_PORT_STAT_CONNECTION)) {
+ acthcd->speed = USB_SPEED_FULL; /*FS is the default */
+ acthcd->port |= (USB_PORT_STAT_C_RESET << 16);
+ acthcd->port &= ~USB_PORT_STAT_RESET;
+
+ /*clear usb reset irq */
+ writeb(USBIRQ_URES, acthcd->base + USBIRQ);
+
+ /*reset all ep-in */
+ aotg_hcep_reset(acthcd, USB_HCD_IN_MASK,
+ ENDPRST_FIFORST | ENDPRST_TOGRST);
+ /*reset all ep-out */
+ aotg_hcep_reset(acthcd, USB_HCD_OUT_MASK,
+ ENDPRST_FIFORST | ENDPRST_TOGRST);
+
+ acthcd->port |= USB_PORT_STAT_ENABLE;
+ acthcd->rhstate = AOTG_RH_ENABLE;
+ /*now root port is enabled fully */
+ if (readb(acthcd->base + USBCS) & USBCS_HFMODE) {
+ acthcd->speed = USB_SPEED_HIGH;
+ acthcd->port |= USB_PORT_STAT_HIGH_SPEED;
+ writeb(USBIRQ_HS, acthcd->base + USBIRQ);
+ HCD_DEBUG("%s: USB device is HS\n", __func__);
+ } else if (readb(acthcd->base + USBCS) & USBCS_LSMODE) {
+ acthcd->speed = USB_SPEED_LOW;
+ acthcd->port |= USB_PORT_STAT_LOW_SPEED;
+ HCD_DEBUG("%s: USB device is LS\n", __func__);
+ } else {
+ acthcd->speed = USB_SPEED_FULL;
+ HCD_DEBUG("%s: USB device is FS\n", __func__);
+ }
+
+ /*usb_clearbitsb(USBIEN_URES,USBIEN);*/ /*disable reset irq */
+ /*khu del for must enable USBIEN_URES again*/
+ writew(0xffff, acthcd->base + HCINxERRIRQ0);
+ writew(0xffff, acthcd->base + HCOUTxERRIRQ0);
+
+ writew(0xffff, acthcd->base + HCINxIRQ0);
+ writew(0xffff, acthcd->base + HCOUTxIRQ0);
+
+ writew(0xffff, acthcd->base + HCINxERRIEN0);
+ writew(0xffff, acthcd->base + HCOUTxERRIEN0);
+
+ HCD_DEBUG("%s: USB reset end\n", __func__);
+ }
+ break;
+
+ case UIV_EP0IN:
+ writew(1, acthcd->base + HCOUTxIRQ0); /*clear hcep0out irq */
+ handle_hcep0_out(acthcd);
+ break;
+ case UIV_EP0OUT:
+ writew(1, acthcd->base + HCINxIRQ0); /*clear hcep0in irq */
+ handle_hcep0_in(acthcd);
+ break;
+ case UIV_EP1IN:
+ ACT_HCD_DBG
+ writew(1<<1, acthcd->base + HCOUTxIRQ0); /*clear hcep1out irq */
+ break;
+ case UIV_EP1OUT:
+ ACT_HCD_DBG
+ writeb(1<<1, acthcd->base + HCINxIRQ0); /*clear hcep1in irq */
+ break;
+ case UIV_EP2IN:
+ ACT_HCD_DBG
+ writew(1<<2, acthcd->base + HCOUTxIRQ0); /*clear hcep2out irq */
+ break;
+ case UIV_EP2OUT:
+ ACT_HCD_DBG
+ writeb(1<<2, acthcd->base + HCINxIRQ0); /*clear hcep2in irq */
+ break;
+
+ default:
+ if ((irqvector >= UIV_HCOUT0ERR) && (irqvector <= UIV_HCOUT15ERR)) {
+ printk("irqvector:%d, 0x%x\n", irqvector, irqvector);
+ aotg_hcd_err_handle(acthcd, irqvector, (irqvector - UIV_HCOUT0ERR), 0);
+ break;
+ }
+ if ((irqvector >= UIV_HCIN0ERR) && (irqvector <= UIV_HCIN15ERR)) {
+ printk("irqvector:%d, 0x%x\n", irqvector, irqvector);
+ aotg_hcd_err_handle(acthcd, irqvector, (irqvector - UIV_HCIN0ERR), 1);
+ break;
+ }
+ dev_err(acthcd->dev, "error interrupt, pls check it! irqvector: 0x%02X\n", (u8)irqvector);
+ //spin_unlock(&acthcd->lock);
+ return IRQ_NONE;
+ }
+ }
+
+ //writeb(readb(acthcd->base + 0x518), acthcd->base + 0x518);
+
+
+ aotg_clear_all_overflow_irq(acthcd);
+ aotg_clear_all_shortpkt_irq(acthcd);
+ aotg_clear_all_zeropkt_irq(acthcd);
+ aotg_clear_all_hcoutdma_irq(acthcd);
+ aotg_ring_irq_handler(acthcd);
+
+ //ACT_HCD_DBG
+ //spin_unlock(&acthcd->lock);
+ //printk("%s,(0x%p : 0x%x)\n",__FUNCTION__, acthcd->base + HCINxDMAIRQ0,
+ //readw(acthcd->base + HCINxDMAIRQ0));
+ return IRQ_HANDLED;
+}
+
+static void aotg_hub_hotplug_timer(unsigned long data)
+{
+ struct aotg_hcd *acthcd = (struct aotg_hcd *)data;
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+ struct platform_device *pdev;
+ unsigned int port_no;
+ unsigned long flags;
+ int connect_changed = 0;
+
+ //if ((void *)data == (void *)NULL)
+ if (unlikely(IS_ERR_OR_NULL((void *)data))) {
+ ACT_HCD_DBG
+ return;
+ }
+ if (acthcd->hcd_exiting != 0) {
+ ACT_HCD_DBG
+ return;
+ }
+
+ //disable_irq_nosync(acthcd->uhc_irq);
+ disable_irq(acthcd->uhc_irq);
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+ if (acthcd->put_aout_msg != 0) {
+ pdev = to_platform_device(hcd->self.controller);
+ port_no = pdev->id & 0xff;
+ ACT_HCD_DBG
+ //update_driver_state(UPDATE_UDEVICE_OUT, port_no);
+ acthcd->put_aout_msg = 0;
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+ aotg_hub_notify_hcd_exit(0);
+ return;
+ }
+
+ if ((readb(acthcd->base + OTGSTATE) == AOTG_STATE_A_HOST) && (acthcd->discon_happened == 0)) {
+ if (!acthcd->inserted) {
+ acthcd->port |= (USB_PORT_STAT_C_CONNECTION << 16);
+ /*set port status bit,and indicate the present of a device */
+ acthcd->port |= USB_PORT_STAT_CONNECTION;
+ acthcd->rhstate = AOTG_RH_ATTACHED;
+ acthcd->inserted = 1;
+ connect_changed = 1;
+ }
+ } else {
+ if (acthcd->inserted) {
+ acthcd->port &= ~(USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_ENABLE |
+ USB_PORT_STAT_LOW_SPEED |
+ USB_PORT_STAT_HIGH_SPEED | USB_PORT_STAT_SUSPEND);
+ acthcd->port |= (USB_PORT_STAT_C_CONNECTION << 16);
+ acthcd->rhstate = AOTG_RH_NOATTACHED;
+ acthcd->inserted = 0;
+ connect_changed = 1;
+ }
+ if (acthcd->discon_happened == 1) {
+ acthcd->discon_happened = 0;
+
+ if (readb(acthcd->base + OTGSTATE) == AOTG_STATE_A_HOST) {
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1000));
+ }
+ }
+ }
+
+ dev_info(acthcd->dev, "<USB> %s connection changed: %d, acthcd->inserted: %d\n",
+ dev_name(hcd->self.controller), connect_changed, acthcd->inserted);
+ if (connect_changed) {
+ if (HC_IS_SUSPENDED(hcd->state)) {
+ usb_hcd_resume_root_hub(hcd);
+ }
+ ACT_HCD_DBG
+ //aotg_hcd_flush_queue(acthcd);
+ usb_hcd_poll_rh_status(hcd);
+ }
+
+ if ((acthcd->inserted == 0) && (connect_changed == 1) &&
+ (readb(acthcd->base + OTGSTATE) != AOTG_STATE_A_HOST)) {
+ acthcd->put_aout_msg = 1;
+ mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(2200));
+ }
+ acthcd->suspend_request_pend = 0;
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+ return;
+}
+
+static inline int aotg_print_ep_timeout(struct aotg_hcep *ep)
+{
+ int ret = 0;
+
+ if (ep == NULL) {
+ return ret;
+ }
+ if (ep->q != NULL) {
+ if (ep->q->timeout == 0)
+ return ret;
+
+ if (time_after(jiffies, ep->q->timeout)) {
+ ret = 1;
+ printk("ep->index:%x ep->mask:%x\n", ep->index, ep->mask);
+ printk("timeout:0x%x!\n", (unsigned int)ep->q->timeout);
+ ep->q->timeout = jiffies + HZ;
+ }
+ }
+ return ret;
+}
+
+static void aotg_check_trb_timer(unsigned long data)
+{
+ unsigned long flags;
+ struct aotg_hcep *ep;
+ int i;
+ struct aotg_hcd *acthcd = (struct aotg_hcd *)data;
+
+ if (unlikely(IS_ERR_OR_NULL((void *)data))) {
+ ACT_HCD_DBG
+ return;
+ }
+ if (acthcd->hcd_exiting != 0) {
+ ACT_HCD_DBG
+ return;
+ }
+
+ spin_lock_irqsave(&acthcd->lock, flags);
+ if (acthcd->check_trb_mutex) {
+ mod_timer(&acthcd->check_trb_timer, jiffies + msecs_to_jiffies(1));
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return;
+ }
+
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ if (ep && (ep->ring) && (ep->ring->type == PIPE_BULK))
+ handle_ring_dma_tx(acthcd,i);
+ }
+
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ if (ep && (ep->ring) && (ep->ring->type == PIPE_BULK))
+ handle_ring_dma_tx(acthcd,i | AOTG_DMA_OUT_PREFIX);
+ }
+
+ mod_timer(&acthcd->check_trb_timer, jiffies + msecs_to_jiffies(3));
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return;
+}
+
+static void aotg_hub_trans_wait_timer(unsigned long data)
+{
+ unsigned long flags;
+ struct aotg_hcep *ep;
+ int i, ret;
+ struct aotg_hcd *acthcd = (struct aotg_hcd *)data;
+
+ if (unlikely(IS_ERR_OR_NULL((void *)data))) {
+ ACT_HCD_DBG
+ return;
+ }
+ if (acthcd->hcd_exiting != 0) {
+ ACT_HCD_DBG
+ return;
+ }
+
+ //disable_irq_nosync(acthcd->uhc_irq);
+ disable_irq(acthcd->uhc_irq);
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+ ep = acthcd->active_ep0;
+ ret = aotg_print_ep_timeout(ep);
+
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ ret |= aotg_print_ep_timeout(ep);
+ }
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ if (ep == NULL) {
+ continue;
+ }
+ ret |= aotg_print_ep_timeout(ep);
+
+ if (ep->fifo_busy) {
+ if ((ep->fifo_busy > 80) && (ep->fifo_busy % 80 == 0)) {
+ printk("ep->fifo_busy:%d\n", ep->fifo_busy);
+ }
+ if (ret == 0) {
+ tasklet_hi_schedule(&acthcd->urb_tasklet);
+ break;
+ }
+ }
+ }
+
+ if (ret != 0) {
+ tasklet_hi_schedule(&acthcd->urb_tasklet);
+ }
+ mod_timer(&acthcd->trans_wait_timer, jiffies + msecs_to_jiffies(500));
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+ return;
+}
+//FIXME
+static inline int start_transfer(struct aotg_hcd *acthcd, struct aotg_queue *q, struct aotg_hcep *ep)
+{
+ struct urb *urb = q->urb;
+ int retval = 0;
+
+ ep->urb_enque_cnt++;
+ q->length = urb->transfer_buffer_length;
+
+ /* do with hub connected. */
+ if (ep->has_hub) {
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ writeb(usb_pipedevice(urb->pipe), ep->reg_hcep_dev_addr);
+ writeb(urb->dev->portnum, ep->reg_hcep_port);
+ } else {
+ writeb((0x80 | usb_pipedevice(urb->pipe)), ep->reg_hcep_dev_addr);
+ if (urb->dev->speed == USB_SPEED_LOW) {
+ writeb(0x80 | urb->dev->portnum, ep->reg_hcep_port);
+ } else {
+ writeb(urb->dev->portnum, ep->reg_hcep_port);
+ }
+ }
+ //writeb(0, ep->reg_hcep_splitcs);
+ } else {
+ writeb(usb_pipedevice(urb->pipe), ep->reg_hcep_dev_addr);
+ writeb(urb->dev->portnum, ep->reg_hcep_port);
+ }
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ q->timeout = jiffies + HZ/2;
+ retval = handle_setup_packet(acthcd, q);
+ break;
+
+ default:
+ printk(KERN_ERR"%s err, check it pls!\n", __FUNCTION__);
+ }
+
+ return retval;
+}
+
+#if 0
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_STILL_IMAGE 6
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_CDC_DATA 0x0a
+#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
+#define USB_CLASS_VIDEO 0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
+#define USB_CLASS_MISC 0xef
+#define USB_CLASS_APP_SPEC 0xfe
+#define USB_CLASS_VENDOR_SPEC 0xff
+#endif
+/*
+static void aotg_hcd_dump_isoc_packet(struct urb *urb)
+{
+ int i;
+ int number_of_packets;
+ u32 start_addr, addr;
+ unsigned int len;
+
+ number_of_packets = urb->number_of_packets;
+ start_addr = (u32)urb->transfer_dma;
+
+ printk("----dump iso_packets( addr--len )----\n");
+ for (i = 0; i < number_of_packets; i++) {
+ addr = start_addr + urb->iso_frame_desc[i].offset;
+ len = urb->iso_frame_desc[i].length;
+ printk("packet%d : %u, %d\n", i, addr, len);
+ }
+ return;
+}
+*/
+static struct aotg_hcep *aotg_hcep_alloc(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct aotg_hcep *ep = NULL;
+ int pipe = urb->pipe;
+ int is_out = usb_pipeout(pipe);
+ int type = usb_pipetype(pipe);
+ int i, retval = 0;
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ u8 think_time;
+
+ ep = kzalloc(sizeof *ep, GFP_ATOMIC);
+ if (NULL == ep) {
+ dev_err(acthcd->dev, "alloc ep failed\n");
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ ep->udev = usb_get_dev(urb->dev);
+ ep->epnum = usb_pipeendpoint(pipe);
+ ep->maxpacket = usb_maxpacket(ep->udev, urb->pipe, is_out);
+ ep->type = type;
+ ep->urb_enque_cnt = 0;
+ ep->urb_endque_cnt = 0;
+ ep->urb_stop_stran_cnt = 0;
+ ep->urb_unlinked_cnt = 0;
+#ifdef USBH_DEBUG
+ dev_info(acthcd->dev, "ep->epnum: %d, ep->maxpacket : %d, ep->type : %d\n", ep->epnum, ep->maxpacket, ep->type);
+#endif
+ ep->length = 0;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), is_out, 0);
+
+ if (urb->dev->parent) {
+ if (urb->dev->tt) {
+ /* calculate in ns. */
+ think_time = (urb->dev->tt->think_time / 666);
+ printk("think_time:%d\n", think_time);
+ if (think_time <= 0) {
+ think_time = 1;
+ } else if (think_time > 4) {
+ think_time = 4;
+ }
+ think_time = think_time * 20;
+ writeb(think_time, acthcd->base + HCTRAINTERVAL);
+ printk("think_time:0x%x\n", readb(acthcd->base + HCTRAINTERVAL));
+ //printk("urb->dev->tt->hub:%p \n", urb->dev->tt->hub);
+ }
+
+ if ((urb->dev->parent->parent) && (urb->dev->parent != hcd->self.root_hub)) {
+ ep->has_hub = 1;
+ ep->hub_addr = 0x7f & readb(acthcd->base + FNADDR);
+ } else {
+ ep->has_hub = 0;
+ }
+ }
+
+ switch (type) {
+ case PIPE_CONTROL:
+ ep->reg_hcep_dev_addr = acthcd->base + HCEP0ADDR;
+ ep->reg_hcep_port = acthcd->base + HCEP0PORT;
+ ep->reg_hcep_splitcs = acthcd->base + HCEP0SPILITCS;
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ if (acthcd->ep0[i] == NULL) {
+ ep->ep0_index = i;
+ acthcd->ep0[i] = ep;
+ break;
+ }
+ }
+ if (i == MAX_EP_NUM) {
+ ACT_HCD_ERR
+ }
+
+ ep->index = 0;
+ ep->mask = 0;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), 1, 0);
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), 0, 0);
+
+ if (acthcd->active_ep0 == NULL) {
+ //writeb(ep->epnum, acthcd->base + HCEP0CTRL);
+ //writeb((u8)ep->maxpacket, acthcd->base + HCIN0MAXPCK);
+ //writeb((u8)ep->maxpacket, acthcd->base + HCOUT0MAXPCK);
+ usb_setbitsw(1, acthcd->base + HCOUTxIEN0);
+ usb_setbitsw(1, acthcd->base + HCINxIEN0);
+ writew(1, acthcd->base + HCOUTxIRQ0);
+ writew(1, acthcd->base + HCINxIRQ0);
+
+ if (ep->has_hub) {
+ usb_setbitsb(0x80, acthcd->base + FNADDR);
+ } else {
+ writeb(usb_pipedevice(urb->pipe), acthcd->base + FNADDR);
+ }
+ dev_info(acthcd->dev, "device addr : 0x%08x\n", readb(acthcd->base + FNADDR));
+ } else {
+ ACT_HCD_ERR
+ }
+ break;
+
+ case PIPE_BULK:
+ retval = aotg_hcep_config(acthcd, ep, EPCON_TYPE_BULK, EPCON_BUF_SINGLE, is_out);
+ if (retval < 0) {
+ dev_err(acthcd->dev, "PIPE_BULK, retval: %d\n", retval);
+ kfree(ep);
+ goto exit;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ retval = aotg_hcep_config(acthcd, ep, EPCON_TYPE_INT, EPCON_BUF_SINGLE, is_out);
+ if (retval < 0) {
+ dev_err(acthcd->dev, "PIPE_INTERRUPT, retval: %d\n", retval);
+ kfree(ep);
+ goto exit;
+ }
+ ep->interval= urb->ep->desc.bInterval;
+ writeb(ep->interval, ep->reg_hcep_interval);
+ //printk("urb->interval: %d\n", urb->interval);
+ //printk("urb->ep->desc.bInterval: %d, reg_interval:0x%x\n",
+ // urb->ep->desc.bInterval, readb(ep->reg_hcep_interval));
+
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ retval = aotg_hcep_config_iso(acthcd, ep, EPCON_TYPE_ISO, EPCON_BUF_SINGLE, is_out);
+ ep->iso_packets = (urb->ep->desc.wMaxPacketSize >> 11) & 3;
+ ep->interval = urb->ep->desc.bInterval;
+ writeb(ep->interval, ep->reg_hcep_interval);
+ usb_setb(ep->iso_packets << 4, ep->reg_hcepcon);
+ printk("iso_packets:%d, bInterval:%d, urb_interval:%d, reg_con:0x%x\n",
+ ep->iso_packets, ep->interval, urb->interval, readb(ep->reg_hcepcon));
+ break;
+
+ default:
+ dev_err(acthcd->dev, "not support type, type: %d\n", type);
+ retval = -ENODEV;
+ kfree(ep);
+ goto exit;
+ }
+
+ if ((ep->udev->speed != USB_SPEED_HIGH) && ep->has_hub && (type == PIPE_INTERRUPT)) {
+ aotg_hcep_set_split_micro_frame(acthcd, ep);
+ }
+ ep->hep = urb->ep;
+ urb->ep->hcpriv = ep;
+ return ep;
+
+exit:
+ return NULL;
+}
+
+static int aotg_hub_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, unsigned mem_flags)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ struct aotg_queue *q=NULL;
+ unsigned long flags;
+ struct aotg_hcep *ep = NULL;
+ struct aotg_td *td, *next;
+ int pipe = urb->pipe;
+ int type = usb_pipetype(pipe);
+ int retval = 0;
+
+ if ((acthcd == NULL) || (act_hcd_ptr[acthcd->id] == NULL)) {
+ printk("aotg_hcd device had been removed...\n");
+ return -EIO;
+ }
+
+ if (acthcd->hcd_exiting != 0) {
+ dev_dbg(acthcd->dev, "aotg hcd exiting! type:%d\n", type);
+ return -ENODEV;
+ }
+
+ if (!(acthcd->port & USB_PORT_STAT_ENABLE)
+ || (acthcd->port & (USB_PORT_STAT_C_CONNECTION << 16))
+ || (acthcd->hcd_exiting != 0)
+ || (acthcd->inserted == 0)
+ || !HC_IS_RUNNING(hcd->state)) {
+ dev_err(acthcd->dev, "usbport dead or disable\n");
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+ ep = urb->ep->hcpriv;
+ if ((unlikely(!urb->ep->enabled)) || (likely(ep) && unlikely(ep->error_count > 3))) {
+ printk("ep had been stopped!\n");
+ //spin_unlock_irqrestore(&acthcd->lock, flags);
+ //ep = (struct aotg_hcep *)urb->ep->hcpriv;
+ retval = -ENOENT;
+ goto exit0;
+ }
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval) {
+ dev_err(acthcd->dev, "<QUEUE> usb_hcd_link_urb_to_ep error!! retval:0x%x\n",retval);
+ goto exit0;
+ }
+
+ if (likely(urb->ep->hcpriv)) {
+ ep = (struct aotg_hcep *)urb->ep->hcpriv;
+ } else {
+ ep = aotg_hcep_alloc(hcd, urb);
+ if (NULL == ep) {
+ dev_err(acthcd->dev, "<QUEUE> alloc ep failed\n");
+ retval = -ENOMEM;
+ goto exit1;
+ }
+ if (!usb_pipecontrol(pipe)) {
+ if (usb_pipeint(pipe))
+ ep->ring = aotg_alloc_ring(acthcd, ep, INTR_TRBS, GFP_ATOMIC);
+ else
+ ep->ring = aotg_alloc_ring(acthcd, ep, NUM_TRBS, GFP_ATOMIC);
+ if (!ep->ring) {
+ dev_err(acthcd->dev, "alloc td_ring failed\n");
+ retval = -ENOMEM;
+ goto exit1;
+ }
+ INIT_LIST_HEAD(&ep->queue_td_list);
+ INIT_LIST_HEAD(&ep->enring_td_list);
+ INIT_LIST_HEAD(&ep->dering_td_list);
+
+ //enable_overflow_irq(acthcd, ep);
+ }
+ urb->ep->hcpriv = ep;
+ if (type == PIPE_BULK)
+ mod_timer(&acthcd->check_trb_timer, jiffies + msecs_to_jiffies(100));
+ }
+
+ urb->hcpriv = hcd;
+
+ if (type == PIPE_CONTROL) {
+ q = aotg_hcd_get_queue(acthcd, urb, mem_flags);
+ if (unlikely(!q)) {
+ dev_err(acthcd->dev, "<QUEUE> alloc dma queue failed\n");
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return -ENOMEM;
+ }
+
+ q->ep = ep;
+ q->urb = urb;
+ list_add_tail(&q->enqueue_list, &acthcd->hcd_enqueue_list);
+ aotg_dbg_put_q(q, usb_pipeendpoint(q->urb->pipe), usb_pipein(q->urb->pipe),
+ q->urb->transfer_buffer_length);
+ } else if (type == PIPE_BULK) {
+ td = aotg_alloc_td(mem_flags);
+ if (!td) {
+ dev_err(acthcd->dev, "alloc td failed\n");
+ retval = -ENOMEM;
+ goto exit1;
+ }
+ td->urb = urb;
+
+ ep->urb_enque_cnt++;
+
+ if (list_empty(&ep->queue_td_list)) {
+ //ACT_HCD_DBG
+ retval = aotg_ring_enqueue_td(acthcd, ep->ring, td);
+ if (retval) {
+ list_add_tail(&td->queue_list, &ep->queue_td_list);
+ goto out;
+ }
+
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ ep->ring->enring_cnt++;
+ } else {
+ //ACT_HCD_DBG
+ list_add_tail(&td->queue_list, &ep->queue_td_list);
+ }
+
+ if (!list_empty(&ep->enring_td_list) &&
+ !is_ring_running(ep->ring)) {
+ //ACT_HCD_DBG
+ aotg_start_ring_transfer(acthcd, ep, urb);
+ }
+
+ } else if (type == PIPE_INTERRUPT) {
+ if (unlikely(ep->ring->intr_inited == 0)) {
+ retval = aotg_ring_enqueue_intr_td(acthcd, ep->ring, ep, urb, GFP_ATOMIC);
+ if (retval) {
+ printk("%s, intr urb enqueue err!\n", __FUNCTION__);
+ goto exit1;
+ }
+ ep->ring->intr_started = 0;
+ }
+ ep->urb_enque_cnt++;
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ if (td->urb) {
+ continue;
+ } else {
+ td->urb = urb;
+ break;
+ }
+ }
+
+ if (unlikely(ep->ring->enqueue_trb->hw_buf_len != urb->transfer_buffer_length)) {
+ //printk("ep:%p,hw_buf_len:%d, urb_len:%d .......\n",ep,ep->ring->enqueue_trb->hw_buf_len,urb->transfer_buffer_length);
+ aotg_intr_chg_buf_len(acthcd,ep->ring,urb->transfer_buffer_length);
+ printk("WARNNING:interrupt urb length changed......\n");
+ }
+
+ if (ep->ring->intr_started == 0) {
+ ep->ring->intr_started = 1;
+ //printk("%s, start ep%d intr transfer\n", __FUNCTION__, ep->index);
+ aotg_start_ring_transfer(acthcd, ep, urb);
+ }
+
+ if (!is_ring_running(ep->ring)) { /*trb overflow or no urb*/
+ if (ep->is_out) {
+ aotg_start_ring_transfer(acthcd, ep, urb);
+ } else {
+ //if (ep->ring->ring_stopped == 0) {
+ if (aotg_intr_get_finish_trb(ep->ring) == 0) {
+ ep->ring->ring_stopped = 0;
+ aotg_reorder_intr_td(ep);
+ ep_enable(ep);
+ mb();
+ writel(DMACTRL_DMACS,ep->ring->reg_dmactrl);
+ // printk("restart intr!\n");
+ } else ep->ring->ring_stopped = 1;
+ }
+ }
+ } else {// type == PIPE_ISOCHRONOUS
+ td = aotg_alloc_td(mem_flags);
+ if (!td) {
+ dev_err(acthcd->dev, "alloc td failed\n");
+ retval = -ENOMEM;
+ goto exit1;
+ }
+ td->urb = urb;
+
+ ep->urb_enque_cnt++;
+
+ if (list_empty(&ep->queue_td_list)) {
+ //ACT_HCD_DBG
+ retval = aotg_ring_enqueue_isoc_td(acthcd, ep->ring, td);
+ if (retval) {
+ list_add_tail(&td->queue_list, &ep->queue_td_list);
+ goto out;
+ }
+
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ ep->ring->enring_cnt++;
+ } else {
+ //ACT_HCD_DBG
+ list_add_tail(&td->queue_list, &ep->queue_td_list);
+ }
+
+ if (!list_empty(&ep->enring_td_list) && !is_ring_running(ep->ring)) {
+ if (ep->ring->dequeue_trb != ep->ring->first_trb)
+ aotg_reorder_iso_td(acthcd, ep->ring);
+ aotg_start_ring_transfer(acthcd, ep, urb);
+ }
+ }
+out:
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ tasklet_hi_schedule(&acthcd->urb_tasklet);
+ return retval;
+exit1:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+exit0:
+ /* FIXME */
+ printk("never goto here, need to just\n");
+ if (unlikely(retval < 0) && ep) {
+ if (type == PIPE_CONTROL) {
+ ACT_HCD_ERR
+ if (ep)
+ ep->q = NULL;
+ if(q)
+ aotg_hcd_release_queue(acthcd, q);
+ } else {
+ writel(DMACTRL_DMACC,ep->ring->reg_dmactrl);
+ ep_disable(ep);
+ /*if (!list_empty(&ep->queue_td_list)) {
+ list_for_each_entry_safe(td, next, &ep->queue_td_list, queue_list) {
+ list_del(&td->queue_list);
+ if (td)
+ kfree(td);
+ }
+ }
+
+ if (!list_empty(&ep->enring_td_list)) {
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ list_del(&td->enring_list);
+ if (td)
+ kfree(td);
+ }
+ }*/
+ }
+ }
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return retval;
+}
+
+static int aotg_hub_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ struct aotg_hcep *ep;
+ struct aotg_queue *q = NULL, *next, *tmp;
+ struct aotg_ring *ring;
+ struct aotg_td *td, *next_td;
+ unsigned long flags;
+ int retval = 0;
+
+ if ((acthcd == NULL) || (act_hcd_ptr[acthcd->id] == NULL)) {
+ printk("aotg_hcd device had been removed...\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+ retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (retval) {
+ printk("%s, retval:%d, urb not submitted or unlinked\n", __FUNCTION__,
+ retval);
+ goto dequeue_out;
+ }
+
+ ep = (struct aotg_hcep *)urb->ep->hcpriv;
+ if (ep == NULL) {
+ ACT_HCD_ERR
+ retval = -EINVAL;
+ goto dequeue_out;
+ }
+
+ if (!usb_pipecontrol(urb->pipe)) {
+// ACT_HCD_DBG
+ ep->urb_unlinked_cnt++;
+ ring = ep->ring;
+
+ if (usb_pipeint(urb->pipe)) {
+ list_for_each_entry_safe(td, next_td, &ep->enring_td_list, enring_list) {
+ if (urb == td->urb) {
+ retval = aotg_ring_dequeue_intr_td(acthcd, ep, ring, td);
+ goto de_bulk;
+ }
+ }
+ printk("%s, intr dequeue err\n", __FUNCTION__);
+ }
+
+ list_for_each_entry_safe(td, next_td, &ep->queue_td_list, queue_list) {
+ if (urb == td->urb) {
+ retval = aotg_ring_dequeue_td(acthcd, ring, td, TD_IN_QUEUE);
+ goto de_bulk;
+ }
+ }
+
+ list_for_each_entry_safe(td, next_td, &ep->enring_td_list, enring_list) {
+ mb();
+ if (urb == td->urb) {
+ retval = aotg_ring_dequeue_td(acthcd, ring, td, TD_IN_RING);
+ ep->urb_stop_stran_cnt++;
+ goto de_bulk;
+ }
+ }
+
+ //pr_err("%s err, never be here, pls check it!\n", __func__);
+ retval = -EINVAL;
+ goto dequeue_out;
+de_bulk:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&acthcd->lock);
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return retval;
+ }
+
+ q = ep->q;
+
+ /* ep->mask currently equal to q->dma_no. */
+ if (q && (q->urb == urb)) {
+ writeb(EP0CS_HCSET,acthcd->base + EP0CS);
+ //dev_info(acthcd->dev,
+ //"current dequeue -- ep->index: %d, dir : %s, type: %d, transfer_buffer_length: %d, actual_length:%d\n",
+ //ep->index, usb_pipeout(urb->pipe)?"out":"in", usb_pipetype(urb->pipe),
+ //urb->transfer_buffer_length, urb->actual_length);
+
+ /* maybe finished in tasklet_finish_request. */
+ if (!list_empty(&q->finished_list)) {
+ if (q->finished_list.next != LIST_POISON1) {
+ list_del(&q->finished_list);
+ }
+ }
+
+ if (q->is_xfer_start) {
+ ep->urb_stop_stran_cnt++;
+ q->is_xfer_start = 0;
+ }
+ } else {
+ q = NULL;
+ list_for_each_entry_safe(tmp, next, &acthcd->hcd_enqueue_list, enqueue_list) {
+ if (tmp->urb == urb) {
+ list_del(&tmp->enqueue_list);
+ q = tmp;
+ ep = q->ep;
+ if (ep->q == q) {
+ ACT_HCD_DBG
+ }
+ break;
+ }
+ }
+ }
+
+ if (likely(q)) {
+ //ACT_HCD_DBG
+ //if (ep->q == q)
+ //ep->q = NULL;
+ q->status = status;
+ list_add_tail(&q->dequeue_list, &acthcd->hcd_dequeue_list);
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ tasklet_schedule(&acthcd->urb_tasklet);
+ return retval;
+ } else {
+ ACT_HCD_ERR
+ printk("dequeue's urb not find in enqueue_list!\n");
+ }
+
+dequeue_out:
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return retval;
+}
+
+void urb_tasklet_func(unsigned long data)
+{
+ struct aotg_hcd *acthcd = (struct aotg_hcd *)data;
+ struct aotg_queue *q, *next;
+ struct aotg_hcep *ep;
+ struct urb *urb;
+ struct aotg_ring *ring;
+ struct aotg_td *td;
+ unsigned long flags;
+ int status;
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+ int cnt = 0;
+ //static struct aotg_hcep * hcin_ep = NULL;
+
+ //spin_lock(&acthcd->tasklet_lock);
+
+ do {
+ status = (int)spin_is_locked(&acthcd->tasklet_lock);
+ if (status) {
+ acthcd->tasklet_retry = 1;
+ printk("locked, urb retry later!\n");
+ return;
+ }
+ cnt++;
+ /* sometimes tasklet_lock is unlocked, but spin_trylock still will be failed,
+ * maybe caused by the instruction of strexeq in spin_trylock, it will return failed
+ * if other cpu is accessing the nearby address of &acthcd->tasklet_lock.
+ */
+ status = spin_trylock(&acthcd->tasklet_lock);
+ if ((!status) && (cnt > 10)) {
+ acthcd->tasklet_retry = 1;
+ printk("urb retry later!\n");
+ return;
+ }
+ } while (status == 0);
+
+ disable_irq(acthcd->uhc_irq);
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+ for (cnt=1; cnt<MAX_EP_NUM; cnt++) {
+ ep = acthcd->inep[cnt];
+ if (ep && (ep->type == PIPE_INTERRUPT)) {
+ ring = ep->ring;
+ if (ring->ring_stopped) {
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td)
+ continue;
+ urb = td->urb;
+ if (!urb)
+ continue;
+ intr_finish_td(acthcd, ring, td);
+ }
+ }
+ }
+ /* do dequeue task. */
+DO_DEQUEUE_TASK:
+ urb = NULL;
+ list_for_each_entry_safe(q, next, &acthcd->hcd_dequeue_list, dequeue_list) {
+ if (q->status < 0) {
+ urb = q->urb;
+ ep = q->ep;
+ if (ep) {
+ ep->urb_unlinked_cnt++;
+ //ep->q = NULL;
+ }
+ list_del(&q->dequeue_list);
+ status = q->status;
+ tasklet_finish_request(acthcd, q, status);
+ hcd = bus_to_hcd(urb->dev->bus);
+ break;
+ } else {
+ ACT_HCD_ERR
+ }
+ }
+ if (urb != NULL) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ /* in usb_hcd_giveback_urb, complete function may call new urb_enqueue. */
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock_irqsave(&acthcd->lock, flags);
+ goto DO_DEQUEUE_TASK;
+ }
+
+ /* do finished task. */
+DO_FINISH_TASK:
+ urb = NULL;
+ list_for_each_entry_safe(q, next, &acthcd->hcd_finished_list, finished_list) {
+ if (q->finished_list.next != LIST_POISON1) {
+ list_del(&q->finished_list);
+ } else {
+ ACT_HCD_ERR
+ break;
+ }
+ status = q->status;
+ tasklet_finish_request(acthcd, q, status);
+
+ hcd = aotg_to_hcd(acthcd);
+ urb = q->urb;
+ ep = q->ep;
+ if (urb != NULL) {
+ break;
+ }
+ }
+ if (urb != NULL) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+
+ /* in usb_hcd_giveback_urb, complete function may call new urb_enqueue. */
+ usb_hcd_giveback_urb(hcd, urb, status);
+
+ spin_lock_irqsave(&acthcd->lock, flags);
+ goto DO_FINISH_TASK;
+ }
+
+//DO_ENQUEUE_TASK:
+ /* do enqueue task. */
+ /* start transfer directly, don't care setup appearing in bulkout. */
+ list_for_each_entry_safe(q, next, &acthcd->hcd_enqueue_list, enqueue_list) {
+ urb = q->urb;
+ ep = q->ep;
+
+ /* deal with controll request. */
+ if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+ if ((acthcd->active_ep0 != NULL) && (acthcd->active_ep0->q != NULL)) {
+ acthcd->ep0_block_cnt++;
+ //ACT_HCD_DBG
+ if ((acthcd->ep0_block_cnt % 10) == 0) {
+ ACT_HCD_DBG
+ printk("cnt:%d\n", acthcd->ep0_block_cnt);
+ acthcd->ep0_block_cnt = 0;
+ //aotg_hub_urb_dequeue(hcd, acthcd->active_ep0->q->urb, -ETIMEDOUT);
+ }
+ continue;
+ } else {
+ acthcd->ep0_block_cnt = 0;
+ goto BEGIN_START_TANSFER;
+ }
+ }
+
+ /* deal with new bulk in request. */
+ if ((usb_pipetype(urb->pipe) == PIPE_BULK) && (usb_pipein(urb->pipe))) {
+ if (ep->q != NULL) {
+ continue;
+ }
+ goto BEGIN_START_TANSFER;
+ }
+
+ /* deal with bulk out request. */
+ if ((usb_pipetype(urb->pipe) == PIPE_BULK) && (usb_pipeout(urb->pipe))) {
+ if (ep->q != NULL) {
+ continue;
+ }
+ if ((EPCS_BUSY & readb(ep->reg_hcepcs)) != 0) {
+ ep->fifo_busy++;
+ mod_timer(&acthcd->trans_wait_timer, jiffies + msecs_to_jiffies(3));
+ continue;
+ } else {
+ ep->fifo_busy = 0;
+ }
+ goto BEGIN_START_TANSFER;
+ }
+
+BEGIN_START_TANSFER:
+ list_del(&q->enqueue_list);
+ status = start_transfer(acthcd, q, ep);
+
+ if (unlikely(status < 0)) {
+ ACT_HCD_ERR
+ hcd = bus_to_hcd(urb->dev->bus);
+ aotg_hcd_release_queue(acthcd, q);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock_irqsave(&acthcd->lock, flags);
+ }
+ //spin_unlock_irqrestore(&acthcd->lock, flags);
+ //enable_irq(acthcd->uhc_irq);
+ //spin_unlock(&acthcd->tasklet_lock);
+ //return;
+ }
+
+ if (acthcd->tasklet_retry != 0) {
+ acthcd->tasklet_retry = 0;
+ goto DO_DEQUEUE_TASK;
+ }
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+ spin_unlock(&acthcd->tasklet_lock);
+ return;
+}
+
+static void aotg_hub_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+{
+ int i;
+ int index;
+ unsigned long flags;
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ struct aotg_hcep *ep = hep->hcpriv;
+
+ if (!ep)
+ return;
+
+ /* assume we'd just wait for the irq */
+// for (i = 0; i < 100 && !list_empty(&hep->urb_list); i++)
+// msleep(3);
+
+ if (in_irq()) {
+ disable_irq_nosync(acthcd->uhc_irq);
+ } else {
+ disable_irq(acthcd->uhc_irq);
+ }
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+// usb_put_dev(ep->udev);
+ index = ep->index;
+ if (index == 0) {
+ acthcd->ep0[ep->ep0_index] = NULL;
+ if (acthcd->active_ep0 == ep) {
+ acthcd->active_ep0 = NULL;
+ }
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ if (acthcd->ep0[i] != NULL) {
+ break;
+ }
+ }
+ if (i == MAX_EP_NUM) {
+ usb_clearbitsw(1, acthcd->base + HCOUTxIEN0);
+ usb_clearbitsw(1, acthcd->base + HCINxIEN0);
+ writew(1, acthcd->base + HCOUTxIRQ0);
+ writew(1, acthcd->base + HCINxIRQ0);
+ }
+ } else {
+ ep_disable(ep);
+ if (ep->mask & USB_HCD_OUT_MASK) {
+ acthcd->outep[index] = NULL;
+ } else {
+ acthcd->inep[index] = NULL;
+ }
+// pio_irq_disable(acthcd, ep->mask);
+// pio_irq_clear(acthcd, ep->mask);
+ release_fifo_addr(acthcd, ep->fifo_addr);
+ }
+
+ hep->hcpriv = NULL;
+
+ if(ep->ring){
+ printk("%s\n", __FUNCTION__);
+
+ aotg_stop_ring(ep->ring);
+ if (ep->ring->type == PIPE_INTERRUPT) {
+ printk("%s, ep%d dma buf free\n", __FUNCTION__, ep->index);
+ aotg_intr_dma_buf_free(acthcd, ep->ring);
+ }
+
+ aotg_free_ring(acthcd, ep->ring);
+ }
+
+ dev_info(acthcd->dev, "<EP DISABLE> ep%d index %d from ep [%s]\n",
+ ep->epnum, index,
+ ep->mask & USB_HCD_OUT_MASK ? "out":"in");
+
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+ kfree(ep);
+ return;
+}
+
+static int aotg_hcd_get_frame(struct usb_hcd *hcd)
+{
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+ return tv.tv_usec / 1000;
+}
+
+static int aotg_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct aotg_hcd *acthcd;
+ unsigned long flags;
+ int retval = 0;
+
+ acthcd = hcd_to_aotg(hcd);
+ local_irq_save(flags);
+ if (!HC_IS_RUNNING(hcd->state))
+ goto done;
+
+ if ((acthcd->port & AOTG_PORT_C_MASK) != 0) {
+ *buf = (1 << 1);
+ HUB_DEBUG("<HUB STATUS>port status %08x has changes\n", acthcd->port);
+ retval = 1;
+ }
+done:
+ local_irq_restore(flags);
+ return retval;
+}
+
+static __inline__ void port_reset(struct aotg_hcd *acthcd)
+{
+ HCD_DEBUG("<USB> port reset\n");
+ writeb(0x1<<6 | 0x1<<5, acthcd->base + HCPORTCTRL); /*portrst & 55ms */
+}
+
+static void port_power(struct aotg_hcd *acthcd, int is_on)
+{
+ struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+ //struct device *dev = hcd->self.controller;
+
+ /* hub is inactive unless the port is powered */
+ if (is_on) {
+ hcd->self.controller->power.power_state = PMSG_ON;
+ dev_dbg(acthcd->dev, "<USB> power on\n");
+ } else {
+ hcd->self.controller->power.power_state = PMSG_SUSPEND;
+ dev_dbg(acthcd->dev, "<USB> power off\n");
+ }
+}
+
+static void port_suspend(struct aotg_hcd *acthcd)
+{
+ usb_clearbitsb(OTGCTRL_BUSREQ, acthcd->base + OTGCTRL);
+}
+
+static void port_resume(struct aotg_hcd *acthcd)
+{
+ usb_setbitsb(OTGCTRL_BUSREQ, acthcd->base + OTGCTRL);
+}
+
+static int aotg_hcd_start(struct usb_hcd *hcd)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ //struct device *dev = hcd->self.controller;
+ //struct aotg_plat_data *data = dev->platform_data;
+ int retval = 0;
+ unsigned long flags;
+
+ dev_info(acthcd->dev, "<HCD> start\n");
+
+ local_irq_save(flags);
+ hcd->state = HC_STATE_RUNNING;
+ hcd->uses_new_polling = 1;
+ local_irq_restore(flags);
+
+ return retval;
+
+}
+
+static void aotg_hcd_stop(struct usb_hcd *hcd)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ //struct device *dev = hcd->self.controller;
+ //struct aotg_plat_data *data = dev->platform_data;
+ unsigned long flags;
+
+ dev_info(acthcd->dev, "<HCD> stop\n");
+
+ local_irq_save(flags);
+ hcd->state = HC_STATE_HALT;
+ acthcd->port = 0;
+ acthcd->rhstate = AOTG_RH_POWEROFF;
+ local_irq_restore(flags);
+ return;
+}
+
+#ifdef CONFIG_PM
+
+static int aotg_hub_suspend(struct usb_hcd *hcd)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+
+ if ((hcd == NULL) || (acthcd == NULL)) {
+ ACT_HCD_ERR
+ return 0;
+ }
+ acthcd->suspend_request_pend = 1;
+ port_suspend(acthcd);
+
+ return 0;
+}
+
+static int
+aotg_hub_resume(struct usb_hcd *hcd)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+
+ port_resume(acthcd);
+
+ return 0;
+}
+
+#else
+
+#define aotg_hub_suspend NULL
+#define aotg_hub_resume NULL
+
+#endif
+
+static __inline__ void aotg_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+ memset(desc, 0, sizeof *desc);
+ desc->bDescriptorType = 0x29;
+ desc->bDescLength = 9;
+ desc->wHubCharacteristics = (__force __u16)
+ (__constant_cpu_to_le16(0x0001));
+ desc->bNbrPorts = 1;
+ //desc->bitmap[0] = 1 << 1;
+ //desc->bitmap[1] = 0xff;
+}
+
+static int aotg_hub_control(struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ unsigned long flags;
+ int retval = 0;
+
+ if (in_irq()) {
+ disable_irq_nosync(acthcd->uhc_irq);
+ } else {
+ disable_irq(acthcd->uhc_irq);
+ }
+ spin_lock_irqsave(&acthcd->lock, flags);
+
+ if (!HC_IS_RUNNING(hcd->state)) {
+ dev_err(acthcd->dev, "<HUB_CONTROL> hc state is not HC_STATE_RUNNING\n");
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+ return -EPERM;
+ }
+ HUB_DEBUG("<HUB_CONTROL> typeReq:%x, wValue:%04x, wIndex: %04x, wLength: %04x\n", typeReq, wValue, wIndex, wLength);
+
+ switch (typeReq) {
+ case ClearHubFeature:
+ HUB_DEBUG("<HUB_CONTROL> ClearHubFeature, wValue:%04x, wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+ break;
+ case ClearPortFeature:
+ HUB_DEBUG("<HUB_CONTROL> ClearPortFeature, wValue:%04x, wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+
+ if (wIndex != 1 || wLength != 0)
+ goto hub_error;
+ HUB_DEBUG("<HUB_CONTROL> before clear operation,the port status is %08x\n", acthcd->port);
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ acthcd->port &= ~(USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_LOW_SPEED
+ | USB_PORT_STAT_HIGH_SPEED);
+ acthcd->rhstate = AOTG_RH_DISABLE;
+ if (acthcd->port & USB_PORT_STAT_POWER)
+ port_power(acthcd, 0);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ HUB_DEBUG("<HUB_CONTROL>clear suspend feathure\n");
+ //port_resume(acthcd);
+ acthcd->port &= ~(1 << wValue);
+ break;
+ case USB_PORT_FEAT_POWER:
+ acthcd->port = 0;
+ acthcd->rhstate = AOTG_RH_POWEROFF;
+ port_power(acthcd, 0);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_SUSPEND:
+ case USB_PORT_FEAT_C_CONNECTION:
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_RESET:
+ acthcd->port &= ~(1 << wValue);
+ break;
+ default:
+ goto hub_error;
+ }
+ HUB_DEBUG("<HUB_CONTROL> after clear operation,the port status is %08x\n", acthcd->port);
+ break;
+ case GetHubDescriptor:
+ HUB_DEBUG("<HUB_CONTROL> GetHubDescriptor, wValue:%04x, wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+ aotg_hub_descriptor((struct usb_hub_descriptor *)buf);
+ break;
+ case GetHubStatus:
+ HUB_DEBUG("<HUB_CONTROL> GetHubStatus, wValue:%04x, wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+
+ *(__le32 *) buf = __constant_cpu_to_le32(0);
+ break;
+ case GetPortStatus:
+ HUB_DEBUG("<HUB_CONTROL> GetPortStatus, wValue:%04x, wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+
+ if (wIndex != 1)
+ goto hub_error;
+ *(__le32 *) buf = cpu_to_le32(acthcd->port);
+ HUB_DEBUG("<HUB_CONTROL> the port status is %08x\n ",
+ acthcd->port);
+ break;
+ case SetHubFeature:
+ HUB_DEBUG("<HUB_CONTROL> SetHubFeature, wValue: %04x,wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+ goto hub_error;
+ break;
+ case SetPortFeature:
+ HUB_DEBUG("<HUB_CONTROL> SetPortFeature, wValue:%04x, wIndex: %04x, wLength: %04x\n",
+ wValue, wIndex, wLength);
+
+ switch (wValue) {
+ case USB_PORT_FEAT_POWER:
+ if (unlikely(acthcd->port & USB_PORT_STAT_POWER))
+ break;
+ acthcd->port |= (1 << wValue);
+ acthcd->rhstate = AOTG_RH_POWERED;
+ port_power(acthcd, 1);
+ break;
+ case USB_PORT_FEAT_RESET:
+ port_reset(acthcd);
+ /* if it's already enabled, disable */
+ acthcd->port &= ~(USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_LOW_SPEED
+ | USB_PORT_STAT_HIGH_SPEED);
+ acthcd->port |= (1 << wValue);
+ mdelay(2);
+ acthcd->rhstate = AOTG_RH_RESET;
+ usb_setbitsb(USBIEN_URES, acthcd->base + USBIEN);
+ /*enable reset irq */
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ /*acthcd->port |= USB_PORT_FEAT_SUSPEND;*/
+ acthcd->port |= (1 << wValue);
+ acthcd->rhstate = AOTG_RH_SUSPEND;
+ //port_suspend(acthcd);
+ break;
+ default:
+ if (acthcd->port & USB_PORT_STAT_POWER)
+ acthcd->port |= (1 << wValue);
+ }
+ break;
+ default:
+hub_error:
+ retval = -EPIPE;
+ dev_err(acthcd->dev, "<HUB_CONTROL> hub control error\n");
+ break;
+
+ }
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ enable_irq(acthcd->uhc_irq);
+
+ return retval;
+}
+
+static void aotg_DD_set_phy(void __iomem *base, u8 reg, u8 value)
+{
+ u8 addrlow, addrhigh;
+ int time = 1;
+
+ addrlow = reg & 0x0f;
+ addrhigh = (reg >> 4) & 0x0f;
+
+ /*write vstatus: */
+ writeb(value, base + VDSTATUS);
+ mb();
+
+ /*write vcontrol: */
+ writeb(addrlow | 0x10, base + VDCTRL);
+ udelay(time); //the vload period should > 33.3ns
+ writeb(addrlow & 0x0f, base + VDCTRL);
+ udelay(time);
+ mb();
+ writeb(addrlow | 0x10, base + VDCTRL);
+ udelay(time);
+ writeb(addrhigh | 0x10, base + VDCTRL);
+ udelay(time);
+ writeb(addrhigh & 0x0f, base + VDCTRL);
+ udelay(time);
+ writeb(addrhigh | 0x10, base + VDCTRL);
+ udelay(time);
+ return;
+}
+
+static void aotg_DD_set_phy_init(struct aotg_hcd *acthcd)
+{
+ int slew_rate,tx_bias;
+ if (acthcd->id) {
+ slew_rate = aotg1_slew_rate;
+ tx_bias = aotg1_tx_bias;
+ } else {
+ slew_rate = aotg0_slew_rate;
+ tx_bias = aotg0_tx_bias;
+ }
+
+ aotg_DD_set_phy(acthcd->base, 0xf4,(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0));
+ aotg_DD_set_phy(acthcd->base, 0xe0,(1<<5) |(1<<4)|(0<<3)|(1<<2)|(1<<0));
+
+ aotg_DD_set_phy(acthcd->base, 0xf4,(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0));
+ if((slew_rate >=0) && (slew_rate <= 7))
+ aotg_DD_set_phy(acthcd->base, 0xe1,(slew_rate<<5)|(0<<4)|(1<<3)|(1<<2)|(3<<0));
+ else
+ aotg_DD_set_phy(acthcd->base, 0xe1,(3<<5) |(0<<4)|(1<<3)|(1<<2)|(3<<0));
+
+ aotg_DD_set_phy(acthcd->base, 0xf4,(1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0));
+ aotg_DD_set_phy(acthcd->base, 0xe6,(1<<7) |(4<<4)|(1<<3)|(0<<2)|(3<<0));
+
+ aotg_DD_set_phy(acthcd->base, 0xf4,(1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0));
+ //aotg_DD_set_phy(acthcd->base, 0xe7,(7<<4)|(0<<1)|(1<<0));
+ aotg_DD_set_phy(acthcd->base, 0xe7,(9<<4)|(0<<1)|(1<<0));
+
+ aotg_DD_set_phy(acthcd->base, 0xf4,(1<<7) |(1<<5)|(1<<4)|(2<<2)|(3<<0));
+ aotg_DD_set_phy(acthcd->base, 0xe0,(1<<5) |(1<<4)|(0<<3)|(0<<2)|(1<<0));
+
+
+ aotg_DD_set_phy(acthcd->base, 0xf4,(1<<7) |(0<<5)|(1<<4)|(2<<2)|(3<<0));
+ if((tx_bias >=0) && (tx_bias <= 15))
+ aotg_DD_set_phy(acthcd->base, 0xe4, (0xc<<4)|(tx_bias<<0));
+ else
+ aotg_DD_set_phy(acthcd->base, 0xe4, (0xc<<4)|(4<<0));
+
+ aotg_DD_set_phy(acthcd->base, 0xf0,(1<<7) |(1<<6) |(1<<5)|(1<<4)|(1<<3)|(1<<2)|(0<<1)|(0<<0));
+ return;
+}
+
+static void aotg_hcd_clk_enable(struct aotg_hcd *acthcd, int is_enable)
+{
+ struct aotg_plat_data *data = acthcd->port_specific;
+#if 0
+ __u32 tmp;
+ struct clk *dev_pll = NULL;
+ struct clk *usb_pll = NULL;
+
+ if (is_enable) {
+ dev_pll = clk_get_sys(CLK_NAME_DEVPLL, NULL); /*\B8\F9\BE\DDclk_name\BB\F1ȡclk\BDṹ\CC\E5*/
+ if (IS_ERR(dev_pll)) {
+ printk("get dev_pll err!\n");
+ return;
+ }
+
+ usb_pll = clk_get_sys(CLK_NAME_USBPLL, NULL); /*\B8\F9\BE\DDclk_name\BB\F1ȡclk\BDṹ\CC\E5*/
+ if (IS_ERR(usb_pll)) {
+ ACT_HCD_ERR
+ }
+ clk_enable(dev_pll); /*enable clk*/
+ //clk_enable(usb_pll); /*enable clk*/
+
+ usb_setbitsl(data->usbpll_bits, data->usbpll);
+ tmp = readl(data->usbpll);
+
+ hcd_2clk_bits_en |= 0x1 << acthcd->id;
+
+ } else {
+ if (!hcd_2clk_bits_en) {
+ return;
+ }
+ hcd_2clk_bits_en &= ~(0x1 << acthcd->id);
+ dev_pll = clk_get_sys(CLK_NAME_DEVPLL, NULL); /*\B8\F9\BE\DDclk_name\BB\F1ȡclk\BDṹ\CC\E5*/
+ if (IS_ERR(dev_pll)) {
+ printk("get dev_pll err!\n");
+ return;
+ }
+
+ usb_pll = clk_get_sys(CLK_NAME_USBPLL, NULL); /*\B8\F9\BE\DDclk_name\BB\F1ȡclk\BDṹ\CC\E5*/
+
+ if (IS_ERR(usb_pll)) {
+ ACT_HCD_ERR;
+ }
+ usb_clearbitsl(data->usbpll_bits, data->usbpll);
+
+ clk_disable(dev_pll); /*disable clk*/
+ //clk_disable(usb_pll); /*disable clk*/
+ }
+#endif
+
+ if (is_enable) {
+ usb_setbitsl(data->usbpll_bits, data->usbpll);
+ } else {
+ usb_clearbitsl(data->usbpll_bits, data->usbpll);
+ }
+
+ return;
+}
+
+static int aotg_hcd_controller_reset(struct aotg_hcd *acthcd)
+{
+ struct aotg_plat_data *data = acthcd->port_specific;
+ int i = 0;
+
+ usb_clearbitsl(data->devrst_bits, data->devrst);
+ udelay(1);
+ usb_setbitsl(data->devrst_bits, data->devrst);
+
+ while (((readb(acthcd->base + USBERESET) & USBERES_USBRESET) != 0) && (i < 300000)) {
+ i++;
+ udelay(1);
+ }
+
+ if (!(readb(acthcd->base + USBERESET) & USBERES_USBRESET)) {
+ dev_info(acthcd->dev, "usb reset OK: %x.\n", readb(acthcd->base + USBERESET));
+ } else {
+ dev_err(acthcd->dev, "usb reset ERROR: %x.\n", readb(acthcd->base + USBERESET));
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static void aotg_hcd_hardware_init(struct aotg_hcd *acthcd)
+{
+ u8 val8;
+ unsigned long flags;
+ struct aotg_plat_data *data = acthcd->port_specific;
+
+ owl_powergate_power_on(acthcd->id == 0 ?
+ OWL_POWERGATE_USB2_0 : OWL_POWERGATE_USB2_1);
+ //module_clk_enable(MOD_ID_USB2);
+ module_clk_enable(acthcd->id == 0 ?
+ MOD_ID_USB2_0 : MOD_ID_USB2_1);
+ aotg_hcd_clk_enable(acthcd, 1);
+
+ local_irq_save(flags);
+ aotg_hcd_controller_reset(acthcd);
+ /* fpga : new DMA mode */
+ writel(0x1, acthcd->base + HCDMABCKDOOR);
+
+ /* USBH0_ECS: set soft vbus and id,
+ * bit29 -- host disconnect detection enable;
+ * bit28 -- connect and disconnect enable.
+ * bit27 -- softid value;
+ * bit26 -- softid enalbe
+ * bit25 -- softvbus value.
+ * bit24 -- softvbus enable.
+ * bit13:14 -- VBUS detection threshold
+ * bit7 -- PLL LDO enable
+ * bit 4:6 -- vbus threshold 3.43~3.57. */
+ writel((0x37 << 24) | (0x10 << 13) | (0xb << 4), data->usbecs);
+ udelay(100);
+ aotg_DD_set_phy_init(acthcd);
+
+ /***** TA_BCON_COUNT *****/
+ writeb(0x0, acthcd->base + TA_BCON_COUNT); //110ms
+ /****HNP setting ********/
+ //Writeb(acthcd->base + USBH_BKDOOR, (Readb(USBH_BKDOOR)| 0x08));
+ //Writeb(acthcd->base + USBH_BKDOOR, (Readb(USBH_BKDOOR)| 0x04)); //set the tx_pre
+
+ /*set TA_AIDL_BDIS timeout never generate */
+ writeb(0xff, acthcd->base + TAAIDLBDIS);
+ /*set TA_WAIT_BCON timeout never generate */
+ writeb(0xff, acthcd->base + TAWAITBCON);
+ /*set TB_VBUS_DISCHARGE_PLS timeout value = 40.68ms*/
+ writeb(0x28, acthcd->base + TBVBUSDISPLS);
+ /*set TA_WAIT_BCON timeout never generate*/
+ usb_setbitsb(1 << 7, acthcd->base + TAWAITBCON);
+
+ writew(0x1000, acthcd->base + VBUSDBCTIMERL);
+// writeb(0x40, acthcd->base + USBCS);
+
+ val8 = readb(acthcd->base + BKDOOR);
+ if (data && data->no_hs) {
+ val8 |= (1 << 7);
+ } else {
+ val8 &= ~(1 << 7);
+ }
+ if (is_ls_device[acthcd->id])
+ val8 |= (1<<7);
+ writeb(val8, acthcd->base + BKDOOR);
+ mb();
+
+ local_irq_restore(flags);
+ //writeb(0xff, acthcd->base + HCTRAINTERVAL);
+
+ return;
+}
+
+static int aotg_hcd_init(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ int retval = 0;
+ int i;
+
+ /*init software state */
+ spin_lock_init(&acthcd->lock);
+ spin_lock_init(&acthcd->tasklet_lock);
+ acthcd->tasklet_retry = 0;
+ //acthcd->dev = &pdev->dev;
+ acthcd->port_specific = pdev->dev.platform_data;
+ acthcd->port = 0;
+ acthcd->rhstate = AOTG_RH_POWEROFF;
+ acthcd->inserted = 0;
+
+ INIT_LIST_HEAD(&acthcd->hcd_enqueue_list);
+ INIT_LIST_HEAD(&acthcd->hcd_dequeue_list);
+ INIT_LIST_HEAD(&acthcd->hcd_finished_list);
+ tasklet_init(&acthcd->urb_tasklet, urb_tasklet_func, (unsigned long)acthcd);
+
+#if 0
+ for (i = 0; i < PERIODIC_SIZE; i++) {
+ acthcd->load[i] = 0;
+ acthcd->periodic[i] = NULL;
+ }
+#endif
+
+ acthcd->active_ep0 = NULL;
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ acthcd->ep0[i] = NULL;
+ acthcd->inep[i] = NULL;
+ acthcd->outep[i] = NULL;
+ }
+
+ acthcd->fifo_map[0] = 1<<31;
+ acthcd->fifo_map[1] = 1<<31 | 64;
+ for (i = 2; i < 64; i++) {
+ acthcd->fifo_map[i] = 0;
+ }
+
+ acthcd->put_aout_msg = 0;
+ acthcd->discon_happened = 0;
+ acthcd->uhc_irq = 0;
+ acthcd->check_trb_mutex = 0;
+ for (i = 0; i < AOTG_QUEUE_POOL_CNT; i++) {
+ acthcd->queue_pool[i] = NULL;
+ }
+
+ return retval;
+}
+
+static const char platform_drv_name[] = "aotg_hcd";
+static const char hcd_driver_name[] = "aotg_hub_hcd";
+
+#define AOTG_BUF_NEED_MAP(x, y) ((x != NULL) && (((unsigned long)x & 0x3) == 0))
+//#define AOTG_BUF_NEED_MAP(x, y) ((x != NULL) && ((y & 0x3) == 0))
+
+static int aotg_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ int ret = 0;
+
+ if (usb_pipetype(urb->pipe) != PIPE_INTERRUPT) {
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+ }
+ return ret;
+}
+
+static void aotg_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (usb_pipetype(urb->pipe) != PIPE_INTERRUPT) {
+
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+ }
+ return;
+}
+
+static struct hc_driver act_hc_driver = {
+ .description = hcd_driver_name,
+ .hcd_priv_size = sizeof(struct aotg_hcd),
+ .product_desc = DRIVER_DESC,
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = aotg_hub_irq,
+ .flags = HCD_USB2 | HCD_MEMORY,
+
+ /* Basic lifecycle operations */
+ .start = aotg_hcd_start,
+ .stop = aotg_hcd_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = aotg_hub_urb_enqueue,
+ .urb_dequeue = aotg_hub_urb_dequeue,
+
+ .map_urb_for_dma = aotg_map_urb_for_dma,
+ .unmap_urb_for_dma = aotg_unmap_urb_for_dma,
+
+ .endpoint_disable = aotg_hub_endpoint_disable,
+
+ /*
+ * periodic schedule support
+ */
+ .get_frame_number = aotg_hcd_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = aotg_hub_status_data,
+ .hub_control = aotg_hub_control,
+
+ .bus_suspend = aotg_hub_suspend,
+ .bus_resume = aotg_hub_resume,
+};
+
+struct of_device_id aotg_hcd_of_match[] = {
+ {.compatible = "actions,owl-usb-2.0-0",.data = &aotg_data0},
+ {.compatible = "actions,owl-usb-2.0-1",.data = &aotg_data1},
+ {},
+};
+MODULE_DEVICE_TABLE(of, aotg_hcd_of_match);
+
+static int aotg_platform_device_init(struct platform_device *pdev)
+{
+ struct device_node *of_node;
+ enum of_gpio_flags flags;
+
+ of_node = of_find_compatible_node(NULL, NULL, aotg_hcd_of_match[pdev->id].compatible);
+ if (NULL == of_node) {
+ dev_err(&pdev->dev, "can't find usbh%d dts node\n",pdev->id);
+ return -1;
+ }
+
+ if (!of_find_property(of_node, "vbus_otg_en_gpio", NULL)) {
+ pr_info("can't find vbus_otg_en_gpio config\n");
+ vbus_otg_en_gpio[pdev->id][0] = -1;
+ } else {
+ vbus_otg_en_gpio[pdev->id][0] = of_get_named_gpio_flags(of_node, "vbus_otg_en_gpio",0, &flags);
+ vbus_otg_en_gpio[pdev->id][1] = flags & 0x01;
+ if (gpio_request(vbus_otg_en_gpio[pdev->id][0], aotg_hcd_of_match[pdev->id].compatible)) {
+ dev_dbg(&pdev->dev, "fail to request vbus gpio [%d]\n", vbus_otg_en_gpio[pdev->id][0]);
+ //return -3;
+ }
+ gpio_direction_output(vbus_otg_en_gpio[pdev->id][0], 1);
+ }
+
+ pr_info("vbus_otg_en_gpio:%d\n",vbus_otg_en_gpio[pdev->id][0]);
+
+ aotg_power_onoff(pdev->id,1);
+
+ return 0;
+};
+
+static int aotg_hub_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res_mem; //, *res_irq;
+ struct aotg_hcd *acthcd;
+ int irq;
+ int retval;
+
+ if (aotg_platform_device_init(pdev) <0) {
+ retval = -ENODEV;
+ goto err0;
+ }
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mem) {
+ dev_err(&pdev->dev, "<HCD_PROBE>usb has no resource for mem!\n");
+ retval = -ENODEV;
+ goto err0;
+ }
+ printk("res_mem->start--end = 0x%x--0x%x\n",res_mem->start,res_mem->end);
+
+ hcd = usb_create_hcd(&act_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ dev_err(&pdev->dev, "<HCD_PROBE>usb create hcd failed\n");
+ retval = -ENOMEM;
+ goto err0;
+ }
+
+ hcd->rsrc_start = res_mem->start;
+ hcd->rsrc_len = res_mem->end - res_mem->start + 1;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "<HCD_PROBE>usb has no resource for irq!\n");
+ retval = -ENODEV;
+ goto err1;
+ }
+ printk("irq = %d\n",irq);
+
+ if (!request_mem_region(res_mem->start, res_mem->end - res_mem->start + 1, dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "<HCD_PROBE>request_mem_region failed\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(res_mem->start, res_mem->end - res_mem->start + 1);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "<HCD_PROBE>ioremap failed\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ retval = aotg_hcd_init(hcd, pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "<HCD_PROBE>hcd init failed\n");
+ goto err3;
+ }
+
+ acthcd = hcd_to_aotg(hcd);
+ act_hcd_ptr[pdev->id] = acthcd;
+ acthcd->dev = &pdev->dev;
+ acthcd->base = hcd->regs;
+ acthcd->hcd_exiting = 0;
+ acthcd->uhc_irq = irq;
+ acthcd->id = pdev->id;
+ dev_info(&pdev->dev, "pdev->id probe:%d\n", pdev->id);
+
+ aotg_hcd_hardware_init(acthcd);
+#if 0
+#ifdef CONFIG_PM
+ aotg_hcd_register_earlysuspend(acthcd);
+#endif
+#endif
+ //pdev->dev.dma_mask = NULL;
+
+ hcd->self.sg_tablesize = 32;
+// hcd->self.sg_tablesize = ~0;
+
+ hcd->has_tt = 1;
+ hcd->self.uses_pio_for_control = 1; /* for ep0, using CPU mode only. */
+
+ init_timer(&acthcd->hotplug_timer);
+ acthcd->hotplug_timer.function = aotg_hub_hotplug_timer;
+ acthcd->hotplug_timer.data = (unsigned long)acthcd;
+
+ init_timer(&acthcd->trans_wait_timer);
+ acthcd->trans_wait_timer.function = aotg_hub_trans_wait_timer;
+ acthcd->trans_wait_timer.data = (unsigned long)acthcd;
+ init_timer(&acthcd->check_trb_timer);
+ acthcd->check_trb_timer.function = aotg_check_trb_timer;
+ acthcd->check_trb_timer.data = (unsigned long)acthcd;
+
+ retval = usb_add_hcd(hcd, irq, 0);
+ if (likely(retval == 0)) {
+ aotg_enable_irq(acthcd);
+ create_debug_file(acthcd);
+ dev_info(&pdev->dev, "hcd controller initialized. OTGIRQ: 0x%02X, OTGSTATE: 0x%02X \n",
+ readb(acthcd->base + OTGIRQ),
+ readb(acthcd->base + OTGSTATE));
+
+ writeb(readb(acthcd->base + USBEIRQ), acthcd->base + USBEIRQ);
+ printk("USBEIRQ(0x%p): 0x%02X\n", acthcd->base + USBEIRQ, readb(acthcd->base + USBEIRQ));
+
+ // if (readb(acthcd->base + OTGSTATE) == AOTG_STATE_A_HOST) {
+ // acthcd->put_aout_msg = 0;
+ // mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(3));
+ // } else {
+ // acthcd->put_aout_msg = 1;
+ // mod_timer(&acthcd->hotplug_timer, jiffies + msecs_to_jiffies(1000));
+ // }
+
+ return 0;
+ } else {
+ dev_err(acthcd->dev, "<HCD_PROBE>usb add hcd failed\n");
+ }
+
+ del_timer_sync(&acthcd->hotplug_timer);
+ del_timer_sync(&acthcd->trans_wait_timer);
+ del_timer_sync(&acthcd->check_trb_timer);
+err3:
+ if (acthcd != NULL) {
+ aotg_hcd_clk_enable(acthcd, 0);
+ iounmap(hcd->regs);
+ }
+err2:
+ release_mem_region(res_mem->start, res_mem->end - res_mem->start + 1);
+err1:
+ usb_put_hcd(hcd);
+err0:
+ dev_err(&pdev->dev, "%s: usb probe hcd failed, error is %d", __func__, retval);
+
+ return retval;
+}
+
+#if 0
+static int inline aotg_hcd_stop_q(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ struct aotg_queue *q = NULL;
+ int ret = 0;
+
+ if ((!ep) || (!ep->q)) {
+ return 0;
+ }
+ q = ep->q;
+ if (list_empty(&q->finished_list)) {
+ q->status = -EIO;
+ ret = 1;
+ list_add_tail(&q->finished_list, &acthcd->hcd_finished_list);
+ } else {
+ return 0;
+ }
+
+ q->is_xfer_start = 0;
+
+ return ret;
+}
+
+static int aotg_hcd_flush_queue(struct aotg_hcd *acthcd)
+{
+ //struct usb_hcd *hcd = aotg_to_hcd(acthcd);
+ struct aotg_queue *q = NULL, *next;
+ struct urb *urb;
+ struct aotg_hcep *ep;
+ int i, ret = 0;
+
+ /* make sure all urb request is exited. */
+ //ep = acthcd->ep0;
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->ep0[i];
+ ret |= aotg_hcd_stop_q(acthcd, ep);
+ }
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ ret |= aotg_hcd_stop_q(acthcd, ep);
+ }
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ ret |= aotg_hcd_stop_q(acthcd, ep);
+ }
+
+ list_for_each_entry_safe(q, next, &acthcd->hcd_enqueue_list, enqueue_list) {
+ urb = q->urb;
+ ep = q->ep;
+ if (ep)
+ ep->urb_unlinked_cnt++;
+ if (q->enqueue_list.next != LIST_POISON1) {
+ list_del(&q->enqueue_list);
+ q->status = -EIO;
+ if (list_empty(&q->finished_list)) {
+ ret = 1;
+ list_add_tail(&q->finished_list, &acthcd->hcd_finished_list);
+ } else {
+ ACT_HCD_ERR
+ }
+ } else {
+ ACT_HCD_DBG
+ }
+ }
+
+ return ret;
+}
+#endif
+
+static int aotg_hub_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ struct aotg_hcep *ep;
+ int i;
+
+ usb_remove_hcd(hcd);
+ act_hcd_ptr[pdev->id] = NULL;
+#if 0
+#ifdef CONFIG_PM
+ aotg_hcd_unregister_earlysuspend(acthcd);
+#endif
+#endif
+ aotg_disable_irq(acthcd);
+ aotg_hcd_clk_enable(acthcd, 0);
+ acthcd->hcd_exiting = 1;
+
+ tasklet_kill(&acthcd->urb_tasklet);
+ del_timer_sync(&acthcd->trans_wait_timer);
+ del_timer_sync(&acthcd->check_trb_timer);
+ del_timer_sync(&acthcd->hotplug_timer);
+ remove_debug_file(acthcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ //aotg_hcd_release_queue(acthcd, NULL);
+ owl_powergate_power_off(acthcd->id == 0 ? OWL_POWERGATE_USB2_0 : OWL_POWERGATE_USB2_1);
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ ep = acthcd->ep0[i];
+ if (ep) {
+ ACT_HCD_DBG
+ if (ep->q)
+ ACT_HCD_DBG
+ kfree(ep);
+ }
+ }
+//fix here in 64 bit
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->inep[i];
+ if (ep) {
+ ACT_HCD_DBG
+ if (ep->ring) {
+ ACT_HCD_DBG
+ //aotg_free_ring(acthcd, ep->ring);
+ }
+ kfree(ep);
+ }
+ }
+ for (i = 1; i < MAX_EP_NUM; i++) {
+ ep = acthcd->outep[i];
+ if (ep) {
+ ACT_HCD_DBG
+ if (ep->ring) {
+ ACT_HCD_DBG
+ //aotg_free_ring(acthcd,ep->ring);
+ }
+ kfree(ep);
+ }
+ }
+
+ usb_put_hcd(hcd);
+ printk("pdev->id remove:%d\n", pdev->id);
+
+ if (!port_host_plug_detect[acthcd->id])
+ aotg_power_onoff(pdev->id,0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int aotg_hcd_hub_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+
+ if ((hcd == NULL) || (acthcd == NULL)) {
+ ACT_HCD_ERR
+ return 0;
+ }
+ dev_info(acthcd->dev, " ==> %s\n", __func__);
+ /*do {
+ i++;
+ msleep(1);
+ } while ((acthcd->suspend_request_pend != 0) && (i < 200));*/
+
+ aotg_disable_irq(acthcd);
+ //usb_clearbitsb(OTGCTRL_BUSREQ, acthcd->base + OTGCTRL);
+ owl_powergate_power_off(acthcd->id == 0 ?
+ OWL_POWERGATE_USB2_0 : OWL_POWERGATE_USB2_1);
+ aotg_hcd_clk_enable(acthcd, 0);
+
+ aotg_power_onoff(pdev->id,0);
+ acthcd->lr_flag = 1;
+ return 0;
+}
+
+static int aotg_hcd_hub_resume(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ struct usb_device *udev;
+ int i;
+
+ if ((hcd == NULL) || (acthcd == NULL)) {
+ ACT_HCD_ERR
+ return 0;
+ }
+
+ /* power on. */
+/* if (acthcd->id == 0) {
+ aotg0_device_init(1);
+ } else {
+ aotg1_device_init(1);
+ }*/
+ //gpio_set_value_cansleep(vbus_otg_en_gpio[pdev->id][0], 1);
+ aotg_power_onoff(pdev->id,1);
+ msleep(10);
+
+ dev_info(acthcd->dev, " ==> %s\n", __func__);
+ aotg_hcd_hardware_init(acthcd);
+
+ //INIT_LIST_HEAD(&acthcd->hcd_enqueue_list);
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ if (acthcd->ep0[i] != NULL) {
+ break;
+ }
+ }
+
+ if (i == MAX_EP_NUM) {
+ printk(KERN_ERR"%s, usb device is NULL!\n", __FUNCTION__);
+ }
+ else {
+ udev = acthcd->ep0[i]->udev;
+ //if (port_plug_en[acthcd->id]) {
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ //} else {
+ // usb_set_device_state(udev, USB_STATE_CONFIGURED);
+ //}
+ }
+ if (port_host_plug_detect[acthcd->id]) {
+ aotg_dev_plugout_msg(acthcd->id);
+ } else {
+ aotg_enable_irq(acthcd);
+ }
+ return 0;
+}
+#endif
+
+void aotg_hcd_shutdown(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct aotg_hcd *acthcd = hcd_to_aotg(hcd);
+ printk("usb2-%d shutdown\n", acthcd->id);
+
+ //gpio_set_value_cansleep(vbus_otg_en_gpio[pdev->id][0], 0);
+ aotg_power_onoff(pdev->id,0);
+ return;
+}
+
+static struct platform_driver aotg_hcd_hub_driver = {
+ .probe = aotg_hub_probe,
+ .remove = aotg_hub_remove,
+#ifdef CONFIG_PM
+ .suspend = aotg_hcd_hub_suspend,
+ .resume = aotg_hcd_hub_resume,
+#endif
+ .shutdown = aotg_hcd_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = platform_drv_name,
+ .of_match_table = aotg_hcd_of_match,
+ },
+};
+
+static inline int aotg_device_calc_id(int dev_id)
+{
+ int id;
+
+ if (hcd_ports_en_ctrl == 1) {
+ id = 0;
+ } else if (hcd_ports_en_ctrl == 2) {
+ id = 1;
+ } else if (hcd_ports_en_ctrl == 3) {
+ if (dev_id) {
+ id = 0;
+ } else {
+ id = 1;
+ }
+ } else {
+ id = dev_id;
+ }
+ return id;
+}
+
+int aotg_device_init(int dev_id)
+{
+ struct device_node *of_node;
+ struct resource res[2];
+ int ret = 0;
+
+ mutex_lock(&aotg_onoff_mutex);
+ if (aotg_initialized[dev_id]) {
+ aotg_initialized[dev_id]++;
+ printk("aotg%d initialized allready! cnt:%d\n", dev_id, aotg_initialized[dev_id]);
+ mutex_unlock(&aotg_onoff_mutex);
+ return 0;
+ }
+ aotg_initialized[dev_id] = 1;
+ of_node = of_find_compatible_node(NULL, NULL, aotg_hcd_of_match[dev_id].compatible);
+ if (NULL == of_node) {
+ ERR("can't find usbh%d dts node\n",dev_id);
+ ret = -1;
+ goto err1;
+ }
+
+ memset(&res, 0, sizeof(res));
+ if (of_address_to_resource(of_node, 0, &res[0])) {
+ ERR("can't fetch mem info from dts\n");
+ ret = -2;
+ goto err1;
+ }
+
+ if (of_irq_to_resource(of_node, 0, &res[1]) == NO_IRQ) {
+ ERR("can't fetch IRQ info from dts\n");
+ ret = -3;
+ goto err1;
+ }
+
+ aotg_dev[dev_id] = platform_device_alloc("aotg_hcd", dev_id);
+ if (!aotg_dev[dev_id]) {
+ ERR("platform_device_alloc fail\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+ aotg_dev[dev_id]->dev.dma_mask = &hcd_dmamask;
+ aotg_dev[dev_id]->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = platform_device_add_resources(aotg_dev[dev_id], res, ARRAY_SIZE(res));
+ if (ret) {
+ ERR("platform_device_add_resources fail\n");
+ goto err;
+ }
+
+ ret = platform_device_add_data(aotg_dev[dev_id], aotg_hcd_of_match[dev_id].data, sizeof(struct aotg_plat_data));
+ if (ret) {
+ ERR("platform_device_add_data fail\n");
+ goto err;
+ }
+
+ ret = platform_device_add(aotg_dev[dev_id]);
+ if (ret) {
+ ERR("platform_device_add fail\n");
+ goto err;
+ }
+
+ mutex_unlock(&aotg_onoff_mutex);
+ return 0;
+err:
+ platform_device_put(aotg_dev[dev_id]);
+ aotg_dev[dev_id] = NULL;
+err1:
+ mutex_unlock(&aotg_onoff_mutex);
+ return ret;
+}
+
+void aotg_device_exit(int dev_id)
+{
+ mutex_lock(&aotg_onoff_mutex);
+ if (!aotg_initialized[dev_id]) {
+ printk("aotg%d exit allready!\n",dev_id);
+ mutex_unlock(&aotg_onoff_mutex);
+ return;
+ }
+
+ aotg_initialized[dev_id]--;
+ if (aotg_initialized[dev_id] > 0) {
+ printk("aotg%d_exit cnt:%d\n", dev_id, aotg_initialized[dev_id]);
+ mutex_unlock(&aotg_onoff_mutex);
+ return;
+ }
+ aotg_initialized[dev_id] = 0;
+
+ if (aotg_dev[dev_id] != NULL) {
+ platform_device_unregister(aotg_dev[dev_id]);
+ aotg_dev[dev_id] = NULL;
+ }
+ mutex_unlock(&aotg_onoff_mutex);
+}
+
+int aotg_hub_register(int dev_id)
+{
+ int proc_id;
+ proc_id = aotg_device_calc_id(dev_id);
+
+ //wake_lock(&acts_hcd_wakelock);
+
+// if (dev_id) {
+// proc_id = 1;
+
+ /*if (!(aotg_registered_map&(1<<proc_id))) {
+ printk("register aotg_hcd%d device !\n", proc_id);
+ aotg_registered_map |= 1<<proc_id;
+ return aotg_device_init(proc_id);
+ }
+ else
+ {
+ ERR("aotg_hub%d device had been registered!\n",proc_id);
+ }*/
+ return aotg_device_init(proc_id);
+}
+EXPORT_SYMBOL(aotg_hub_register);
+
+void aotg_hub_unregister(int dev_id)
+{
+ int proc_id;
+ proc_id = aotg_device_calc_id(dev_id);
+
+ /*if (aotg_registered_map&(1<<proc_id)) {
+ printk("unregister aotg_hcd%d device!\n", proc_id);
+ aotg_registered_map &= ~(1<<proc_id);
+ aotg_device_exit(dev_id);
+ }
+ else
+ {
+ ERR("aotg_hcd%d device had been unregistered!\n",proc_id);
+ }*/
+ aotg_device_exit(dev_id);
+}
+EXPORT_SYMBOL(aotg_hub_unregister);
+
+static int __init ahcd_init(void)
+{
+ mutex_init(&aotg_onoff_mutex);
+ platform_driver_register(&aotg_hcd_hub_driver);
+ //wake_lock_init(&acts_hcd_wakelock, WAKE_LOCK_SUSPEND, "acts_hcd");
+ create_acts_hcd_proc();
+ aotg_uhost_mon_init();
+ return 0;
+}
+
+static void __exit ahcd_exit(void)
+{
+ remove_acts_hcd_proc();
+ platform_driver_unregister(&aotg_hcd_hub_driver);
+ //wake_lock_destroy(&acts_hcd_wakelock);
+ aotg_uhost_mon_exit();
+ return;
+}
+
+module_init(ahcd_init);
+module_exit(ahcd_exit);
+
+MODULE_DESCRIPTION("Actions HCD controller driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/host/aotg_hcd.h b/drivers/usb/host/aotg_hcd.h
new file mode 100644
index 0000000..e169edd
--- /dev/null
+++ b/drivers/usb/host/aotg_hcd.h
@@ -0,0 +1,467 @@
+#ifndef __LINUX_USB_HOST_AOTG_H
+#define __LINUX_USB_HOST_AOTG_H
+
+#include <mach/hardware.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
+#include <linux/earlysuspend.h>
+
+#include "aotg_regs.h"
+
+//#define USBH_DEBUG
+
+#define PERIODIC_SIZE 64
+#define MAX_PERIODIC_LOAD 500 //50%
+
+#define AOTG_BULK_FIFO_START_ADDR 0x0080
+#define AOTG_INTERRUPT_FIFO_START_ADDR 0xC00 //max 1k
+
+
+#define USB_HCD_IN_MASK 0x00
+#define USB_HCD_OUT_MASK 0x10
+
+#define AOTG_MAX_FIFO_SIZE (512*10 + 64*2) //5k
+#define ALLOC_FIFO_UNIT 64
+//#define AOTG_MIN_DMA_SIZE 512
+//#define AOTG_MIN_DMA_SIZE 64
+#define AOTG_MIN_DMA_SIZE 0
+
+#define AOTG_PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION \
+ | USB_PORT_STAT_C_ENABLE \
+ | USB_PORT_STAT_C_SUSPEND \
+ | USB_PORT_STAT_C_OVERCURRENT \
+ | USB_PORT_STAT_C_RESET) << 16)
+
+#define MAX_EP_NUM 16 //count of each type, 1st is reserved
+#define MAX_SG_TABLE (0x1 << 9)
+
+#define MAX_ERROR_COUNT 6
+
+#ifndef USBH0_ECS
+#define USBH0_ECS (TIMER_2HZ_BASE+0x0084)
+#endif
+
+#define CMU_USBPLL_USBPLL0EN 0x1500
+
+#define CMU_DEVRST1_USBH0 0x01
+
+#define CMU_USBPLL_USBPLL1EN 0x2a00
+
+#define CMU_DEVRST1_USB1 (1<<22)
+
+#ifndef USBH1_ECS
+#define USBH1_ECS (TIMER_2HZ_BASE+0x0088)
+#endif
+
+/* 0 is all enable, 1 -- just usb0 enable, 2 -- usb1 enable,
+ * 3 -- usb0 and usb1 enable,but reversed.
+ */
+extern int hcd_ports_en_ctrl;
+
+extern struct aotg_hcd *act_hcd_ptr[2];
+
+struct hcd_stats {
+ unsigned long insrmv;
+ unsigned long wake;
+ unsigned long sof;
+};
+
+enum aotg_rh_state {
+ AOTG_RH_POWEROFF,
+ AOTG_RH_POWERED,
+ AOTG_RH_ATTACHED,
+ AOTG_RH_NOATTACHED,
+ AOTG_RH_RESET,
+ AOTG_RH_ENABLE,
+ AOTG_RH_DISABLE,
+ AOTG_RH_SUSPEND,
+ AOTG_RH_ERR
+};
+
+enum control_phase {
+ PHASE_UNDEFINED,
+ PHASE_SETUP,
+ PHASE_DATA,
+ PHASE_STATUS,
+};
+
+#define TRB_ITE (1 << 11)
+#define TRB_CHN (1 << 10)
+#define TRB_CSP (1 << 9)
+#define TRB_COF (1 << 8)
+#define TRB_ICE (1 << 7)
+#define TRB_IZE (1 << 6)
+#define TRB_ISE (1 << 5)
+#define TRB_LT (1 << 4)
+#define AOTG_TRB_IOC (1 << 3)
+#define AOTG_TRB_IOZ (1 << 2)
+#define AOTG_TRB_IOS (1 << 1)
+#define TRB_OF (1 << 0)
+
+struct aotg_trb {
+ u32 hw_buf_ptr;
+ u32 hw_buf_len;
+ u32 hw_buf_remain;
+ u32 hw_token;
+};
+
+#define USE_SG
+#ifdef USE_SG
+#define NUM_TRBS (256)
+#define RING_SIZE (NUM_TRBS * 16)
+#else
+#define NUM_TRBS (64)
+#define RING_SIZE (NUM_TRBS * 16)
+#endif
+
+//#define INTR_TRBS (256)
+#define INTR_TRBS (10)
+
+
+#define RING_IN_OF (0xFFFE)
+#define RING_OUT_OF (0xFFFE0000)
+
+#define TD_IN_FINISH (0)
+#define TD_IN_RING (0x1 << 0)
+#define TD_IN_QUEUE (0x1 << 1)
+
+struct aotg_ring {
+ //need a protect lock
+ unsigned is_running:1;
+ unsigned is_out:1;
+ unsigned intr_inited:1;
+ unsigned intr_started:1;
+ unsigned ring_stopped:1;
+ int num_trbs;
+ //int irq_interval;
+ //int td_irq_interval;
+ int type;
+ u8 mask;
+ void *priv;
+ atomic_t num_trbs_free;
+
+ int intr_mem_size;
+ struct dma_pool *intr_dma_pool;
+ u8 *intr_dma_buf_vaddr;
+ dma_addr_t intr_dma_buf_phyaddr;
+ char pool_name[32];
+
+ struct aotg_trb *enqueue_trb;
+ struct aotg_trb *dequeue_trb;
+ struct aotg_trb *first_trb;
+ struct aotg_trb *last_trb;
+ struct aotg_trb *ring_trb;
+ u32 trb_dma;
+
+ unsigned int enring_cnt;
+ unsigned int dering_cnt;
+
+ volatile void __iomem *reg_dmalinkaddr;
+ volatile void __iomem *reg_curaddr;
+ volatile void __iomem *reg_dmactrl;
+ volatile void __iomem *reg_dmacomplete_cnt;
+};
+
+struct aotg_td {
+ struct urb *urb;
+ int num_trbs;
+ u32 trb_dma;
+ int err_count;
+ struct aotg_trb *trb_vaddr;
+
+ struct list_head queue_list;
+ struct list_head enring_list;
+ struct list_head dering_list;
+
+ u8 *intr_mem_vaddr;
+ dma_addr_t intr_men_phyaddr;
+ int mem_size;
+
+ unsigned cross_ring:1;
+};
+
+struct aotg_queue {
+ int in_using;
+ struct aotg_hcep *ep;
+ struct urb *urb;
+ int dma_no;
+ int is_xfer_start;
+ int need_zero;
+
+ //struct list_head dma_q_list;
+ //struct list_head ep_q_list;
+ struct list_head enqueue_list;
+ struct list_head dequeue_list;
+ struct list_head finished_list;
+ int status; //for dequeue
+ int length;
+
+ struct aotg_td td;
+
+ struct scatterlist *cur_sg;
+ int err_count;
+ unsigned long timeout; /* jiffies + n. */
+
+ /* fixing dma address unaligned to 4 Bytes. */
+ u8 * dma_copy_buf;
+ dma_addr_t dma_addr;
+
+ /* for debug. */
+ unsigned int seq_info;
+} __attribute__ ((aligned (4)));
+
+struct aotg_dma_buf {
+ unsigned int size;
+ u8 * buf;
+ dma_addr_t dma;
+ int in_using;
+};
+
+struct aotg_hcd {
+ int id;
+ spinlock_t lock;
+ spinlock_t tasklet_lock;
+ int check_trb_mutex;
+ volatile int tasklet_retry;
+ void __iomem *base;
+ struct device *dev;
+ struct aotg_plat_data *port_specific;
+ struct proc_dir_entry *pde;
+ enum usb_device_speed speed;
+ int inserted; /*imply a USB deivce inserting in MiniA receptacle*/
+ u32 port; /*indicate portstatus and portchange*/
+ enum aotg_rh_state rhstate;
+
+ int hcd_exiting;
+
+ u16 hcin_dma_ien;
+ u16 hcout_dma_ien;
+
+ /* when using hub, every usb device need a ep0 hcep data struct, but share the same hcd ep0. */
+ struct aotg_hcep *active_ep0;
+ int ep0_block_cnt;
+ struct aotg_hcep *ep0[MAX_EP_NUM];
+ struct aotg_hcep *inep[MAX_EP_NUM]; // 0 for reserved
+ struct aotg_hcep *outep[MAX_EP_NUM]; // 0 for reserved
+
+ struct list_head hcd_enqueue_list;
+ struct list_head hcd_dequeue_list;
+ struct list_head hcd_finished_list;
+ struct tasklet_struct urb_tasklet;
+
+ struct timer_list hotplug_timer;
+ struct timer_list check_trb_timer;
+ struct timer_list trans_wait_timer;
+ ulong fifo_map[AOTG_MAX_FIFO_SIZE/ALLOC_FIFO_UNIT];
+
+ int discon_happened;
+ int put_aout_msg;
+ int suspend_request_pend;
+ int uhc_irq;
+
+#ifdef CONFIG_PM
+#define USB_RESET_DEVICE (0)
+#define USB_RESET_AND_VERIFY_DEVICE (1)
+ int lr_flag;
+ struct early_suspend earlysuspend;
+
+# endif
+
+ #define AOTG_QUEUE_POOL_CNT 60
+ struct aotg_queue *queue_pool[AOTG_QUEUE_POOL_CNT];
+ #define AOTG_DMA_BUF_CNT 8
+ struct aotg_dma_buf dma_poll[AOTG_DMA_BUF_CNT];
+};
+
+struct aotg_hcep {
+ struct usb_host_endpoint *hep;
+ struct usb_device *udev;
+ int index;
+ /* just for ep0, when using hub, every usb device need a ep0 hcep data struct, but share the same hcd ep0. */
+ int ep0_index;
+ int iso_packets;
+ u32 maxpacket;
+ u16 error_count;
+ u16 length;
+ u8 epnum;
+ u8 nextpid;
+ u8 mask;
+ u8 type;
+ u8 is_out;
+ u8 buftype;
+ u8 has_hub;
+ u8 hub_addr;
+ u8 reg_hcep_splitcs_val;
+
+ void __iomem *reg_hcepcs;
+ void __iomem *reg_hcepcon;
+ void __iomem *reg_hcepctrl;
+ void __iomem *reg_hcepbc;
+ void __iomem *reg_hcmaxpck;
+ void __iomem *reg_hcepaddr;
+ void __iomem *reg_hcerr;
+ //void __iomem *reg_hcfifo;
+ void __iomem *reg_hcep_interval;
+ void __iomem *reg_hcep_dev_addr;
+ void __iomem *reg_hcep_port;
+ void __iomem *reg_hcep_splitcs;
+
+ unsigned int urb_enque_cnt;
+ unsigned int urb_endque_cnt;
+ unsigned int urb_stop_stran_cnt;
+ unsigned int urb_unlinked_cnt;
+
+ u32 dma_bytes;
+ u16 interval;
+ u16 load; /* one packet times in us. */
+
+ //u16 branch;
+ //struct aotg_hcep *next;
+ u16 fifo_busy;
+
+ ulong fifo_addr;
+ struct aotg_queue *q;
+
+ struct aotg_ring *ring;
+ struct list_head queue_td_list;
+ struct list_head enring_td_list;
+ struct list_head dering_td_list;
+
+};
+
+#define get_hcepcon_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*8)
+#define get_hcepcs_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*8)
+#define get_hcepctrl_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*4)
+#define get_hcepbc_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*8)
+#define get_hcepmaxpck_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*2)
+#define get_hcepaddr_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*4)
+//#define get_hcfifo_reg(x , z) (x + (z - 1)*4)
+#define get_hcep_dev_addr_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*8)
+#define get_hcep_port_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*8)
+#define get_hcep_splitcs_reg(dir , x , y , z) ((dir ? x : y) + (z - 1)*8)
+
+#define AOTG_DMA_OUT_PREFIX 0x10
+#define AOTG_DMA_NUM_MASK 0xf
+#define AOTG_IS_DMA_OUT(x) ((x) & AOTG_DMA_OUT_PREFIX)
+#define AOTG_GET_DMA_NUM(x) ((x) & AOTG_DMA_NUM_MASK)
+
+#define GET_DMALINKADDR_REG(dir, x, y, z) ((dir ? x : y) + (z - 1) * 0x10)
+#define GET_CURADDR_REG(dir, x, y, z) ((dir ? x : y) + (z - 1) * 0x10)
+#define GET_DMACTRL_REG(dir, x, y, z) ((dir ? x : y) + (z - 1) * 0x10)
+#define GET_DMACOMPLETE_CNT_REG(dir, x, y, z) ((dir ? x : y) + (z - 1) * 0x10)
+
+
+static inline struct aotg_hcd *hcd_to_aotg(struct usb_hcd *hcd)
+{
+ return (struct aotg_hcd *) (hcd->hcd_priv);
+}
+
+static inline void aotg_clear_all_overflow_irq(struct aotg_hcd *acthcd)
+{
+ unsigned int irq_pend = 0;
+
+ irq_pend = readl(acthcd->base + HCDMAxOVERFLOWIRQ);
+
+ if (irq_pend) {
+ writel(irq_pend, acthcd->base + HCDMAxOVERFLOWIRQ);
+ }
+ return;
+}
+
+static inline void aotg_clear_all_shortpkt_irq(struct aotg_hcd *acthcd)
+{
+ unsigned int irq_pend = 0;
+
+ irq_pend = readw(acthcd->base + HCINxSHORTPCKIRQ0);
+
+ if (irq_pend) {
+ writew(irq_pend, acthcd->base + HCINxSHORTPCKIRQ0);
+ }
+ return;
+}
+
+static inline void aotg_clear_all_zeropkt_irq(struct aotg_hcd *acthcd)
+{
+ unsigned int irq_pend = 0;
+
+ irq_pend = readw(acthcd->base + HCINxZEROPCKIEN0);
+
+ if (irq_pend) {
+ writew(irq_pend, acthcd->base + HCINxZEROPCKIEN0);
+ }
+ return;
+}
+
+static inline void aotg_clear_all_hcoutdma_irq(struct aotg_hcd *acthcd)
+{
+ unsigned int irq_pend = 0;
+
+ irq_pend = readw(acthcd->base + HCOUTxDMAIRQ0);
+
+ if (irq_pend) {
+ writew(irq_pend, acthcd->base + HCOUTxDMAIRQ0);
+ }
+ return;
+}
+
+static inline void aotg_hcep_reset(struct aotg_hcd *acthcd, u8 ep_mask, u8 type_mask)
+{
+ u8 val;
+
+ writeb(ep_mask, acthcd->base + ENDPRST); /*select ep */
+ val = ep_mask | type_mask;
+ writeb(val, acthcd->base + ENDPRST); /*reset ep */
+ return;
+}
+
+static inline struct usb_hcd *aotg_to_hcd(struct aotg_hcd *acthcd)
+{
+ return container_of((void *)acthcd, struct usb_hcd, hcd_priv);
+}
+
+void aotg_hcd_dump_td(struct aotg_ring *ring, struct aotg_td *td);
+struct aotg_ring *aotg_alloc_ring(struct aotg_hcd *acthcd,
+ struct aotg_hcep *ep, unsigned int num_trbs,
+ gfp_t mem_flags);
+void aotg_free_ring(struct aotg_hcd *acthcd, struct aotg_ring *ring);
+void enable_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep);
+
+void dequeue_td(struct aotg_ring *ring, struct aotg_td *td, int dequeue_flag);
+int aotg_ring_enqueue_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td);
+int aotg_ring_dequeue_td(struct aotg_hcd *acthcd, struct aotg_ring *ring,
+ struct aotg_td *td, int dequeue_flag);
+int aotg_ring_enqueue_isoc_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td);
+int aotg_ring_enqueue_intr_td(struct aotg_hcd *acthcd, struct aotg_ring *ring,
+ struct aotg_hcep *ep, struct urb *urb, gfp_t mem_flags);
+int aotg_ring_dequeue_intr_td(struct aotg_hcd *acthcd, struct aotg_hcep *ep,
+ struct aotg_ring *ring, struct aotg_td *td);
+void aotg_intr_dma_pool_destroy(struct aotg_ring *ring);
+void aotg_intr_dma_buf_free(struct aotg_hcd *acthcd, struct aotg_ring *ring);
+
+struct aotg_td *aotg_alloc_td(gfp_t mem_flags);
+void aotg_release_td(struct aotg_td *td);
+
+int is_ring_running(struct aotg_ring *ring);
+void aotg_start_ring(struct aotg_ring *ring, u32 addr);
+void aotg_stop_ring(struct aotg_ring *ring);
+u32 ring_trb_virt_to_dma(struct aotg_ring *ring,
+ struct aotg_trb *trb_vaddr);
+
+void aotg_ring_irq_handler(struct aotg_hcd *acthcd);
+
+void aotg_dump_linklist_reg_2(struct aotg_hcd *acthcd, int dmanr);
+
+int intr_finish_td(struct aotg_hcd *acthcd, struct aotg_ring *ring, struct aotg_td *td);
+void dequeue_intr_td(struct aotg_ring *ring, struct aotg_td *td);
+void aotg_reorder_intr_td( struct aotg_hcep *ep);
+int aotg_intr_chg_buf_len(struct aotg_hcd *acthcd, struct aotg_ring *ring, int len);
+int aotg_intr_get_finish_trb(struct aotg_ring *ring);
+void aotg_reorder_iso_td(struct aotg_hcd *acthcd, struct aotg_ring *ring);
+void handle_ring_dma_tx(struct aotg_hcd *acthcd, unsigned int irq_mask);
+
+#endif /* __LINUX_USB_HOST_AOTG_H */
+
diff --git a/drivers/usb/host/aotg_mon.c b/drivers/usb/host/aotg_mon.c
new file mode 100644
index 0000000..6b3b16d
--- /dev/null
+++ b/drivers/usb/host/aotg_mon.c
@@ -0,0 +1,386 @@
+/*
+ * (C) Copyright www.actions-semi.com 2012-2014
+ * Written by houjingkun. <houjingkun at actions-semi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
+
+#include <asm/irq.h>
+#include <linux/regulator/consumer.h>
+#include <mach/hardware.h>
+#include <linux/clk.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
+#include <mach/debug.h>
+#include <asm/prom.h>
+#include <mach/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <mach/powergate.h>
+
+#include "aotg_hcd.h"
+#include "aotg_regs.h"
+#include "aotg_plat_data.h"
+#include "aotg_debug.h"
+
+int aotg_device_init(int dev_id);
+void aotg_device_exit(int dev_id);
+void aotg_power_onoff(int id,int on_off);
+
+
+/* usbecs register. */
+#define USB2_ECS_VBUS_P0 10
+#define USB2_ECS_ID_P0 12
+#define USB2_ECS_LS_P0_SHIFT 8
+#define USB2_ECS_LS_P0_MASK (0x3<<8)
+#define USB2_ECS_DPPUEN_P0 3
+#define USB2_ECS_DMPUEN_P0 2
+#define USB2_ECS_SOFTIDEN_P0 26
+#define USB2_ECS_SOFTID_P0 27
+#define USB2_ECS_SOFTVBUSEN_P0 24
+#define USB2_ECS_SOFTVBUS_P0 25
+#define USB2_ECS_PLL_LDO_EN (1<<7)
+#define USB2_PLL_EN0 (1<<12)
+#define USB2_PLL_EN1 (1<<13)
+#define USB2_PHYCLK_EN0 (1<<10)
+#define USB2_PHYCLK_EN1 (1<<11)
+
+struct aotg_uhost_mon_t {
+ int id;
+ void __iomem *usbecs;
+ void __iomem *usbpll;
+
+ struct timer_list hotplug_timer;
+
+ struct workqueue_struct *aotg_dev_onoff;
+ struct delayed_work aotg_dev_init;
+ struct delayed_work aotg_dev_exit;
+ struct wake_lock aotg_wake_lock;
+
+ unsigned int aotg_uhost_det;
+
+ /* dp, dm state. */
+ unsigned int old_state;
+ unsigned int state;
+};
+
+int port_host_plug_detect[2] = {0};
+extern int is_ls_device[2];
+extern int vbus_otg_en_gpio[2][2];
+extern struct of_device_id aotg_hcd_of_match[];
+static struct aotg_uhost_mon_t * aotg_uhost_mon0 = NULL;
+static struct aotg_uhost_mon_t * aotg_uhost_mon1 = NULL;
+
+int usb2_set_dp_500k_15k(struct aotg_uhost_mon_t * umon, int enable_500k_up, int enable_15k_down)
+{
+ unsigned int val;
+
+ val = readl(umon->usbecs) & (~((1 << USB2_ECS_DPPUEN_P0) |
+ (1 << USB2_ECS_DMPUEN_P0)));
+
+ if (enable_500k_up != 0) {
+ val |= (1 << USB2_ECS_DPPUEN_P0)|(1 << USB2_ECS_DMPUEN_P0);
+ }
+
+ writel(val, umon->usbecs); /* 500k up enable, 15k down disable; */
+ return 0;
+}
+
+/* return dp, dm state. */
+static inline unsigned int usb_get_linestates(struct aotg_uhost_mon_t * umon)
+{
+ unsigned int state;
+
+ state = ((readl(umon->usbecs) & USB2_ECS_LS_P0_MASK) >> USB2_ECS_LS_P0_SHIFT);
+ return state;
+}
+
+static void aotg_uhost_mon_timer(unsigned long data)
+{
+ static int cnt = 0;
+ struct aotg_uhost_mon_t * umon = (struct aotg_uhost_mon_t *)data;
+
+ if ((!umon) || (!umon->aotg_uhost_det)) {
+ return;
+ }
+ umon->state = usb_get_linestates(umon);
+
+ cnt++;
+ if ((cnt % 16) == 0) {
+ }
+
+ if (umon->state != 0) {
+ if ((umon->state == umon->old_state) && (umon->state != 0x3)) {
+ umon->aotg_uhost_det = 0;
+ umon->old_state = 0;
+ if(umon->state==2)
+ is_ls_device[umon->id]=1;
+ queue_delayed_work(umon->aotg_dev_onoff, &umon->aotg_dev_init, msecs_to_jiffies(1));
+ return;
+ }
+ }
+
+ umon->old_state = umon->state;
+ mod_timer(&umon->hotplug_timer, jiffies + msecs_to_jiffies(500));
+ return;
+}
+
+static void aotg_dev_register(struct work_struct *w)
+{
+ struct aotg_uhost_mon_t *umon = container_of(w, struct aotg_uhost_mon_t, aotg_dev_init.work);
+
+ if (umon->id) {
+ usb_clearbitsl(USB2_PLL_EN1,aotg_uhost_mon1->usbpll);
+ owl_powergate_power_off(OWL_POWERGATE_USB2_1);
+ } else {
+ usb_clearbitsl(USB2_PLL_EN0,aotg_uhost_mon0->usbpll);
+ owl_powergate_power_off(OWL_POWERGATE_USB2_0);
+ }
+ wake_lock_timeout(&umon->aotg_wake_lock, 15*HZ);
+ aotg_device_init(umon->id);
+ return;
+}
+
+static void aotg_dev_unregister(struct work_struct *w)
+{
+ struct aotg_uhost_mon_t *umon = container_of(w, struct aotg_uhost_mon_t, aotg_dev_exit.work);
+
+ lock_system_sleep();
+ wake_lock_timeout(&umon->aotg_wake_lock, 15*HZ);
+ unlock_system_sleep();
+
+ aotg_device_exit(umon->id);
+ umon->aotg_uhost_det = 1;
+ if (umon->id) {
+ owl_powergate_power_on(OWL_POWERGATE_USB2_1);
+ usb_setbitsl(USB2_PLL_EN1,aotg_uhost_mon1->usbpll);
+ usb_setbitsl(USB2_PHYCLK_EN1,aotg_uhost_mon1->usbpll);
+ usb_setbitsl(USB2_ECS_PLL_LDO_EN,aotg_uhost_mon1->usbecs);
+ usb2_set_dp_500k_15k(aotg_uhost_mon1, 0, 1);
+ is_ls_device[1]=0;
+ } else {
+ owl_powergate_power_on(OWL_POWERGATE_USB2_0);
+ usb_setbitsl(USB2_PLL_EN0,aotg_uhost_mon0->usbpll);
+ usb_setbitsl(USB2_PHYCLK_EN0,aotg_uhost_mon0->usbpll);
+ usb_setbitsl(USB2_ECS_PLL_LDO_EN,aotg_uhost_mon0->usbecs);
+ usb2_set_dp_500k_15k(aotg_uhost_mon0, 0, 1);
+ is_ls_device[0]=0;
+ }
+
+ mod_timer(&umon->hotplug_timer, jiffies + msecs_to_jiffies(1000));
+ return;
+}
+
+void aotg_dev_plugout_msg(int id)
+{
+ struct aotg_uhost_mon_t *umon = NULL;
+
+ printk("usb%d had been plugged out!\n",id);
+ if ((id == 0) && aotg_uhost_mon0) {
+ umon = aotg_uhost_mon0;
+ } else if ((id == 1) && aotg_uhost_mon1) {
+ umon = aotg_uhost_mon1;
+ } else {
+ ACT_HCD_DBG
+ return;
+ }
+
+ umon->old_state = 0;
+ queue_delayed_work(umon->aotg_dev_onoff, &umon->aotg_dev_exit, msecs_to_jiffies(1000));
+ return;
+}
+
+static struct aotg_uhost_mon_t * aotg_uhost_mon_alloc(void)
+{
+ struct aotg_uhost_mon_t *umon = NULL;
+
+ umon = kzalloc(sizeof(*umon), GFP_KERNEL);
+ if (!umon)
+ return NULL;
+
+ init_timer(&umon->hotplug_timer);
+ umon->hotplug_timer.function = aotg_uhost_mon_timer;
+ umon->hotplug_timer.data = (unsigned long)umon;
+
+ INIT_DELAYED_WORK(&umon->aotg_dev_init, aotg_dev_register);
+ INIT_DELAYED_WORK(&umon->aotg_dev_exit, aotg_dev_unregister);
+
+ umon->aotg_uhost_det = 1;
+
+ return umon;
+}
+
+void aotg_uhost_mon_init(void)
+{
+ struct device_node *of_node;
+ enum of_gpio_flags flags;
+
+ of_node = of_find_compatible_node(NULL, NULL, "actions,owl-usb-2.0-0");
+ if (of_node) {
+ if (!of_find_property(of_node, "port0_host_plug_detect", NULL)) {
+ pr_info("can't find port0_host_plug_detect config\n");
+ port_host_plug_detect[0] = 0;
+ } else {
+ port_host_plug_detect[0] = be32_to_cpup((const __be32 *)of_get_property(of_node, "port0_host_plug_detect",NULL));
+ }
+ pr_info("port_host_plug_detect[0]:%d\n", port_host_plug_detect[0]);
+
+ if (!of_find_property(of_node, "vbus_otg_en_gpio", NULL)) {
+ pr_debug("can't find vbus_otg0_en_gpio config\n");
+ vbus_otg_en_gpio[0][0] = -1;
+ } else {
+ vbus_otg_en_gpio[0][0] = of_get_named_gpio_flags(of_node, "vbus_otg_en_gpio",0, &flags);
+ vbus_otg_en_gpio[0][1] = flags & 0x01;
+ if (gpio_request(vbus_otg_en_gpio[0][0], aotg_hcd_of_match[0].compatible))
+ pr_debug("fail to request vbus gpio [%d]\n", vbus_otg_en_gpio[0][0]);
+ if (port_host_plug_detect[0] != 2)
+ gpio_direction_output(vbus_otg_en_gpio[0][0], !!port_host_plug_detect[0]);
+ }
+ pr_info("port0_vubs_en:%d\n",vbus_otg_en_gpio[0][0]);
+ }
+ else {
+ pr_debug("can't find usbh0 dts node\n");
+ }
+
+ of_node = of_find_compatible_node(NULL, NULL, "actions,owl-usb-2.0-1");
+ if (of_node) {
+ if (!of_find_property(of_node, "port1_host_plug_detect", NULL)) {
+ pr_info("can't find port1_host_plug_detect config\n");
+ port_host_plug_detect[1] = 0;
+ } else {
+ port_host_plug_detect[1] = be32_to_cpup((const __be32 *)of_get_property(of_node, "port1_host_plug_detect",NULL));
+ }
+ pr_info("port_host_plug_detect[1]:%d\n", port_host_plug_detect[1]);
+
+ if (!of_find_property(of_node, "vbus_otg_en_gpio", NULL)) {
+ printk("can't find vbus_otg1_en_gpio config\n");
+ vbus_otg_en_gpio[1][0] = -1;
+ } else {
+ vbus_otg_en_gpio[1][0] = of_get_named_gpio_flags(of_node, "vbus_otg_en_gpio",0, &flags);
+ vbus_otg_en_gpio[1][1] = flags & 0x01;
+ if (gpio_request(vbus_otg_en_gpio[1][0], aotg_hcd_of_match[1].compatible))
+ pr_debug("fail to request vbus gpio [%d]\n", vbus_otg_en_gpio[1][0]);
+ if (port_host_plug_detect[1] != 2)
+ gpio_direction_output(vbus_otg_en_gpio[1][0], !!port_host_plug_detect[1]);
+ }
+ pr_info("port1_vubs_en:%d\n",vbus_otg_en_gpio[1][0]);
+ }
+ else {
+ pr_debug("can't find usbh1 dts node\n");
+ }
+
+ if (port_host_plug_detect[0]) {
+ aotg_uhost_mon0 = aotg_uhost_mon_alloc();
+ aotg_uhost_mon0->id = 0;
+ aotg_uhost_mon0->aotg_dev_onoff = create_singlethread_workqueue("aotg_dev0_onoff");
+ aotg_uhost_mon0->usbecs = (void __iomem *)IO_ADDRESS(USBH0_ECS);
+ aotg_uhost_mon0->usbpll = (void __iomem *)IO_ADDRESS(CMU_USBPLL);
+
+ owl_powergate_power_on(OWL_POWERGATE_USB2_0);
+ usb_setbitsl(USB2_PLL_EN0,aotg_uhost_mon0->usbpll);
+ usb_setbitsl(USB2_PHYCLK_EN0,aotg_uhost_mon0->usbpll);
+ usb_setbitsl(USB2_ECS_PLL_LDO_EN,aotg_uhost_mon0->usbecs);
+ usb2_set_dp_500k_15k(aotg_uhost_mon0, 0, 1);
+ wake_lock_init(&aotg_uhost_mon0->aotg_wake_lock, WAKE_LOCK_SUSPEND, "aotg_wake_lock0");
+ printk("start mon 0 ......\n");
+ mod_timer(&aotg_uhost_mon0->hotplug_timer, jiffies + msecs_to_jiffies(10000));
+ }
+ if (port_host_plug_detect[1]) {
+ aotg_uhost_mon1 = aotg_uhost_mon_alloc();
+ aotg_uhost_mon1->id = 1;
+ aotg_uhost_mon1->aotg_dev_onoff = create_singlethread_workqueue("aotg_dev1_onoff");
+ aotg_uhost_mon1->usbecs = (void __iomem *)IO_ADDRESS(USBH1_ECS);
+ aotg_uhost_mon1->usbpll = (void __iomem *)IO_ADDRESS(CMU_USBPLL);
+
+ owl_powergate_power_on(OWL_POWERGATE_USB2_1);
+ usb_setbitsl(USB2_PLL_EN1,aotg_uhost_mon1->usbpll);
+ usb_setbitsl(USB2_PHYCLK_EN1,aotg_uhost_mon1->usbpll);
+ usb_setbitsl(USB2_ECS_PLL_LDO_EN,aotg_uhost_mon1->usbecs);
+ usb2_set_dp_500k_15k(aotg_uhost_mon1, 0, 1);
+ wake_lock_init(&aotg_uhost_mon1->aotg_wake_lock, WAKE_LOCK_SUSPEND, "aotg_wake_lock1");
+ printk("start mon 1 ......\n");
+ mod_timer(&aotg_uhost_mon1->hotplug_timer, jiffies + msecs_to_jiffies(10000));
+ }
+
+ return;
+}
+
+static int inline aotg_uhost_mon_free(struct aotg_uhost_mon_t *umon)
+{
+ if (!umon)
+ return -1;
+
+ if (umon->id) {
+ usb_clearbitsl(USB2_PLL_EN1,aotg_uhost_mon1->usbpll);
+ owl_powergate_power_off(OWL_POWERGATE_USB2_1);
+ } else {
+ usb_clearbitsl(USB2_PLL_EN0,aotg_uhost_mon0->usbpll);
+ owl_powergate_power_off(OWL_POWERGATE_USB2_0);
+ }
+
+ if (umon->aotg_dev_onoff) {
+ cancel_delayed_work_sync(&umon->aotg_dev_init);
+ cancel_delayed_work_sync(&umon->aotg_dev_exit);
+ flush_workqueue(umon->aotg_dev_onoff);
+ destroy_workqueue(umon->aotg_dev_onoff);
+ }
+ wake_unlock(&umon->aotg_wake_lock);
+ del_timer_sync(&umon->hotplug_timer);
+ kfree(umon);
+ return 0;
+}
+
+void aotg_uhost_mon_exit(void)
+{
+ aotg_power_onoff(0,0);
+ aotg_power_onoff(1,0);
+
+ aotg_uhost_mon_free(aotg_uhost_mon0);
+ aotg_uhost_mon_free(aotg_uhost_mon1);
+ aotg_uhost_mon0 = NULL;
+ aotg_uhost_mon1 = NULL;
+ return;
+}
+
+
diff --git a/drivers/usb/host/aotg_mon.h b/drivers/usb/host/aotg_mon.h
new file mode 100644
index 0000000..37e9a69c
--- /dev/null
+++ b/drivers/usb/host/aotg_mon.h
@@ -0,0 +1,11 @@
+#ifndef __AOTG_UHOST_MON_H__
+#define __AOTG_UHOST_MON_H__
+
+void aotg_dev_plugout_msg(int id);
+extern int port_host_plug_detect[2];
+
+void aotg_uhost_mon_init(void);
+void aotg_uhost_mon_exit(void);
+
+#endif /* __AOTG_UHOST_MON_H__ */
+
diff --git a/drivers/usb/host/aotg_plat_data.h b/drivers/usb/host/aotg_plat_data.h
new file mode 100644
index 0000000..26e36c6
--- /dev/null
+++ b/drivers/usb/host/aotg_plat_data.h
@@ -0,0 +1,22 @@
+
+#ifndef __AOTG_PLAT_DATA_H__
+#define __AOTG_PLAT_DATA_H__
+
+struct aotg_plat_data {
+ void __iomem *usbecs;
+ void __iomem *usbpll;
+ u32 usbpll_bits;
+ void __iomem *devrst;
+ u32 devrst_bits;
+ int no_hs;
+};
+
+int aotg0_device_init(int power_only);
+void aotg0_device_exit(int power_only);
+
+int aotg1_device_init(int power_only);
+void aotg1_device_exit(int power_only);
+extern void aotg_hub_unregister(int dev_id);
+extern int aotg_hub_register(int dev_id);
+
+#endif
diff --git a/drivers/usb/host/aotg_regs.h b/drivers/usb/host/aotg_regs.h
new file mode 100644
index 0000000..a286b9b
--- /dev/null
+++ b/drivers/usb/host/aotg_regs.h
@@ -0,0 +1,1527 @@
+/*
+ * for Actions AOTG
+ *
+ */
+
+#ifndef __AOTG_REGS_H__
+#define __AOTG_REGS_H__
+
+//#include <mach/hardware.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+//#include <mach/irqs.h>
+#include <mach/hardware.h>
+
+#define USBH_BASE0 0xB0600000
+#define USBH_BASE1 0xB0700000
+
+#define AOTG_REGS_SIZE (64*1024) //64k
+
+#define HCIN0BC 0x00000000
+#define HCOUT0BC 0x00000001
+#define EP0CS 0x00000002
+
+#define HCIN1BC 0x00000008
+#define HCIN2BC 0x00000010
+#define HCIN3BC 0x00000018
+#define HCIN4BC 0x00000020
+#define HCIN5BC 0x00000028
+#define HCIN6BC 0x00000030
+#define HCIN7BC 0x00000038
+#define HCIN8BC 0x00000040
+#define HCIN9BC 0x00000048
+#define HCIN10BC 0x00000050
+#define HCIN11BC 0x00000058
+#define HCIN12BC 0x00000060
+#define HCIN13BC 0x00000068
+#define HCIN14BC 0x00000070
+#define HCIN15BC 0x00000078
+
+#define HCIN1BCL 0x00000008
+#define HCIN2BCL 0x00000010
+#define HCIN3BCL 0x00000018
+#define HCIN4BCL 0x00000020
+#define HCIN5BCL 0x00000028
+#define HCIN6BCL 0x00000030
+#define HCIN7BCL 0x00000038
+#define HCIN8BCL 0x00000040
+#define HCIN9BCL 0x00000048
+#define HCIN10BCL 0x00000050
+#define HCIN11BCL 0x00000058
+#define HCIN12BCL 0x00000060
+#define HCIN13BCL 0x00000068
+#define HCIN14BCL 0x00000070
+#define HCIN15BCL 0x00000078
+
+#define HCIN1BCH 0x00000009
+#define HCIN2BCH 0x00000011
+#define HCIN3BCH 0x00000019
+#define HCIN4BCH 0x00000021
+#define HCIN5BCH 0x00000029
+#define HCIN6BCH 0x00000031
+#define HCIN7BCH 0x00000039
+#define HCIN8BCH 0x00000041
+#define HCIN9BCH 0x00000049
+#define HCIN10BCH 0x00000051
+#define HCIN11BCH 0x00000059
+#define HCIN12BCH 0x00000061
+#define HCIN13BCH 0x00000069
+#define HCIN14BCH 0x00000071
+#define HCIN15BCH 0x00000079
+
+#define HCIN1CON 0x0000000A
+#define HCIN2CON 0x00000012
+#define HCIN3CON 0x0000001A
+#define HCIN4CON 0x00000022
+#define HCIN5CON 0x0000002A
+#define HCIN6CON 0x00000032
+#define HCIN7CON 0x0000003A
+#define HCIN8CON 0x00000042
+#define HCIN9CON 0x0000004A
+#define HCIN10CON 0x00000052
+#define HCIN11CON 0x0000005A
+#define HCIN12CON 0x00000062
+#define HCIN13CON 0x0000006A
+#define HCIN14CON 0x00000072
+#define HCIN15CON 0x0000007A
+
+#define HCIN1CS 0x0000000B
+#define HCIN2CS 0x00000013
+#define HCIN3CS 0x0000001B
+#define HCIN4CS 0x00000023
+#define HCIN5CS 0x0000002B
+#define HCIN6CS 0x00000033
+#define HCIN7CS 0x0000003B
+#define HCIN8CS 0x00000043
+#define HCIN9CS 0x0000004B
+#define HCIN10CS 0x00000053
+#define HCIN11CS 0x0000005B
+#define HCIN12CS 0x00000063
+#define HCIN13CS 0x0000006B
+#define HCIN14CS 0x00000073
+#define HCIN15CS 0x0000007B
+
+#define HCOUT1BC 0x0000000C
+#define HCOUT2BC 0x00000014
+#define HCOUT3BC 0x0000001C
+#define HCOUT4BC 0x00000024
+#define HCOUT5BC 0x0000002C
+#define HCOUT6BC 0x00000034
+#define HCOUT7BC 0x0000003C
+#define HCOUT8BC 0x00000044
+#define HCOUT9BC 0x0000004C
+#define HCOUT10BC 0x00000054
+#define HCOUT11BC 0x0000005C
+#define HCOUT12BC 0x00000064
+#define HCOUT13BC 0x0000006C
+#define HCOUT14BC 0x00000074
+#define HCOUT15BC 0x0000007C
+
+#define HCOUT1BCL 0x0000000C
+#define HCOUT2BCL 0x00000014
+#define HCOUT3BCL 0x0000001C
+#define HCOUT4BCL 0x00000024
+#define HCOUT5BCL 0x0000002C
+#define HCOUT6BCL 0x00000034
+#define HCOUT7BCL 0x0000003C
+#define HCOUT8BCL 0x00000044
+#define HCOUT9BCL 0x0000004C
+#define HCOUT10BCL 0x00000054
+#define HCOUT11BCL 0x0000005C
+#define HCOUT12BCL 0x00000064
+#define HCOUT13BCL 0x0000006C
+#define HCOUT14BCL 0x00000074
+#define HCOUT15BCL 0x0000007C
+
+#define HCOUT1BCH 0x0000000D
+#define HCOUT2BCH 0x00000015
+#define HCOUT3BCH 0x0000001D
+#define HCOUT4BCH 0x00000025
+#define HCOUT5BCH 0x0000002D
+#define HCOUT6BCH 0x00000035
+#define HCOUT7BCH 0x0000003D
+#define HCOUT8BCH 0x00000045
+#define HCOUT9BCH 0x0000004D
+#define HCOUT10BCH 0x00000055
+#define HCOUT11BCH 0x0000005D
+#define HCOUT12BCH 0x00000065
+#define HCOUT13BCH 0x0000006D
+#define HCOUT14BCH 0x00000075
+#define HCOUT15BCH 0x0000007D
+
+#define HCOUT1CON 0x0000000E
+#define HCOUT2CON 0x00000016
+#define HCOUT3CON 0x0000001E
+#define HCOUT4CON 0x00000026
+#define HCOUT5CON 0x0000002E
+#define HCOUT6CON 0x00000036
+#define HCOUT7CON 0x0000003E
+#define HCOUT8CON 0x00000046
+#define HCOUT9CON 0x0000004E
+#define HCOUT10CON 0x00000056
+#define HCOUT11CON 0x0000005E
+#define HCOUT12CON 0x00000066
+#define HCOUT13CON 0x0000006E
+#define HCOUT14CON 0x00000076
+#define HCOUT15CON 0x0000007E
+
+#define HCOUT1CS 0x0000000F
+#define HCOUT2CS 0x00000017
+#define HCOUT3CS 0x0000001F
+#define HCOUT4CS 0x00000027
+#define HCOUT5CS 0x0000002F
+#define HCOUT6CS 0x00000037
+#define HCOUT7CS 0x0000003F
+#define HCOUT8CS 0x00000047
+#define HCOUT9CS 0x0000004F
+#define HCOUT10CS 0x00000057
+#define HCOUT11CS 0x0000005F
+#define HCOUT12CS 0x00000067
+#define HCOUT13CS 0x0000006F
+#define HCOUT14CS 0x00000077
+#define HCOUT15CS 0x0000007F
+
+#define HCEP0CTRL 0x000000C0
+#define HCOUT1CTRL 0x000000C4
+#define HCOUT2CTRL 0x000000C8
+#define HCOUT3CTRL 0x000000CC
+#define HCOUT4CTRL 0x000000D0
+#define HCOUT5CTRL 0x000000D4
+#define HCOUT6CTRL 0x000000D8
+#define HCOUT7CTRL 0x000000DC
+#define HCOUT8CTRL 0x000000E0
+#define HCOUT9CTRL 0x000000E4
+#define HCOUT10CTRL 0x000000E8
+#define HCOUT11CTRL 0x000000EC
+#define HCOUT12CTRL 0x000000F0
+#define HCOUT13CTRL 0x000000F4
+#define HCOUT14CTRL 0x000000F8
+#define HCOUT15CTRL 0x000000FC
+
+#define HCOUT0ERR 0x000000C1
+#define HCOUT1ERR 0x000000C5
+#define HCOUT2ERR 0x000000C9
+#define HCOUT3ERR 0x000000CD
+#define HCOUT4ERR 0x000000D1
+#define HCOUT5ERR 0x000000D5
+#define HCOUT6ERR 0x000000D9
+#define HCOUT7ERR 0x000000DD
+#define HCOUT8ERR 0x000000E1
+#define HCOUT9ERR 0x000000E5
+#define HCOUT10ERR 0x000000E9
+#define HCOUT11ERR 0x000000ED
+#define HCOUT12ERR 0x000000F1
+#define HCOUT13ERR 0x000000F5
+#define HCOUT14ERR 0x000000F9
+#define HCOUT15ERR 0x000000FD
+
+#define HCIN1CTRL 0x000000C6
+#define HCIN2CTRL 0x000000CA
+#define HCIN3CTRL 0x000000CE
+#define HCIN4CTRL 0x000000D2
+#define HCIN5CTRL 0x000000D6
+#define HCIN6CTRL 0x000000DA
+#define HCIN7CTRL 0x000000DE
+#define HCIN8CTRL 0x000000E2
+#define HCIN9CTRL 0x000000E6
+#define HCIN10CTRL 0x000000EA
+#define HCIN11CTRL 0x000000EE
+#define HCIN12CTRL 0x000000F2
+#define HCIN13CTRL 0x000000F6
+#define HCIN14CTRL 0x000000FA
+#define HCIN15CTRL 0x000000FE
+
+#define HCIN0ERR 0x000000C3
+#define HCIN1ERR 0x000000C7
+#define HCIN2ERR 0x000000CB
+#define HCIN3ERR 0x000000CF
+#define HCIN4ERR 0x000000D3
+#define HCIN5ERR 0x000000D7
+#define HCIN6ERR 0x000000DB
+#define HCIN7ERR 0x000000DF
+#define HCIN8ERR 0x000000E3
+#define HCIN9ERR 0x000000E7
+#define HCIN10ERR 0x000000EB
+#define HCIN11ERR 0x000000EF
+#define HCIN12ERR 0x000000F3
+#define HCIN13ERR 0x000000F7
+#define HCIN14ERR 0x000000FB
+#define HCIN15ERR 0x000000FF
+
+#define EP0INDATA_W0 0x00000100
+#define EP0INDATA_W1 0x00000104
+#define EP0INDATA_W2 0x00000108
+#define EP0INDATA_W3 0x0000010C
+#define EP0INDATA_W4 0x00000110
+#define EP0INDATA_W5 0x00000114
+#define EP0INDATA_W6 0x00000118
+#define EP0INDATA_W7 0x0000011C
+#define EP0INDATA_W8 0x00000120
+#define EP0INDATA_W9 0x00000124
+#define EP0INDATA_W10 0x00000128
+#define EP0INDATA_W11 0x0000012C
+#define EP0INDATA_W12 0x00000130
+#define EP0INDATA_W13 0x00000134
+#define EP0INDATA_W14 0x00000138
+#define EP0INDATA_W15 0x0000013C
+#define EP0OUTDATA_W0 0x00000140
+#define EP0OUTDATA_W1 0x00000144
+#define EP0OUTDATA_W2 0x00000148
+#define EP0OUTDATA_W3 0x0000014C
+#define EP0OUTDATA_W4 0x00000150
+#define EP0OUTDATA_W5 0x00000154
+#define EP0OUTDATA_W6 0x00000158
+#define EP0OUTDATA_W7 0x0000015C
+#define EP0OUTDATA_W8 0x00000160
+#define EP0OUTDATA_W9 0x00000164
+#define EP0OUTDATA_W10 0x00000168
+#define EP0OUTDATA_W11 0x0000016C
+#define EP0OUTDATA_W12 0x00000170
+#define EP0OUTDATA_W13 0x00000174
+#define EP0OUTDATA_W14 0x00000178
+#define EP0OUTDATA_W15 0x0000017C
+#define SETUPDATA_W0 0x00000180
+#define SETUPDATA_W1 0x00000184
+
+
+#if 0
+/////////////////////////////////////////////////////
+/******* for device. *****************************/
+/////////////////////////////////////////////////////
+#define OUT0BC 0x00000000
+#define IN0BC 0x00000001
+
+#define OUT1BCL 0x00000008
+#define OUT1BCH 0x00000009
+#define OUT1CON 0x0000000A
+#define OUT1CS 0x0000000B
+#define IN1BCL 0x0000000C
+#define IN1BCH 0x0000000D
+#define IN1CON 0x0000000E
+#define IN1CS 0x0000000F
+#define OUT2BCL 0x00000010
+#define OUT2BCH 0x00000011
+#define OUT2CON 0x00000012
+#define OUT2CS 0x00000013
+#define IN2BCL 0x00000014
+#define IN2BCH 0x00000015
+#define IN2CON 0x00000016
+#define IN2CS 0x00000017
+#define OUT3BCL 0x00000018
+#define OUT3BCH 0x00000019
+#define OUT3CON 0x0000001A
+#define OUT3CS 0x0000001B
+#define IN3BCL 0x0000001C
+#define IN3BCH 0x0000001D
+#define IN3CON 0x0000001E
+#define IN3CS 0x0000001F
+#define OUT4BCL 0x00000020
+#define OUT4BCH 0x00000021
+#define OUT4CON 0x00000022
+#define OUT4CS 0x00000023
+#define IN4BCL 0x00000024
+#define IN4BCH 0x00000025
+#define IN4CON 0x00000026
+#define IN4CS 0x00000027
+#define OUT5BCL 0x00000028
+#define OUT5BCH 0x00000029
+#define OUT5CON 0x0000002A
+#define OUT5CS 0x0000002B
+#define IN5BCL 0x0000002C
+#define IN5BCH 0x0000002D
+#define IN5CON 0x0000002E
+#define IN5CS 0x0000002F
+
+//#define FIFO1DATA 0x00000084
+//#define FIFO2DATA 0x00000088
+//#define FIFO3DATA 0x0000008C
+//#define FIFO4DATA 0x00000090
+//#define FIFO5DATA 0x00000094
+//#define EP0INDAT 0x00000100
+//#define HCEP0OUTDAT 0x00000100
+#endif
+
+
+#if 0
+/*************** for 0-7 ep to 0-15 ep. *****************/
+//#define IN07IRQ 0x00000188
+//#define HCOUT07IRQ 0x00000188
+//#define OUT07IRQ 0x0000018A
+//#define HCIN07IRQ 0x0000018A
+//#define USBIRQ 0x0000018C
+//#define OUT07PNGIRQ 0x0000018E
+//#define INTXKIRQ 0x00000190
+//#define OUTXTOKIRQ 0x00000190
+//#define OUT07EMPTIRQ 0x00000191
+//#define HCIN07EMPTIRQ 0x00000191
+//#define IN07IEN 0x00000194
+//#define HCOUT07IEN 0x00000194
+//#define OUT07IEN 0x00000196
+//#define HCIN07IEN 0x00000196
+//#define USBIEN 0x00000198
+//#define OUT07PNGIEN 0x0000019A
+//#define INTXKIEN 0x0000019C
+//#define OUTXTOKIEN 0x0000019D
+#endif
+
+#define HCOUTxIRQ0 0x00000188
+#define HCOUTxIRQ1 0x00000189
+#define HCINxIRQ0 0x0000018A
+#define HCINxIRQ1 0x0000018B
+#define USBIRQ 0x0000018C
+#define HCINxPNGIRQ0 0x0000018E
+#define HCINxPNGIRQ1 0x0000018F
+#define HCOUTxTOKIRQ0 0x00000190
+#define HCOUTxTOKIRQ1 0x00000191
+#define HCINxTOKIRQ0 0x00000192
+#define HCINxTOKIRQ1 0x00000193
+#define HCOUTxIEN0 0x00000194
+#define HCOUTxIEN1 0x00000195
+#define HCINxIEN0 0x00000196
+#define HCINxIEN1 0x00000197
+#define USBIEN 0x00000198
+#define HCINxPNGIEN0 0x0000019A
+#define HCINxPNGIEN1 0x0000019B
+#define HCOUTxTOKIEN0 0x0000019C
+#define HCOUTxTOKIEN1 0x0000019D
+#define HCINxTOKIEN0 0x0000019E
+#define HCINxTOKIEN1 0x0000019F
+
+#define IVECT 0x000001A0
+#define ENDPRST 0x000001A2
+//#define HCENDPRST 0x000001A2
+#define USBCS 0x000001A3
+#define FRMNRL 0x000001A4
+#define FRMNRH 0x000001A5
+//#define FRMNFH 0x000001A5
+#define FNADDR 0x000001A6
+#define CLKGATE 0x000001A7
+//#define FIFOCTRL 0x000001A8
+#define HCTRAINTERVAL 0x000001A8
+#define HCPORTCTRL 0x000001AB
+#define HCFRMNRL 0x000001AC
+#define HCFRMNRH 0x000001AD
+#define HCFRMREMAINL 0x000001AE
+#define HCFRMREMAINH 0x000001AF
+
+#if 0
+/************** ep0-7 to ep0-15 ******************/
+//#define HCIN07ERRIRQ 0x000001B4
+//#define HCOUT07ERRIRQ 0x000001B6
+//#define HCIN07ERRIEN 0x000001B8
+//#define HCOUT07ERRIEN 0x000001BA
+#endif
+#define HCINxERRIRQ0 0x000001B4
+#define HCINxERRIRQ1 0x000001B5
+#define HCOUTxERRIRQ0 0x000001B6
+#define HCOUTxERRIRQ1 0x000001B7
+#define HCINxERRIEN0 0x000001B8
+#define HCINxERRIEN1 0x000001B9
+#define HCOUTxERRIEN0 0x000001BA
+#define HCOUTxERRIEN1 0x000001BB
+
+#define OTGIRQ 0x000001BC
+#define OTGSTATE 0x000001BD
+#define OTGCTRL 0x000001BE
+#define OTGSTATUS 0x000001BF
+#define OTGIEN 0x000001C0
+#define TAAIDLBDIS 0x000001C1
+#define TAWAITBCON 0x000001C2
+#define TBVBUSPLS 0x000001C3
+//#define TBVBUSDISCHPLS 0x000001C7
+#define TBVBUSDISPLS 0x000001C7
+
+#define HCIN0MAXPCK 0x000001E0
+#define HCIN1MAXPCK 0x000001E2
+#define HCIN2MAXPCK 0x000001E4
+#define HCIN3MAXPCK 0x000001E6
+#define HCIN4MAXPCK 0x000001E8
+#define HCIN5MAXPCK 0x000001EA
+#define HCIN6MAXPCK 0x000001EC
+#define HCIN7MAXPCK 0x000001EE
+#define HCIN8MAXPCK 0x000001F0
+#define HCIN9MAXPCK 0x000001F2
+#define HCIN10MAXPCK 0x000001F4
+#define HCIN11MAXPCK 0x000001F6
+#define HCIN12MAXPCK 0x000001F8
+#define HCIN13MAXPCK 0x000001FA
+#define HCIN14MAXPCK 0x000001FC
+#define HCIN15MAXPCK 0x000001FE
+#define HCIN1MAXPCKL 0x000001E2
+#define HCIN2MAXPCKL 0x000001E4
+#define HCIN3MAXPCKL 0x000001E6
+#define HCIN4MAXPCKL 0x000001E8
+#define HCIN5MAXPCKL 0x000001EA
+#define HCIN6MAXPCKL 0x000001EC
+#define HCIN7MAXPCKL 0x000001EE
+#define HCIN8MAXPCKL 0x000001F0
+#define HCIN9MAXPCKL 0x000001F2
+#define HCIN10MAXPCKL 0x000001F4
+#define HCIN11MAXPCKL 0x000001F6
+#define HCIN12MAXPCKL 0x000001F8
+#define HCIN13MAXPCKL 0x000001FA
+#define HCIN14MAXPCKL 0x000001FC
+#define HCIN15MAXPCKL 0x000001FE
+#define HCIN1MAXPCKH 0x000001E3
+#define HCIN2MAXPCKH 0x000001E5
+#define HCIN3MAXPCKH 0x000001E7
+#define HCIN4MAXPCKH 0x000001E9
+#define HCIN5MAXPCKH 0x000001EB
+#define HCIN6MAXPCKH 0x000001ED
+#define HCIN7MAXPCKH 0x000001EF
+#define HCIN8MAXPCKH 0x000001F1
+#define HCIN9MAXPCKH 0x000001F3
+#define HCIN10MAXPCKH 0x000001F5
+#define HCIN11MAXPCKH 0x000001F7
+#define HCIN12MAXPCKH 0x000001F9
+#define HCIN13MAXPCKH 0x000001FB
+#define HCIN14MAXPCKH 0x000001FD
+#define HCIN15MAXPCKH 0x000001FF
+
+#define HCEP0BINTERVAL 0x00000200
+#define HCIN1BINTERVAL 0x00000208
+#define HCIN2BINTERVAL 0x00000210
+#define HCIN3BINTERVAL 0x00000218
+#define HCIN4BINTERVAL 0x00000220
+#define HCIN5BINTERVAL 0x00000228
+#define HCIN6BINTERVAL 0x00000230
+#define HCIN7BINTERVAL 0x00000238
+#define HCIN8BINTERVAL 0x00000240
+#define HCIN9BINTERVAL 0x00000248
+#define HCIN10BINTERVAL 0x00000250
+#define HCIN11BINTERVAL 0x00000258
+#define HCIN12BINTERVAL 0x00000260
+#define HCIN13BINTERVAL 0x00000268
+#define HCIN14BINTERVAL 0x00000270
+#define HCIN15BINTERVAL 0x00000278
+#define HCEP0ADDR 0x201
+#define HCIN1ADDR 0x00000209
+#define HCIN2ADDR 0x00000211
+#define HCIN3ADDR 0x00000219
+#define HCIN4ADDR 0x00000221
+#define HCIN5ADDR 0x00000229
+#define HCIN6ADDR 0x00000231
+#define HCIN7ADDR 0x00000239
+#define HCIN8ADDR 0x00000241
+#define HCIN9ADDR 0x00000249
+#define HCIN10ADDR 0x00000251
+#define HCIN11ADDR 0x00000259
+#define HCIN12ADDR 0x00000261
+#define HCIN13ADDR 0x00000269
+#define HCIN14ADDR 0x00000271
+#define HCIN15ADDR 0x00000279
+#define HCEP0PORT 0x00000202
+#define HCIN1PORT 0x0000020A
+#define HCIN2PORT 0x00000212
+#define HCIN3PORT 0x0000021A
+#define HCIN4PORT 0x00000222
+#define HCIN5PORT 0x0000022A
+#define HCIN6PORT 0x00000232
+#define HCIN7PORT 0x0000023A
+#define HCIN8PORT 0x00000242
+#define HCIN9PORT 0x0000024A
+#define HCIN10PORT 0x00000252
+#define HCIN11PORT 0x0000025A
+#define HCIN12PORT 0x00000262
+#define HCIN13PORT 0x0000026A
+#define HCIN14PORT 0x00000272
+#define HCIN15PORT 0x0000027A
+#define HCEP0SPILITCS 0x00000203
+#define HCIN1SPILITCS 0x0000020B
+#define HCIN2SPILITCS 0x00000213
+#define HCIN3SPILITCS 0x0000021B
+#define HCIN4SPILITCS 0x00000223
+#define HCIN5SPILITCS 0x0000022B
+#define HCIN6SPILITCS 0x00000233
+#define HCIN7SPILITCS 0x0000023B
+#define HCIN8SPILITCS 0x00000243
+#define HCIN9SPILITCS 0x0000024B
+#define HCIN10SPILITCS 0x00000253
+#define HCIN11SPILITCS 0x0000025B
+#define HCIN12SPILITCS 0x00000263
+#define HCIN13SPILITCS 0x0000026B
+#define HCIN14SPILITCS 0x00000273
+#define HCIN15SPILITCS 0x0000027B
+#define HCOUT1BINTERVAL 0x00000288
+#define HCOUT2BINTERVAL 0x00000290
+#define HCOUT3BINTERVAL 0x00000298
+#define HCOUT4BINTERVAL 0x000002A0
+#define HCOUT5BINTERVAL 0x000002A8
+#define HCOUT6BINTERVAL 0x000002B0
+#define HCOUT7BINTERVAL 0x000002B8
+#define HCOUT8BINTERVAL 0x000002C0
+#define HCOUT9BINTERVAL 0x000002C8
+#define HCOUT10BINTERVAL 0x000002D0
+#define HCOUT11BINTERVAL 0x000002D8
+#define HCOUT12BINTERVAL 0x000002E0
+#define HCOUT13BINTERVAL 0x000002E8
+#define HCOUT14BINTERVAL 0x000002F0
+#define HCOUT15BINTERVAL 0x000002F8
+#define HCOUT1ADDR 0x00000289
+#define HCOUT2ADDR 0x00000291
+#define HCOUT3ADDR 0x00000299
+#define HCOUT4ADDR 0x000002A1
+#define HCOUT5ADDR 0x000002A9
+#define HCOUT6ADDR 0x000002B1
+#define HCOUT7ADDR 0x000002B9
+#define HCOUT8ADDR 0x000002C1
+#define HCOUT9ADDR 0x000002C9
+#define HCOUT10ADDR 0x000002D1
+#define HCOUT11ADDR 0x000002D9
+#define HCOUT12ADDR 0x000002E1
+#define HCOUT13ADDR 0x000002E9
+#define HCOUT14ADDR 0x000002F1
+#define HCOUT15ADDR 0x000002F9
+#define HCOUT1PORT 0x0000028A
+#define HCOUT2PORT 0x00000292
+#define HCOUT3PORT 0x0000029A
+#define HCOUT4PORT 0x000002A2
+#define HCOUT5PORT 0x000002AA
+#define HCOUT6PORT 0x000002B2
+#define HCOUT7PORT 0x000002BA
+#define HCOUT8PORT 0x000002C2
+#define HCOUT9PORT 0x000002CA
+#define HCOUT10PORT 0x000002D2
+#define HCOUT11PORT 0x000002DA
+#define HCOUT12PORT 0x000002E2
+#define HCOUT13PORT 0x000002EA
+#define HCOUT14PORT 0x000002F2
+#define HCOUT15PORT 0x000002FA
+#define HCOUT1SPILITCS 0x0000028B
+#define HCOUT2SPILITCS 0x00000293
+#define HCOUT3SPILITCS 0x0000029B
+#define HCOUT4SPILITCS 0x000002A3
+#define HCOUT5SPILITCS 0x000002AB
+#define HCOUT6SPILITCS 0x000002B3
+#define HCOUT7SPILITCS 0x000002BB
+#define HCOUT8SPILITCS 0x000002C3
+#define HCOUT9SPILITCS 0x000002CB
+#define HCOUT10SPILITCS 0x000002D3
+#define HCOUT11SPILITCS 0x000002DB
+#define HCOUT12SPILITCS 0x000002E3
+#define HCOUT13SPILITCS 0x000002EB
+#define HCOUT14SPILITCS 0x000002F3
+#define HCOUT15SPILITCS 0x000002FB
+
+#if 0
+/************* replaced by new register define. ************/
+#define OUT1STARTADDRESS 0x00000304
+#define OUT1STARTADDRESSL 0x00000304
+#define OUT1STARTADDRESSH 0x00000305
+#define OUT2STARTADDRESS 0x00000308
+#define OUT2STARTADDRESSL 0x00000308
+
+#define OUT3STADDR 0x0000030C
+#define OUT4STADDR 0x00000310
+#define OUT5STADDR 0x00000314
+
+#define OUT2STARTADDRESSH 0x00000309
+#define IN1STARTADDRESS 0x00000344
+#define IN1STARTADDRESSL 0x00000344
+#define IN1STARTADDRESSH 0x00000345
+#define IN2STARTADDRESS 0x00000348
+#define IN2STARTADDRESSL 0x00000348
+#define IN2STARTADDRESSH 0x00000349
+
+#define IN3STADDR 0x0000034C
+#define IN4STADDR 0x00000350
+#define IN5STADDR 0x00000354
+
+#define HCOUT0MAXPCK 0x000003E0
+#define HCOUT1MAXPCKL 0x000003E2
+#define HCOUT1MAXPCKH 0x000003E3
+#define HCOUT2MAXPCKL 0x000003E4
+#define HCOUT2MAXPCKH 0x000003E5
+#define HCOUT3MAXPCKL 0x000003E6
+#define HCOUT3MAXPCKH 0x000003E7
+#define HCOUT4MAXPCKL 0x000003E8
+#define HCOUT4MAXPCKH 0x000003E9
+#define HCOUT5MAXPCKL 0x000003EA
+#define HCOUT5MAXPCKH 0x000003EB
+
+//#define USBERESET 0x00000400
+#define TA_BCON_COUNT 0x00000401
+#define VBUSDBCTIMERL 0x00000402
+#define VBUSDBCTIMERH 0x00000403
+#define VDCTRL 0x00000404
+#define VDSTATE 0x00000405
+#define BKDOOR 0x00000406
+#define DBGMODE 0x00000407
+#define SRPCTRL 0x00000408
+//#define USBEIRQ 0x0000040A
+#define USBEIEN 0x0000040C
+#define UDMAIRQ 0x0000040E
+#define UDMAIEN 0x0000040F
+#define OUTXSHORTPCKIRQ 0x00000410
+#define OUTXSHORTPCKIEN 0x00000412
+#define OUTXNAKCTRL 0x00000414
+#define HCINXSTART 0x00000416
+#define HCINXENDIRQ 0x00000418
+#define HCINXENDIEN 0x0000041A
+
+/* HCINxCounter\BCĴ\E6\C6\F7\B5\C4д\C8\EB\B5\D8ַΪ0x420,0x424,0x428,0x42c,0x430,\B6\C1ȡ\B5\D8ַΪ0x420\A3\AC0x422,0x424,0x426,0x428\A1\A3*/
+//#define HCIN1_COUNTL 0x00000420
+//#define HCIN1_COUNTH 0x00000421
+//#define HCIN2_COUNTL 0x00000422
+//#define HCIN2_COUNTH 0x00000423
+//#define HCIN3_COUNTL 0x00000424
+//#define HCIN3_COUNTH 0x00000425
+//#define HCIN4_COUNTL 0x00000426
+//#define HCIN4_COUNTH 0x00000427
+//#define HCIN5_COUNTL 0x00000428
+//#define HCIN5_COUNTH 0x00000429
+#define HCIN1_COUNTL 0x00000420
+#define HCIN1_COUNTH 0x00000421
+#define HCIN2_COUNTL 0x00000424
+#define HCIN2_COUNTH 0x00000425
+#define HCIN3_COUNTL 0x00000428
+#define HCIN3_COUNTH 0x00000429
+#define HCIN4_COUNTL 0x0000042c
+#define HCIN4_COUNTH 0x0000042d
+#define HCIN5_COUNTL 0x00000430
+#define HCIN5_COUNTH 0x00000431
+
+#define INXBUFEMPTYIRQ 0x00000440
+#define INXBUFEMPTYIEN 0x00000442
+#define INXBUFEMPTYCTRL 0x00000444
+#define UDMA1MEMADDR 0x00000450
+#define UDMA1EPSEL 0x00000454
+#define UDMA1COM 0x00000455
+#define UDMA1CNTL 0x00000458
+#define UDMA1CNTM 0x00000459
+#define UDMA1CNTH 0x0000045A
+#define UDMA1REML 0x0000045C
+#define UDMA1REMM 0x0000045D
+#define UDMA1REMH 0x0000045E
+#define UDMA2MEMADDR 0x00000460
+#define UDMA2EPSEL 0x00000464
+#define UDMA2COM 0x00000465
+#define UDMA2CNTL 0x00000468
+#define UDMA2CNTM 0x00000469
+#define UDMA2CNTH 0x0000046A
+#define UDMA2REML 0x0000046C
+#define UDMA2REMM 0x0000046D
+#define UDMA2REMH 0x0000046E
+#endif
+
+#define HCIN1STADDR 0x00000304
+#define HCIN2STADDR 0x00000308
+#define HCIN3STADDR 0x0000030C
+#define HCIN4STADDR 0x00000310
+#define HCIN5STADDR 0x00000314
+#define HCIN6STADDR 0x00000318
+#define HCIN7STADDR 0x0000031C
+#define HCIN8STADDR 0x00000320
+#define HCIN9STADDR 0x00000324
+#define HCIN10STADDR 0x00000328
+#define HCIN11STADDR 0x0000032C
+#define HCIN12STADDR 0x00000330
+#define HCIN13STADDR 0x00000334
+#define HCIN14STADDR 0x00000338
+#define HCIN15STADDR 0x0000033C
+#define HCOUT1STADDR 0x00000344
+#define HCOUT2STADDR 0x00000348
+#define HCOUT3STADDR 0x0000034C
+#define HCOUT4STADDR 0x00000350
+#define HCOUT5STADDR 0x00000354
+#define HCOUT6STADDR 0x00000358
+#define HCOUT7STADDR 0x0000035C
+#define HCOUT8STADDR 0x00000360
+#define HCOUT9STADDR 0x00000364
+#define HCOUT10STADDR 0x00000368
+#define HCOUT11STADDR 0x0000036C
+#define HCOUT12STADDR 0x00000370
+#define HCOUT13STADDR 0x00000374
+#define HCOUT14STADDR 0x00000378
+#define HCOUT15STADDR 0x0000037C
+#define HCOUT1MAXPCK 0x000003E2
+#define HCOUT2MAXPCK 0x000003E4
+#define HCOUT3MAXPCK 0x000003E6
+#define HCOUT4MAXPCK 0x000003E8
+#define HCOUT5MAXPCK 0x000003EA
+#define HCOUT6MAXPCK 0x000003EC
+#define HCOUT7MAXPCK 0x000003EE
+#define HCOUT8MAXPCK 0x3F0
+#define HCOUT9MAXPCK 0x000003F2
+#define HCOUT10MAXPCK 0x000003F4
+#define HCOUT11MAXPCK 0x000003F6
+#define HCOUT12MAXPCK 0x000003F8
+#define HCOUT13MAXPCK 0x000003FA
+#define HCOUT14MAXPCK 0x000003FC
+#define HCOUT15MAXPCK 0x000003FE
+#define HCOUT1MAXPCKL 0x000003E2
+#define HCOUT2MAXPCKL 0x000003E4
+#define HCOUT3MAXPCKL 0x000003E6
+#define HCOUT4MAXPCKL 0x000003E8
+#define HCOUT5MAXPCKL 0x000003EA
+#define HCOUT6MAXPCKL 0x000003EC
+#define HCOUT7MAXPCKL 0x000003EE
+#define HCOUT8MAXPCKL 0x3F0
+#define HCOUT9MAXPCKL 0x000003F2
+#define HCOUT10MAXPCKL 0x000003F4
+#define HCOUT11MAXPCKL 0x000003F6
+#define HCOUT12MAXPCKL 0x000003F8
+#define HCOUT13MAXPCKL 0x000003FA
+#define HCOUT14MAXPCKL 0x000003FC
+#define HCOUT15MAXPCKL 0x000003FE
+#define HCOUT1MAXPCKH 0x000003E3
+#define HCOUT2MAXPCKH 0x000003E5
+#define HCOUT3MAXPCKH 0x000003E7
+#define HCOUT4MAXPCKH 0x000003E9
+#define HCOUT5MAXPCKH 0x000003EB
+#define HCOUT6MAXPCKH 0x000003ED
+#define HCOUT7MAXPCKH 0x000003EF
+#define HCOUT8MAXPCKH 0x3F1
+#define HCOUT9MAXPCKH 0x000003F3
+#define HCOUT10MAXPCKH 0x000003F5
+#define HCOUT11MAXPCKH 0x000003F7
+#define HCOUT12MAXPCKH 0x000003F9
+#define HCOUT13MAXPCKH 0x000003FB
+#define HCOUT14MAXPCKH 0x000003FD
+#define HCOUT15MAXPCKH 0x000003FF
+#define HCINxDMASTART0 0x00000400
+#define HCINxDMASTART1 0x00000401
+#define HCINDMAERROR 0x00000402
+#define HCINxDMAIRQ0 0x00000404
+#define HCINxDMAIRQ1 0x00000405
+#define HCINxDMAIEN0 0x00000406
+#define HCINxDMAIEN1 0x00000407
+#define HCIN1DMASTADDR 0x00000408
+#define HCIN2DMASTADDR 0x00000410
+#define HCIN3DMASTADDR 0x00000418
+#define HCIN4DMASTADDR 0x00000420
+#define HCIN5DMASTADDR 0x00000428
+#define HCIN6DMASTADDR 0x00000430
+#define HCIN7DMASTADDR 0x00000438
+#define HCIN8DMASTADDR 0x00000440
+#define HCIN9DMASTADDR 0x00000448
+#define HCIN10DMASTADDR 0x00000450
+#define HCIN11DMASTADDR 0x00000458
+#define HCIN12DMASTADDR 0x00000460
+#define HCIN13DMASTADDR 0x00000468
+#define HCIN14DMASTADDR 0x00000470
+#define HCIN15DMASTADDR 0x00000478
+#define HCIN1DMACOUNTER 0x0000040C
+#define HCIN2DMACOUNTER 0x00000414
+#define HCIN3DMACOUNTER 0x0000041C
+#define HCIN4DMACOUNTER 0x00000424
+#define HCIN5DMACOUNTER 0x0000042C
+#define HCIN6DMACOUNTER 0x00000434
+#define HCIN7DMACOUNTER 0x0000043C
+#define HCIN8DMACOUNTER 0x00000444
+#define HCIN9DMACOUNTER 0x0000044C
+#define HCIN10DMACOUNTER 0x00000454
+#define HCIN11DMACOUNTER 0x0000045C
+#define HCIN12DMACOUNTER 0x00000464
+#define HCIN13DMACOUNTER 0x0000046C
+#define HCIN14DMACOUNTER 0x00000474
+#define HCIN15DMACOUNTER 0x0000047C
+#define HCOUTxDMASTART0 0x00000480
+#define HCOUTxDMASTART1 0x00000481
+#define HCOUTxDMAIRQ0 0x00000484
+#define HCOUTxDMAIRQ1 0x00000485
+#define HCOUTxDMAIEN0 0x00000486
+#define HCOUTxDMAIEN1 0x00000487
+#define HCOUT1DMASTADDR 0x00000488
+#define HCOUT2DMASTADDR 0x00000490
+#define HCOUT3DMASTADDR 0x00000498
+#define HCOUT4DMASTADDR 0x000004A0
+#define HCOUT5DMASTADDR 0x000004A8
+#define HCOUT6DMASTADDR 0x000004B0
+#define HCOUT7DMASTADDR 0x000004B8
+#define HCOUT8DMASTADDR 0x000004C0
+#define HCOUT9DMASTADDR 0x000004C8
+#define HCOUT10DMASTADDR 0x000004D0
+#define HCOUT11DMASTADDR 0x000004D8
+#define HCOUT12DMASTADDR 0x000004E0
+#define HCOUT13DMASTADDR 0x000004E8
+#define HCOUT14DMASTADDR 0x000004F0
+#define HCOUT15DMASTADDR 0x000004F8
+#define HCOUT1DMACOUNTER 0x0000048C
+#define HCOUT2DMACOUNTER 0x00000494
+#define HCOUT3DMACOUNTER 0x0000049C
+#define HCOUT4DMACOUNTER 0x000004A4
+#define HCOUT5DMACOUNTER 0x000004AC
+#define HCOUT6DMACOUNTER 0x000004B4
+#define HCOUT7DMACOUNTER 0x000004BC
+#define HCOUT8DMACOUNTER 0x000004C4
+#define HCOUT9DMACOUNTER 0x000004CC
+#define HCOUT10DMACOUNTER 0x000004D4
+#define HCOUT11DMACOUNTER 0x000004DC
+#define HCOUT12DMACOUNTER 0x000004E4
+#define HCOUT13DMACOUNTER 0x000004EC
+#define HCOUT14DMACOUNTER 0x000004F4
+#define HCOUT15DMACOUNTER 0x000004FC
+#define USBERESET 0x00000500
+#define TA_BCON_COUNT 0x00000501
+#define VBUSDBCTIMERL 0x00000502
+#define VBUSDBCTIMERH 0x00000503
+#define VDCTRL 0x00000504
+#define VDSTATUS 0x00000505
+#define BKDOOR 0x00000506
+#define DBGMODE 0x00000507
+#define SRPCTRL 0x00000508
+#define USBEIRQ 0x0000050A
+#define USBEIEN 0x0000050B
+#define HCINxSHORTPCKIRQ0 0x00000510
+#define HCINxSHORTPCKIRQ1 0x00000511
+#define HCINxSHORTPCKIEN0 0x00000512
+#define HCINxSHORTPCKIEN1 0x00000513
+#define HCINxZEROPCKIRQ0 0x00000514
+#define HCINxZEROPCKIRQ1 0x00000515
+#define HCINxZEROPCKIEN0 0x00000516
+#define HCINxZEROPCKIEN1 0x00000517
+#define HCOUTxBUFEMPTYIRQ0 0x00000518
+#define HCOUTxBUFEMPTYIRQ1 0x00000519
+#define HCOUTxBUFEMPTYIEN0 0x0000051A
+#define HCOUTxBUFEMPTYIEN1 0x0000051B
+#define HCOUTxBUFEMPTYCTRL0 0x0000051C
+#define HCOUTxBUFEMPTYCTRL1 0x0000051D
+
+
+//linklist regs
+#define HCDMABCKDOOR 0x00000800
+#define HCDMAxOVERFLOWIRQ 0x00000808
+#define HCDMAxOVERFLOWIEN 0x0000080C
+
+#define HCOUT1DMALINKADDR 0x00000910
+#define HCOUT2DMALINKADDR 0x00000920
+#define HCOUT3DMALINKADDR 0x00000930
+#define HCOUT4DMALINKADDR 0x00000940
+#define HCOUT5DMALINKADDR 0x00000950
+#define HCOUT6DMALINKADDR 0x00000960
+#define HCOUT7DMALINKADDR 0x00000970
+#define HCOUT8DMALINKADDR 0x00000980
+#define HCOUT9DMALINKADDR 0x00000990
+#define HCOUT10DMALINKADDR 0x000009A0
+#define HCOUT11DMALINKADDR 0x000009B0
+#define HCOUT12DMALINKADDR 0x000009C0
+#define HCOUT13DMALINKADDR 0x000009D0
+#define HCOUT14DMALINKADDR 0x000009E0
+#define HCOUT15DMALINKADDR 0x000009F0
+
+#define HCOUT1DMACURADDR 0x00000914
+#define HCOUT2DMACURADDR 0x00000924
+#define HCOUT3DMACURADDR 0x00000934
+#define HCOUT4DMACURADDR 0x00000944
+#define HCOUT5DMACURADDR 0x00000954
+#define HCOUT6DMACURADDR 0x00000964
+#define HCOUT7DMACURADDR 0x00000974
+#define HCOUT8DMACURADDR 0x00000984
+#define HCOUT9DMACURADDR 0x00000994
+#define HCOUT10DMACURADDR 0x000009A4
+#define HCOUT11DMACURADDR 0x000009B4
+#define HCOUT12DMACURADDR 0x000009C4
+#define HCOUT13DMACURADDR 0x000009D4
+#define HCOUT14DMACURADDR 0x000009E4
+#define HCOUT15DMACURADDR 0x000009F4
+
+#define HCOUT1DMACTRL 0x00000918
+#define HCOUT2DMACTRL 0x00000928
+#define HCOUT3DMACTRL 0x00000938
+#define HCOUT4DMACTRL 0x00000948
+#define HCOUT5DMACTRL 0x00000958
+#define HCOUT6DMACTRL 0x00000968
+#define HCOUT7DMACTRL 0x00000978
+#define HCOUT8DMACTRL 0x00000988
+#define HCOUT9DMACTRL 0x00000998
+#define HCOUT10DMACTRL 0x000009A8
+#define HCOUT11DMACTRL 0x000009B8
+#define HCOUT12DMACTRL 0x000009C8
+#define HCOUT13DMACTRL 0x000009D8
+#define HCOUT14DMACTRL 0x000009E8
+#define HCOUT15DMACTRL 0x000009F8
+
+#define HCOUT1DMACOMPLETECNT 0x0000091C
+#define HCOUT2DMACOMPLETECNT 0x0000092C
+#define HCOUT3DMACOMPLETECNT 0x0000093C
+#define HCOUT4DMACOMPLETECNT 0x0000094C
+#define HCOUT5DMACOMPLETECNT 0x0000095C
+#define HCOUT6DMACOMPLETECNT 0x0000096C
+#define HCOUT7DMACOMPLETECNT 0x0000097C
+#define HCOUT8DMACOMPLETECNT 0x0000098C
+#define HCOUT9DMACOMPLETECNT 0x0000099C
+#define HCOUT10DMACOMPLETECNT 0x000009AC
+#define HCOUT11DMACOMPLETECNT 0x000009BC
+#define HCOUT12DMACOMPLETECNT 0x000009CC
+#define HCOUT13DMACOMPLETECNT 0x000009DC
+#define HCOUT14DMACOMPLETECNT 0x000009EC
+#define HCOUT15DMACOMPLETECNT 0x000009FC
+
+#define HCIN1DMALINKADDR 0x00000810
+#define HCIN2DMALINKADDR 0x00000820
+#define HCIN3DMALINKADDR 0x00000830
+#define HCIN4DMALINKADDR 0x00000840
+#define HCIN5DMALINKADDR 0x00000850
+#define HCIN6DMALINKADDR 0x00000860
+#define HCIN7DMALINKADDR 0x00000870
+#define HCIN8DMALINKADDR 0x00000880
+#define HCIN9DMALINKADDR 0x00000890
+#define HCIN10DMALINKADDR 0x000008A0
+#define HCIN11DMALINKADDR 0x000008B0
+#define HCIN12DMALINKADDR 0x000008C0
+#define HCIN13DMALINKADDR 0x000008D0
+#define HCIN14DMALINKADDR 0x000008E0
+#define HCIN15DMALINKADDR 0x000008F0
+
+#define HCIN1DMACURADDR 0x00000814
+#define HCIN2DMACURADDR 0x00000824
+#define HCIN3DMACURADDR 0x00000834
+#define HCIN4DMACURADDR 0x00000844
+#define HCIN5DMACURADDR 0x00000854
+#define HCIN6DMACURADDR 0x00000864
+#define HCIN7DMACURADDR 0x00000874
+#define HCIN8DMACURADDR 0x00000884
+#define HCIN9DMACURADDR 0x00000894
+#define HCIN10DMACURADDR 0x000008A4
+#define HCIN11DMACURADDR 0x000008B4
+#define HCIN12DMACURADDR 0x000008C4
+#define HCIN13DMACURADDR 0x000008D4
+#define HCIN14DMACURADDR 0x000008E4
+#define HCIN15DMACURADDR 0x000008F4
+
+#define HCIN1DMACTRL 0x00000818
+#define HCIN2DMACTRL 0x00000828
+#define HCIN3DMACTRL 0x00000838
+#define HCIN4DMACTRL 0x00000848
+#define HCIN5DMACTRL 0x00000858
+#define HCIN6DMACTRL 0x00000868
+#define HCIN7DMACTRL 0x00000878
+#define HCIN8DMACTRL 0x00000888
+#define HCIN9DMACTRL 0x00000898
+#define HCIN10DMACTRL 0x000008A8
+#define HCIN11DMACTRL 0x000008B8
+#define HCIN12DMACTRL 0x000008C8
+#define HCIN13DMACTRL 0x000008D8
+#define HCIN14DMACTRL 0x000008E8
+#define HCIN15DMACTRL 0x000008F8
+
+#define HCIN1DMACOMPLETECNT 0x0000081C
+#define HCIN2DMACOMPLETECNT 0x0000082C
+#define HCIN3DMACOMPLETECNT 0x0000083C
+#define HCIN4DMACOMPLETECNT 0x0000084C
+#define HCIN5DMACOMPLETECNT 0x0000085C
+#define HCIN6DMACOMPLETECNT 0x0000086C
+#define HCIN7DMACOMPLETECNT 0x0000087C
+#define HCIN8DMACOMPLETECNT 0x0000088C
+#define HCIN9DMACOMPLETECNT 0x0000089C
+#define HCIN10DMACOMPLETECNT 0x000008AC
+#define HCIN11DMACOMPLETECNT 0x000008BC
+#define HCIN12DMACOMPLETECNT 0x000008CC
+#define HCIN13DMACOMPLETECNT 0x000008DC
+#define HCIN14DMACOMPLETECNT 0x000008EC
+#define HCIN15DMACOMPLETECNT 0x000008FC
+
+
+
+/******************************************************************************/
+/* DMA LINK_LIST */
+/******************************************************************************/
+#define DMACTRL_DMACS (1 << 0)
+#define DMACTRL_DMACC (1 << 1)
+
+/******************************************************************************/
+/*OTG external Registers USBEIRQ, USBEIEN. */
+/******************************************************************************/
+#define USBEIRQ_USBIRQ (0x1 << 7)
+#define USBEIRQ_USBIEN (0x1 << 7)
+
+/* USBERESET USBERES*/
+#define USBERES_USBRESET (1 << 0)
+
+/*VDCTRL*/
+#define VDCTRL_VLOAD (1 << 4)
+#define VDCTRL_VCONTROL(x) ((x) & 0xf)
+
+/******************************************************************************/
+/*OTG SFR Registers*/
+/******************************************************************************/
+/*OTGIRQ*/
+#define OTGIRQ_PERIPH (1<<4)
+#define OTGIRQ_VBUSEER (1<<3)
+#define OTGIRQ_LOCSOF (1<<2)
+#define OTGIRQ_SRPDET (1<<1)
+#define OTGIRQ_IDLE (1<<0)
+
+/*bit 7:5 reserved*/
+/*OTGSTATE*/
+#define A_IDLE (0x00)
+#define A_WAIT_VRISE (0x01)
+#define A_WAIT_BCON (0x02)
+#define A_HOST (0x03)
+#define A_SUSPEND (0x04)
+#define A_PHERIPHERAL (0x05)
+#define A_VBUS_ERR (0x06)
+#define A_WAIT_VFAL (0x07)
+#define B_IDLE (0x08)
+#define B_PHERIPHERAL (0x09)
+#define B_WAIT_ACON (0x0a)
+#define B_HOST (0x0b)
+#define B_SRP_INIT1 (0x0c)
+#define B_SRP_INIT2 (0x0d)
+#define B_DISCHRG1 (0x0e)
+#define B_DISCHRG2 (0x0f)
+
+/* OTGSTATE value. */
+/* extra dual-role default-b states */
+/* dual-role default-a */
+#define AOTG_STATE_A_IDLE 0
+#define AOTG_STATE_A_WAIT_VRISE 1
+#define AOTG_STATE_A_WAIT_BCON 2
+#define AOTG_STATE_A_HOST 3
+#define AOTG_STATE_A_SUSPEND 4
+#define AOTG_STATE_A_PERIPHERAL 5
+#define AOTG_STATE_A_VBUS_ERR 6
+#define AOTG_STATE_A_WAIT_VFALL 7
+/* single-role peripheral, and dual-role default-b */
+#define AOTG_STATE_B_IDLE 8
+#define AOTG_STATE_B_PERIPHERAL 9
+#define AOTG_STATE_B_WAIT_ACON 10
+#define AOTG_STATE_B_HOST 11
+#define AOTG_STATE_B_SRP_INIT 12
+#define AOTG_STATE_UNDEFINED 17
+
+/*bit 7:4 reserved*/
+/*OTGCTRL*/
+#define OTGCTRL_FORCEBCONN (1 << 7)
+/*bit 6 reserved*/
+#define OTGCTRL_SRPDATDETEN (1 << 5)
+#define OTGCTRL_SRPVBUSDETEN (1 << 4)
+#define OTGCTRL_BHNPEN (1 << 3)
+#define OTGCTRL_ASETBHNPEN (1 << 2)
+#define OTGCTRL_ABUSDROP (1 << 1)
+#define OTGCTRL_BUSREQ (1 << 0)
+
+/*OTGSTATUS*/
+/*bit 7 reserved*/
+#define OTGSTATUS_ID (1 << 6)
+#define OTGSTATUS_AVBUSSVAL (1 << 5)
+#define OTGSTATUS_BSESSEND (1 << 4)
+#define OTGSTATUS_ASESSVAL (1 << 3)
+#define OTGSTATUS_BSESSVAL (1 << 2)
+#define OTGSTATUS_CONN (1 << 1)
+#define OTGSTATUS_BSE0SRP (1 << 0)
+
+/*OTGIEN*/
+/*bit 7:5 reserved*/
+#define OTGIEN_PERIPH (1 << 4)
+#define OTGIEN_VBUSEER (1 << 3)
+#define OTGIEN_LOCSOF (1 << 2)
+#define OTGIEN_SRPDET (1 << 1)
+#define OTGIEN_IDLE (1 << 0)
+
+/*HCEP0CTRL*/
+#define HCEP0CTRL_ENDPNR(x) (((x) & 0xf) << 0)
+/*bit 7:4 reserved*/
+
+/* HCINxERR */
+#define HCINxERR_TYPE_MASK (0xf << 2)
+/*
+ * 0000 \A8C reserved (no error)
+ * 0001 \A8C CRC error
+ * 0010 \A8C data toggle mismatch
+ * 0011 \A8C endpoint sent STALL handshake
+ * 0100 \A8C no endpoint handshake (timeout)
+ * 0101 \A8C PID error (pid check=error or unknown PID)
+ * 0110 \A8C Data Overrun (too long packet \A8C babble)
+ * 0111 \A8C Data Underrun (packet shorter than MaxPacketSize)
+ * 1xxx \A8C Spilit Transaction Error, reference to HCOUTxSPILITCS register
+*/
+#define HCINxERR_NO_ERR (0x0 << 2)
+#define HCINxERR_CRC_ERR (0x1 << 2)
+#define HCINxERR_TOG_ERR (0x2 << 2)
+#define HCINxERR_STALL (0x3 << 2)
+#define HCINxERR_TIMEOUT (0x4 << 2)
+#define HCINxERR_PID_ERR (0x5 << 2)
+#define HCINxERR_OVER_RUN (0x6 << 2)
+#define HCINxERR_UNDER_RUN (0x7 << 2)
+#define HCINxERR_SPLIET (0x8 << 2)
+#define HCINxERR_RESEND (1 << 6)
+
+/*HCOUTXCTRL*/
+//#define HCOUTXCTRL(x) (((x) & 0xf) << 0)
+/*bit 7:4 reserved*/
+
+
+/******************************************************************************/
+/*Device Mode Special Function Registers*/
+/******************************************************************************/
+/*EP0CS*/
+/*bit 7 reserved*/
+#define EP0CS_HCSETTOOGLE (1 << 6)
+#define EP0CS_HCCLRTOOGLE (1 << 5)
+#define EP0CS_HCSET (1 << 4)
+#define EP0CS_HCINBSY (1 << 3)
+#define EP0CS_HCOUTBSY (1 << 2)
+#define EP0CS_OUTBSY (1 << 3)
+#define EP0CS_INBSY (1 << 2)
+#define EP0CS_HSNAK (1 << 1)
+#define EP0CS_STALL (1 << 0)
+
+/*EPXCS host & device*/
+/* HCIN1CS */
+/*bit 7 reserved*/
+//#define EPCS_AUTO_IN (1 << 4)
+//#define EPCS_AUTO_OUT (1 << 4)
+#define EPCS_NPAK (0x3 << 2)
+#define EPCS_BUSY (1 << 1)
+#define EPCS_ERR (1 << 0)
+
+/*EPXCON host & device*/
+#define EPCON_VAL (1 << 7)
+#define EPCON_STALL (1 << 6)
+#define EPCON_TYPE (0x3 << 2)
+#define EPCON_TYPE_INT (0x3 << 2)
+#define EPCON_TYPE_BULK (0x2 << 2)
+#define EPCON_TYPE_ISO (0x1 << 2)
+#define EPCON_BUF (0x03)
+#define EPCON_BUF_QUAD (0x03)
+#define EPCON_BUF_TRIPLE (0x02)
+#define EPCON_BUF_DOUBLE (0x01)
+#define EPCON_BUF_SINGLE (0x00)
+
+/*OUTXIRQ*/
+//#define OUTXIRQ(x) (1 << (x))
+/*INXIRQ*/
+//#define INXIRQ(x) (1 << (x))
+
+/*USBIRQ*/
+#define USBIRQ_HS (1 << 5)
+#define USBIRQ_URES (1 << 4)
+#define USBIRQ_SUSP (1 << 3)
+#define USBIRQ_SUTOK (1 << 2)
+#define USBIRQ_SOF (1 << 1)
+#define USBIRQ_SUDAV (1 << 0)
+
+/*OUTXIEN*/
+//#define OUTXIEN(x) (1 << (x))
+/*INXIEN*/
+//#define INXIEN(x) (1 << (x))
+
+/*USBIEN*/
+/*bit 7:6 reserved*/
+#define USBIEN_HS (1 << 5)
+#define USBIEN_URES (1 << 4)
+#define USBIEN_SUSP (1 << 3)
+#define USBIEN_SUTOK (1 << 2)
+#define USBIEN_SOF (1 << 1)
+#define USBIEN_SUDAV (1 << 0)
+
+/* IVECT, USB Interrupt Vector. */
+//#define UIV_OTGIRQ (0xd8)
+
+#define UIV_SUDAV 0x01
+#define UIV_SOF 0x02
+#define UIV_SUTOK 0x03
+#define UIV_SUSPEND 0x04
+#define UIV_USBRESET 0x05
+#define UIV_HSPEED 0x06
+
+/* otg status. */
+#define UIV_IDLE 0x07
+#define UIV_SRPDET 0x08
+#define UIV_LOCSOF 0x09
+#define UIV_VBUSERR 0x0a
+#define UIV_PERIPH 0x0b
+
+#define UIV_HCOUT0ERR 0x10
+#define UIV_EP0IN 0x20
+#define UIV_HCEP0OUT 0x20
+#define UIV_IN0TOKEN 0x30
+#define UIV_HCIN0ERR 0x40
+#define UIV_EP0OUT 0x50
+#define UIV_HCEP0IN 0x50
+#define UIV_OUT0TOKEN 0x60
+#define UIV_EP0PING 0x70
+
+#define UIV_HCOUT1ERR 0x11
+#define UIV_EP1IN 0x21
+#define UIV_HCEP1OUT 0x21
+#define UIV_IN0T1KEN 0x31
+#define UIV_HCIN1ERR 0x41
+#define UIV_EP1OUT 0x51
+#define UIV_HCEP1IN 0x51
+#define UIV_OUT1TOKEN 0x61
+#define UIV_EP1PING 0x71
+
+#define UIV_HCOUT2ERR 0x12
+#define UIV_EP2IN 0x22
+#define UIV_HCEP2OUT 0x22
+#define UIV_IN2TOKEN 0x32
+#define UIV_HCIN2ERR 0x42
+#define UIV_EP2OUT 0x52
+#define UIV_HCEP2IN 0x52
+#define UIV_OUT2TOKEN 0x62
+#define UIV_EP2PING 0x72
+
+#define UIV_HCOUT3ERR 0x13
+#define UIV_EP3IN 0x23
+#define UIV_HCEP3OUT 0x23
+#define UIV_IN3TOKEN 0x33
+#define UIV_HCIN3ERR 0x43
+#define UIV_EP3OUT 0x53
+#define UIV_HCEP3IN 0x53
+#define UIV_OUT3TOKEN 0x63
+#define UIV_EP3PING 0x73
+
+#define UIV_HCOUT4ERR 0x14
+#define UIV_EP4IN 0x24
+#define UIV_HCEP4OUT 0x24
+#define UIV_IN4TOKEN 0x34
+#define UIV_HCIN4ERR 0x44
+#define UIV_EP4OUT 0x54
+#define UIV_HCEP4IN 0x54
+#define UIV_OUT4TOKEN 0x64
+#define UIV_EP4PING 0x74
+
+#define UIV_HCOUT5ERR 0x15
+#define UIV_EP5IN 0x25
+#define UIV_HCEP5OUT 0x25
+#define UIV_IN5TOKEN 0x35
+#define UIV_HCIN5ERR 0x45
+#define UIV_EP5OUT 0x55
+#define UIV_HCEP5IN 0x55
+#define UIV_OUT5TOKEN 0x65
+#define UIV_EP5PING 0x75
+
+#define UIV_HCOUT6ERR 0x16
+#define UIV_EP6IN 0x26
+#define UIV_HCEP6OUT 0x26
+#define UIV_IN6TOKEN 0x36
+#define UIV_HCIN6ERR 0x46
+#define UIV_EP6OUT 0x56
+#define UIV_HCEP6IN 0x56
+#define UIV_OUT6TOKEN 0x66
+#define UIV_EP6PING 0x76
+
+#define UIV_HCOUT7ERR 0x17
+#define UIV_EP7IN 0x27
+#define UIV_HCEP7OUT 0x27
+#define UIV_IN7TOKEN 0x37
+#define UIV_HCIN7ERR 0x47
+#define UIV_EP7OUT 0x57
+#define UIV_HCEP7IN 0x57
+#define UIV_OUT7TOKEN 0x67
+#define UIV_EP7PING 0x77
+
+#define UIV_HCOUT8ERR 0x18
+#define UIV_EP8IN 0x28
+#define UIV_HCEP8OUT 0x28
+#define UIV_IN8TOKEN 0x38
+#define UIV_HCIN8ERR 0x48
+#define UIV_EP8OUT 0x58
+#define UIV_HCEP8IN 0x58
+#define UIV_OUT8TOKEN 0x68
+#define UIV_EP8PING 0x78
+
+#define UIV_HCOUT9ERR 0x19
+#define UIV_EP9IN 0x29
+#define UIV_HCEP9OUT 0x29
+#define UIV_IN9TOKEN 0x39
+#define UIV_HCIN9ERR 0x49
+#define UIV_EP9OUT 0x59
+#define UIV_HCEP9IN 0x59
+#define UIV_OUT9TOKEN 0x69
+#define UIV_EP9PING 0x79
+
+#define UIV_HCOUT10ERR 0x1a
+#define UIV_EP10IN 0x2a
+#define UIV_HCEP10OUT 0x2a
+#define UIV_IN10TOKEN 0x3a
+#define UIV_HCIN10ERR 0x4a
+#define UIV_EP10OUT 0x5a
+#define UIV_HCEP10IN 0x5a
+#define UIV_OUT10TOKEN 0x6a
+#define UIV_EP10PING 0x7a
+
+#define UIV_HCOUT11ERR 0x1b
+#define UIV_EP11IN 0x2b
+#define UIV_HCEP11OUT 0x2b
+#define UIV_IN11TOKEN 0x3b
+#define UIV_HCIN11ERR 0x4b
+#define UIV_EP11OUT 0x5b
+#define UIV_HCEP11IN 0x5b
+#define UIV_OUT11TOKEN 0x6b
+#define UIV_EP11PING 0x7b
+
+#define UIV_HCOUT12ERR 0x1c
+#define UIV_EP12IN 0x2c
+#define UIV_HCEP12OUT 0x2c
+#define UIV_IN12TOKEN 0x3c
+#define UIV_HCIN12ERR 0x4c
+#define UIV_EP12OUT 0x5c
+#define UIV_HCEP12IN 0x5c
+#define UIV_OUT12TOKEN 0x6c
+#define UIV_EP12PING 0x7c
+
+#define UIV_HCOUT13ERR 0x1d
+#define UIV_EP13IN 0x2d
+#define UIV_HCEP13OUT 0x2d
+#define UIV_IN13TOKEN 0x3d
+#define UIV_HCIN13ERR 0x4d
+#define UIV_EP13OUT 0x5d
+#define UIV_HCEP13IN 0x5d
+#define UIV_OUT13TOKEN 0x6d
+#define UIV_EP13PING 0x7d
+
+#define UIV_HCOUT14ERR 0x1e
+#define UIV_EP14IN 0x2e
+#define UIV_HCEP14OUT 0x2e
+#define UIV_IN14TOKEN 0x3e
+#define UIV_HCIN14ERR 0x4e
+#define UIV_EP14OUT 0x5e
+#define UIV_HCEP14IN 0x5e
+#define UIV_OUT14TOKEN 0x6e
+#define UIV_EP14PING 0x7e
+
+#define UIV_HCOUT15ERR 0x1f
+#define UIV_EP15IN 0x2f
+#define UIV_HCEP15OUT 0x2f
+#define UIV_IN15TOKEN 0x3f
+#define UIV_HCIN15ERR 0x4f
+#define UIV_EP15OUT 0x5f
+#define UIV_HCEP15IN 0x5f
+#define UIV_OUT15TOKEN 0x6f
+#define UIV_EP15PING 0x7f
+
+
+/*ENDPRST*/
+#define ENDPRST_EPX(x) ((x) & 0xf)
+#define ENDPRST_IO (1 << 4)
+#define ENDPRST_FIFORST (1 << 5)
+#define ENDPRST_TOGRST (1 << 6)
+#define ENDPRST_TOGRST_R (0x3 << 6)
+/*bit 7 reserved*/
+
+/*USBCS*/
+/*bit 7 reserved*/
+#define USBCS_DISCONN (1 << 6)
+#define USBCS_SIGRSUME (1 << 5)
+#define USBCS_HFMODE (1 << 1)
+#define USBCS_LSMODE (1 << 0)
+
+#if 0 /******** need to check bits. ***********************/
+/*FIFOCTRL*/
+/*bit 7:6 reserved*/
+#define FIFOCTRL_EPX(x) ((x) & 0xf)
+#define FIFOCTRL_FIFOAUTO (1 << 5)
+#define FIFOCTRL_IO (1 << 4)
+
+#endif
+
+
+static void inline usb_writeb(u8 val, volatile void __iomem *reg)
+{
+ writeb(val, reg);
+}
+
+static void inline usb_writew(u16 val, volatile void __iomem *reg)
+{
+ writew(val, reg);
+}
+
+static void inline usb_writel(u32 val, volatile void __iomem *reg)
+{
+ writel(val, reg);
+}
+
+/******************************************************************************/
+static inline u8 usb_readb(volatile void __iomem *reg)
+{
+ return readb(reg);
+}
+
+static inline u16 usb_readw(volatile void __iomem *reg)
+{
+ return readw(reg);
+}
+
+static inline u32 usb_readl(volatile void __iomem *reg)
+{
+ return readl(reg);
+}
+
+/******************************************************************************/
+static void inline usb_setb(u8 val, volatile void __iomem *reg)
+{
+ //act_setb(val, (u32)reg);
+ writeb(readb(reg) | val, reg);
+}
+
+static void inline usb_setw(u16 val,volatile void __iomem *reg)
+{
+ //act_setw(val, (u32)reg);
+ writew(readw(reg) | val, reg);
+}
+
+static void inline usb_setl(u32 val,volatile void __iomem *reg)
+{
+ //act_setl(val, (u32)reg);
+ writel(readl(reg) | val, reg);
+}
+
+/******************************************************************************/
+static void inline usb_clearb(u8 val,volatile void __iomem *reg)
+{
+ //act_clearb(val, (u32)reg);
+ writeb(readb(reg)&(~val),reg);
+}
+
+static void inline usb_clearw(u16 val,volatile void __iomem *reg)
+{
+ //act_clearw(val, (u32)reg);
+ writew(readw(reg)&(~val),reg);
+}
+
+static void inline usb_clearl(u32 val,volatile void __iomem *reg)
+{
+ //act_clearl(val, (u32)reg);
+ writel(readl(reg)&(~val),reg);
+}
+
+/*********************** old define. *****************************************/
+
+static inline void usb_setbitsb(u8 mask, volatile void __iomem *mem)
+{
+ writeb(readb(mem) | mask, mem);
+}
+
+static inline void usb_setbitsw(u16 mask, volatile void __iomem *mem)
+{
+ writew(readw(mem) | mask, mem);
+}
+
+static inline void usb_setbitsl(ulong mask, volatile void __iomem *mem)
+{
+ writel(readl(mem) | mask, mem);
+}
+
+static inline void usb_clearbitsb(u8 mask, volatile void __iomem *mem)
+{
+ writeb(readb(mem) & ~mask, mem);
+}
+
+static inline void usb_clearbitsw(u16 mask, volatile void __iomem *mem)
+{
+ writew(readw(mem) & ~mask, mem);
+}
+
+static inline void usb_clearbitsl(ulong mask, volatile void __iomem *mem)
+{
+ writel(readl(mem) & ~mask, mem);
+}
+
+#endif /* __AOTG_REGS_H__ */
+
diff --git a/drivers/usb/host/aotg_ring.c b/drivers/usb/host/aotg_ring.c
new file mode 100644
index 0000000..cea36b2
--- /dev/null
+++ b/drivers/usb/host/aotg_ring.c
@@ -0,0 +1,1509 @@
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+
+#include "aotg_hcd.h"
+#include "aotg_debug.h"
+#include "aotg_mon.h"
+
+void aotg_set_ring_linkaddr(struct aotg_ring *ring, u32 addr);
+int aotg_set_trb_as_ring_linkaddr(struct aotg_ring *ring, struct aotg_trb *trb);
+u32 ring_trb_virt_to_dma(struct aotg_ring *ring,
+ struct aotg_trb *trb_vaddr);
+void clear_ring_irq(struct aotg_hcd *acthcd, unsigned int irq_mask);
+
+void aotg_dump_linklist_reg_2(struct aotg_hcd *acthcd, int dmanr)
+{
+ int is_out, index, index_multi;
+
+ is_out = (dmanr & AOTG_DMA_OUT_PREFIX) ? 1 : 0;
+ index = dmanr & 0xf;
+ if (index >= 1) {
+ index_multi = index - 1;
+ } else {
+ ACT_HCD_ERR
+ return;
+ }
+
+ printk("--------- dma reg, ep%d-%s-------\n", index,
+ is_out ? "out" : "in");
+
+ printk("HCDMABCKDOOR(0x%p) : 0x%x\n",
+ acthcd->base + HCDMABCKDOOR, readl(acthcd->base + HCDMABCKDOOR));
+ printk("HCDMAxOVERFLOWIRQ(0x%p) : 0x%x\n",
+ acthcd->base + HCDMAxOVERFLOWIRQ, readl(acthcd->base + HCDMAxOVERFLOWIRQ));
+ printk("HCDMAxOVERFLOWIEN(0x%p) : 0x%x\n",
+ acthcd->base + HCDMAxOVERFLOWIEN, readl(acthcd->base + HCDMAxOVERFLOWIEN));
+
+ if (is_out) {
+ printk("HCOUT%dDMALINKADDR(0x%p) : 0x%x\n", index,
+ acthcd->base + HCOUT1DMALINKADDR + index_multi * 0x10,
+ readl(acthcd->base + HCOUT1DMALINKADDR + index_multi * 0x10));
+ printk("HCOUT%dDMACURADDR(0x%p) : 0x%x\n",index,
+ acthcd->base + HCOUT1DMACURADDR + index_multi * 0x10,
+ readl(acthcd->base + HCOUT1DMACURADDR + index_multi * 0x10));
+ printk("HCOUT%dDMACTRL(0x%p) : 0x%x\n", index,
+ acthcd->base + HCOUT1DMACTRL + index_multi * 0x10,
+ readl(acthcd->base + HCOUT1DMACTRL + index_multi * 0x10));
+ printk("HCOUT%dDMACOMPLETECNT(0x%p) : 0x%x\n", index,
+ acthcd->base + HCOUT1DMACOMPLETECNT + index_multi * 0x10,
+ readl(acthcd->base + HCOUT1DMACOMPLETECNT + index_multi * 0x10));
+ } else {
+ printk("HCIN%dDMALINKADDR(0x%p) : 0x%x\n", index,
+ acthcd->base + HCIN1DMALINKADDR+ index_multi * 0x10,
+ readl(acthcd->base + HCIN1DMALINKADDR+ index_multi * 0x10));
+ printk("HCIN%dDMACURADDR(0x%p) : 0x%x\n", index,
+ acthcd->base + HCIN1DMACURADDR + index_multi * 0x10,
+ readl(acthcd->base + HCIN1DMACURADDR + index_multi * 0x10));
+ printk("HCIN%dDMACTRL(0x%p) : 0x%x\n", index,
+ acthcd->base + HCIN1DMACTRL+ index_multi * 0x10,
+ readl(acthcd->base + HCIN1DMACTRL+ index_multi * 0x10));
+ printk("HCIN%dDMACOMPLETECNT(0x%p) : 0x%x\n", index,
+ acthcd->base + HCIN1DMACOMPLETECNT + index_multi * 0x10,
+ readl(acthcd->base + HCIN1DMACOMPLETECNT + index_multi * 0x10));
+ }
+}
+
+static void aotg_hcd_dump_trb(struct aotg_ring *ring, struct aotg_trb *trb)
+{
+ printk("trb:0x%x, dma:0x%x\n", (u32)trb,
+ (u32)ring_trb_virt_to_dma(ring, trb));
+ printk("hw_buf_ptr : 0x%x\n", trb->hw_buf_ptr);
+ printk("hw_buf_len : %d\n", trb->hw_buf_len);
+ printk("hw_buf_remain : %d\n", trb->hw_buf_remain);
+ printk("hw_token : 0x%x\n", trb->hw_token);
+}
+
+void aotg_hcd_dump_td(struct aotg_ring *ring, struct aotg_td *td)
+{
+ int i, j;
+ int num_trbs;
+ struct aotg_trb *trb;
+
+ if (td == NULL){
+ ACT_HCD_ERR
+ return;
+ }
+
+ num_trbs = td->num_trbs;
+ trb = td->trb_vaddr;
+
+ printk("==== dump td: %d trbs ====\n", td->num_trbs);
+
+ if (trb + num_trbs > ring->last_trb) {
+ for (i = 0; trb + i < ring->last_trb + 1; i++) {
+ printk("trb_%d:\n", i);
+ aotg_hcd_dump_trb(ring, trb + i);
+ }
+ trb = ring->first_trb;
+ j = 0;
+ for (; i < num_trbs; i++) {
+ printk("trb_%d:\n", i);
+ aotg_hcd_dump_trb(ring, trb + j);
+ j++;
+ }
+ } else {
+ for (i = 0; i < num_trbs; i++) {
+ printk("trb_%d:\n", i);
+ aotg_hcd_dump_trb(ring, trb + i);
+ }
+ }
+
+ printk("\n");
+
+ return;
+}
+
+void inc_dequeue_safe(struct aotg_ring *ring)
+{
+ atomic_inc(&ring->num_trbs_free);
+ if (ring->dequeue_trb == ring->ring_trb) {
+ ring->dequeue_trb = ring->first_trb;
+ } else {
+ ring->dequeue_trb++;
+ }
+ return;
+}
+
+struct aotg_ring *aotg_alloc_ring(struct aotg_hcd *acthcd,
+ struct aotg_hcep *ep, unsigned int num_trbs,
+ gfp_t mem_flags)
+{
+ dma_addr_t dma;
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+ struct aotg_ring *ring;
+
+ ring = kmalloc(sizeof(struct aotg_ring), mem_flags);
+ if (!ring) {
+ return NULL;
+ }
+
+ ring->num_trbs = num_trbs;
+ if (num_trbs == 0) {
+ ACT_HCD_DBG
+ return ring;
+ }
+
+ ring->first_trb = (struct aotg_trb *)
+ dma_alloc_coherent(dev, num_trbs * sizeof(struct aotg_trb),
+ &dma, mem_flags);
+
+ HUB_DEBUG("frist_trb:%x,dma:%x\n",ring->first_trb,dma);
+ memset(ring->first_trb, 0, num_trbs * sizeof(struct aotg_trb));
+ //memset(ring->first_trb, 0, RING_SIZE);
+ ring->trb_dma = (u32)dma;
+ ring->last_trb = ring->first_trb + num_trbs - 1;
+ ring->ring_trb = ring->last_trb;
+ atomic_set(&ring->num_trbs_free, num_trbs);
+ ring->enqueue_trb = ring->first_trb;
+ ring->dequeue_trb = ring->first_trb;
+
+ ring->is_running = 0;
+ ring->is_out = ep->is_out ? 1 : 0;
+ ring->intr_inited = 0;
+ ring->intr_started = 0;
+ ring->priv = ep;
+ ring->mask = ep->mask;
+ ring->type = ep->type;
+ ring->enring_cnt = 0;
+ ring->dering_cnt = 0;
+ ring->ring_stopped= 0;
+
+ ring->reg_dmalinkaddr = GET_DMALINKADDR_REG(ring->is_out, acthcd->base + HCOUT1DMALINKADDR,
+ acthcd->base + HCIN1DMALINKADDR, ep->index);
+ ring->reg_curaddr = GET_CURADDR_REG(ring->is_out, acthcd->base + HCOUT1DMACURADDR,
+ acthcd->base + HCIN1DMACURADDR, ep->index);
+ ring->reg_dmactrl = GET_DMACTRL_REG(ring->is_out, acthcd->base + HCOUT1DMACTRL,
+ acthcd->base + HCIN1DMACTRL, ep->index);
+ ring->reg_dmacomplete_cnt = GET_DMACOMPLETE_CNT_REG(ring->is_out,
+ acthcd->base + HCOUT1DMACOMPLETECNT,
+ acthcd->base + HCIN1DMACOMPLETECNT, ep->index);
+
+
+ /*printk("=====================================\n");
+
+ printk("first_trb:0x%x,last_trb:0x%x, ring_trb:0x%x\n",
+ (u32)(ring->first_trb), (u32)(ring->last_trb), (u32)(ring->ring_trb));
+
+ printk("enq_trb:0x%x, deq_trb:0x%x\n",
+ (u32)(ring->enqueue_trb), (u32)(ring->dequeue_trb));
+ printk("=====================================\n");*/
+ return ring;
+}
+
+void aotg_free_ring(struct aotg_hcd *acthcd, struct aotg_ring *ring)
+{
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+ if (!ring) {
+ return;
+ }
+
+ dma_free_coherent(dev, ring->num_trbs * sizeof(struct aotg_trb),
+ ring->first_trb, ring->trb_dma);
+ kfree(ring);
+ return;
+}
+
+struct aotg_td *aotg_alloc_td(gfp_t mem_flags)
+{
+ struct aotg_td *td;
+
+ //td = kmalloc(sizeof(struct aotg_td), mem_flags);
+ td = kmalloc(sizeof(struct aotg_td), GFP_ATOMIC);
+ if (!td) {
+ return NULL;
+ }
+ memset(td, 0, sizeof(struct aotg_td));
+
+ td->cross_ring = 0;
+ td->err_count = 0;
+ td->urb = NULL;
+ INIT_LIST_HEAD(&td->queue_list);
+ INIT_LIST_HEAD(&td->enring_list);
+ INIT_LIST_HEAD(&td->dering_list);
+
+ return td;
+}
+
+void aotg_release_td(struct aotg_td *td)
+{
+ if (!td)
+ return;
+ kfree(td);
+}
+
+void enable_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ u8 mask = ep->mask;
+ u8 is_out = mask & USB_HCD_OUT_MASK;
+ u8 ep_num = mask & 0x0f;
+
+ if (is_out) {
+ usb_setbitsl(1 << (ep_num + 16), acthcd->base + HCDMAxOVERFLOWIEN);
+ } else {
+ usb_setbitsl(1 << ep_num, acthcd->base + HCDMAxOVERFLOWIEN);
+ }
+ return;
+}
+
+void disable_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ u8 mask = ep->mask;
+ u8 is_out = mask & USB_HCD_OUT_MASK;
+ u8 ep_num = mask & 0x0f;
+
+ if (is_out) {
+ usb_clearbitsl(1 << (ep_num + 16), acthcd->base + HCDMAxOVERFLOWIEN);
+ } else {
+ usb_clearbitsl(1 << ep_num, acthcd->base + HCDMAxOVERFLOWIEN);
+ }
+ return;
+}
+
+void clear_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ u8 mask = ep->mask;
+ u8 is_out = mask & USB_HCD_OUT_MASK;
+ u8 ep_num = mask & 0x0f;
+
+ if (is_out) {
+ usb_clearbitsl(1 << (ep_num + 16), acthcd->base + HCDMAxOVERFLOWIRQ);
+ } else {
+ usb_clearbitsl(1 << ep_num, acthcd->base + HCDMAxOVERFLOWIRQ);
+ }
+}
+
+// FIXME
+void overflow_irq_handler(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ struct aotg_ring *ring;
+
+ if (!ep) {
+ printk(KERN_ERR"%s, ep%d is NULL!\n", __FUNCTION__, ep->index);
+ return;
+ }
+
+ ring = ep->ring;
+
+ return;
+}
+/*
+void aotg_handle_overflow_irq(struct aotg_hcd *acthcd)
+{
+ int i;
+ unsigned int irq_pend = 0;
+ struct aotg_hcep *ep;
+
+ irq_pend = readl(acthcd->base + HCDMAxOVERFLOWIRQ);
+
+ if (irq_pend & RING_IN_OF) {
+ for (i = 1; i < 16; i++) {
+ if (irq_pend & (0x1 << i)) {
+ ep = acthcd->inep[i];
+ overflow_irq_handler(acthcd, ep);
+ }
+ }
+ }
+
+ if (irq_pend & RING_OUT_OF) {
+ for (i = 1; i < 16; i++) {
+ if (irq_pend & (0x1 << (i + 16))) {
+ ep = acthcd->outep[i];
+ overflow_irq_handler(acthcd, ep);
+ }
+ }
+
+ writel(irq_pend, acthcd->base + HCDMAxOVERFLOWIRQ);
+}
+*/
+int is_ring_running(struct aotg_ring *ring)
+{
+ return (readl(ring->reg_dmactrl) & 0x1) ? 1 : 0;
+}
+
+void aotg_start_ring(struct aotg_ring *ring, u32 addr)
+{
+ struct aotg_trb *temp_trb = ring->dequeue_trb;
+ int i;
+ if ((ring->type == PIPE_BULK) && ((temp_trb->hw_token & TRB_OF)== 0)) {
+ for (i=0; i< NUM_TRBS; i++) {
+ if (temp_trb->hw_token == 0xaa) { /*deal dequeue urb*/
+ inc_dequeue_safe(ring);
+ memset(temp_trb,0,sizeof(struct aotg_trb));
+ }
+ else if (temp_trb->hw_token & TRB_OF) {
+ break;
+ }
+
+ if (temp_trb == ring->last_trb) {
+ temp_trb= ring->first_trb;
+ }
+ else {
+ temp_trb++;
+ }
+ }
+ addr = ring_trb_virt_to_dma(ring, temp_trb);
+ }
+ aotg_set_ring_linkaddr(ring, addr);
+ mb();
+ writel(DMACTRL_DMACS,ring->reg_dmactrl);
+
+}
+
+void aotg_stop_ring(struct aotg_ring *ring)
+{
+ writel(DMACTRL_DMACC, ring->reg_dmactrl);
+}
+
+void aotg_pause_ring(struct aotg_ring *ring)
+{
+ usb_setbitsl(DMACTRL_DMACC, ring->reg_dmactrl);
+}
+
+#if(0)
+void aotg_stop_ring(struct aotg_hcd *acthcd, struct aotg_hcep *ep)
+{
+ writel(DMACTRL_DMACC,ep->ring->reg_dmactrl);
+ usb_clearbitsb(0x80, ep->reg_hcepcon);
+ usb_settoggle(ep->udev, ep->epnum, ep->is_out, 0);
+ aotg_hcep_reset(acthcd, ep->mask, ENDPRST_FIFORST);
+ writeb(ep->epnum, ep->reg_hcepctrl);
+ usb_setbitsb(0x80, ep->reg_hcepcon);
+}
+#endif
+
+u32 ring_trb_virt_to_dma(struct aotg_ring *ring,
+ struct aotg_trb *trb_vaddr)
+{
+ u32 addr;
+
+ unsigned long offset;
+
+ if (!ring || !trb_vaddr) {
+ return 0;
+ }
+
+ if (trb_vaddr > ring->last_trb) {
+ return 0;
+ }
+
+ offset = trb_vaddr - ring->first_trb;
+ //return ring->trb_dma + (offset * sizeof(*trb_vaddr));
+ addr = ring->trb_dma + (offset * sizeof(*trb_vaddr));
+
+ //addr = (u32)virt_to_phys(trb_vaddr);
+ //printk("---out:%d,offset:%ld, trb:0x%x,addr:0x%x------\n",ring->is_out,offset,
+ // trb_vaddr, addr);
+ return addr;
+
+}
+
+void aotg_set_ring_linkaddr(struct aotg_ring *ring, u32 addr)
+{
+ if (!ring) {
+ ACT_HCD_ERR
+ return;
+ }
+ writel(addr, ring->reg_dmalinkaddr);
+
+ //printk("linkaddr(0x%p):0x%x\n", ring->reg_dmalinkaddr,
+ // readl(ring->reg_dmalinkaddr));
+}
+
+int aotg_set_trb_as_ring_linkaddr(struct aotg_ring *ring, struct aotg_trb *trb)
+{
+ u32 addr;
+
+ addr = (u32)ring_trb_virt_to_dma(ring, trb);
+ if (!addr) {
+ ACT_HCD_ERR
+ return -1;
+ }
+
+ aotg_set_ring_linkaddr(ring, addr);
+ return 0;
+}
+
+int ring_empty(struct aotg_ring *ring)
+{
+ return (atomic_read(&ring->num_trbs_free) == NUM_TRBS) ? 1 : 0;
+}
+
+int ring_full(struct aotg_ring *ring)
+{
+ return (atomic_read(&ring->num_trbs_free) == 0) ? 1 : 0;
+}
+
+inline int is_room_on_ring(struct aotg_ring *ring, unsigned int num_trbs)
+{
+ return (num_trbs > atomic_read(&ring->num_trbs_free)) ? 0 : 1;
+}
+
+inline unsigned int count_urb_need_trbs(struct urb *urb)
+{
+ int num_sgs, num_trbs;
+ /* at least one trb */
+ num_sgs = urb->num_mapped_sgs;
+ if (num_sgs == 0) {
+ num_trbs = 1;
+ } else {
+ num_trbs = num_sgs;
+ }
+
+ if (usb_pipeout(urb->pipe) &&
+ (urb->transfer_flags & URB_ZERO_PACKET)) {
+ num_trbs++;
+ }
+
+ return num_trbs;
+}
+
+void aotg_fill_trb(struct aotg_trb *trb,
+ u32 dma_addr, u32 len, u32 token)
+{
+ trb->hw_buf_ptr = dma_addr;
+ trb->hw_buf_len = len;
+ trb->hw_token = token;
+
+ ACT_LINKLIST_DMA_DEBUG("hw_ptr(0x%x), hw_len(%d),hw_token(0x%x)\n",
+ trb->hw_buf_ptr, trb->hw_buf_len, trb->hw_token);
+ return;
+}
+
+int aotg_sg_map_trb(struct aotg_trb *trb,
+ struct scatterlist *sg, int len, u32 token)
+{
+ int this_trb_len;
+
+ if (NULL == sg) {
+ aotg_fill_trb(trb, 0, 0, token);
+ return 0;
+ }
+
+ this_trb_len = min_t(int, sg_dma_len(sg), len);
+
+ aotg_fill_trb(trb, (u32)sg_dma_address(sg), this_trb_len, token);
+
+ return this_trb_len;
+}
+#if (0)
+/*
+ * ring->enqueue_trb should be overflow
+ */
+void inc_enqueue_safe(struct aotg_ring *ring)
+{
+ atomic_dec(&ring->num_trbs_free);
+ if (ring->enqueue_trb == ring->ring_trb) {
+ if (ring->type == PIPE_BULK) {
+ ring->enqueue_trb->hw_token &= ~TRB_CHN;
+ if (ring->is_out)
+ ring->enqueue_trb->hw_token |= TRB_ITE | TRB_LT;
+ else
+ ring->enqueue_trb->hw_token |= TRB_ICE | TRB_LT;
+ ring->enqueue_trb = ring->first_trb;
+ } else {
+ ring->enqueue_trb->hw_token |= TRB_COF;
+ ring->enqueue_trb = ring->first_trb;
+ }
+ } else {
+ ring->enqueue_trb += 1;
+ }
+}
+#endif
+void enqueue_trb(struct aotg_ring *ring, u32 buf_ptr, u32 buf_len,
+ u32 token)
+{
+ struct aotg_trb *trb;
+ trb = ring->enqueue_trb;
+
+ atomic_dec(&ring->num_trbs_free);
+ if (trb == ring->last_trb) {
+ if (ring->type == PIPE_BULK) {
+ token &= ~TRB_CHN;
+ if (ring->is_out)
+ token |= TRB_ITE | TRB_LT;
+ else
+ token |= TRB_ICE | TRB_LT;
+ ring->enqueue_trb = ring->first_trb;
+ } else {
+ token |= TRB_COF;
+ ring->enqueue_trb = ring->first_trb;
+ }
+ } else {
+ ring->enqueue_trb += 1;
+ }
+
+ trb->hw_buf_ptr = buf_ptr;
+ trb->hw_buf_len = buf_len;
+ trb->hw_buf_remain = 0;
+ wmb();
+ trb->hw_token = token;
+}
+
+/*
+ * ensure ring has enough room for this td
+ * before call this function.
+ */
+int ring_enqueue_sg_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td)
+{
+ u8 is_out;
+ int num_sgs, num_trbs;
+ int len, this_trb_len;
+ u32 addr, token;
+ struct urb *urb = td->urb;
+ struct scatterlist *sg;
+
+ is_out = usb_pipeout(urb->pipe);
+
+ len = urb->transfer_buffer_length;
+ num_sgs = urb->num_mapped_sgs;
+ num_trbs = count_urb_need_trbs(urb);
+
+ td->num_trbs = num_trbs;
+ td->trb_vaddr = ring->enqueue_trb;
+ td->trb_dma= ring_trb_virt_to_dma(ring, ring->enqueue_trb);
+
+ if (td->trb_vaddr + (num_trbs - 1) > ring->last_trb) {
+ td->cross_ring = 1;
+ }
+
+ sg = urb->sg;
+ addr = (u32)sg_dma_address(sg);
+ this_trb_len = (u32)min_t(int, sg_dma_len(sg), len);
+
+ if (is_out)
+ token = TRB_OF;
+ else
+ //token = TRB_CSP | TRB_ISE | TRB_IZE | TRB_OF;
+ token = TRB_CSP | TRB_OF;
+
+ do {
+ if (num_trbs == 1) {
+ token &= ~TRB_CHN;
+ if (is_out)
+ token |= TRB_ITE;
+ else
+ token |= TRB_ICE;
+
+ if (is_out && (urb->transfer_flags & URB_ZERO_PACKET))
+ enqueue_trb(ring, 0, 0, token);
+ else
+ enqueue_trb(ring, addr, this_trb_len, token);
+ break;
+ }
+ token |= TRB_CHN;
+ enqueue_trb(ring, addr, this_trb_len, token);
+ len -= this_trb_len;
+ num_trbs--;
+ num_sgs--;
+
+ if (num_sgs) {
+ sg = sg_next(sg);
+ addr = (u32)sg_dma_address(sg);
+ this_trb_len = (u32)min_t(int, sg_dma_len(sg), len);
+ }
+ } while (num_trbs);
+
+ //aotg_hcd_dump_td(ring, td);
+
+ return 0;
+}
+
+int aotg_ring_enqueue_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td)
+{
+ u8 is_out;
+ u32 addr, token, this_trb_len;
+ int num_trbs;
+ struct urb *urb = td->urb;
+
+ if (!acthcd || !td || !ring || !urb) {
+ ACT_HCD_ERR
+ return -1;
+ }
+
+ num_trbs = count_urb_need_trbs(urb);
+
+ if (!is_room_on_ring(ring, num_trbs)) {
+ //ACT_HCD_DBG
+ return -1;
+ }
+
+ if (urb->num_sgs) {
+ return ring_enqueue_sg_td(acthcd, ring, td);
+ }
+
+ is_out = usb_pipeout(urb->pipe);
+
+ td->num_trbs = num_trbs;
+ td->trb_vaddr = ring->enqueue_trb;
+ td->trb_dma = ring_trb_virt_to_dma(ring, ring->enqueue_trb);
+
+ addr = (u32)urb->transfer_dma;
+ this_trb_len = (u32)urb->transfer_buffer_length;
+
+ if (is_out) {
+ token = TRB_OF;
+ } else {
+ token = TRB_CSP | TRB_OF;
+ }
+
+ /*
+ * Finish bulk OUT with short packet
+ */
+ if (num_trbs > 1) {
+ token |= TRB_CHN;
+ enqueue_trb(ring, addr, this_trb_len, token);
+ addr = 0;
+ this_trb_len = 0;
+ }
+
+ token &= ~TRB_CHN;
+ if (!port_host_plug_detect[acthcd->id])
+ token |= TRB_LT; /*8723bu,release cpu for interrupt transfer*/
+ if (is_out)
+ token |= TRB_ITE;
+ else
+ token |= TRB_ICE;
+
+ enqueue_trb(ring, addr, this_trb_len, token);
+
+ //aotg_hcd_dump_td(ring, td);
+
+ return 0;
+}
+
+void aotg_reorder_intr_td( struct aotg_hcep *ep) {
+ struct aotg_td *td, *next, *entry_td = NULL;
+ struct urb *urb;
+ struct aotg_ring *ring;
+ unsigned long td_temp = ULONG_MAX;
+ ring = ep->ring;
+
+ ring->dequeue_trb = ring->first_trb;
+ ring->enqueue_trb = ring->first_trb;
+ list_for_each_entry(td, &ep->enring_td_list, enring_list) {
+ if (td_temp > (unsigned long)(td->intr_mem_vaddr)) {
+ td_temp = (unsigned long)(td->intr_mem_vaddr);
+ entry_td = td;
+ }
+ }
+
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ if ((unsigned long)(td->intr_mem_vaddr) > td_temp) {
+ if (td->urb) {
+ urb = td->urb;
+ td->urb = NULL;
+ entry_td->urb = urb;
+ entry_td = list_entry(entry_td->enring_list.next,struct aotg_td,enring_list);
+ }
+ list_del(&td->enring_list);
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ }
+ else {
+ break;
+ }
+ }
+}
+
+void aotg_reorder_iso_td(struct aotg_hcd *acthcd, struct aotg_ring *ring) {
+ struct aotg_td *td, *next;
+ struct aotg_trb *new_trb_q, *prev_trb_q, *trb;
+ int i;
+ dma_addr_t dma, prev_dma;
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+ struct aotg_hcep *ep = (struct aotg_hcep *)ring->priv;
+
+ new_trb_q = (struct aotg_trb *)
+ dma_alloc_coherent(dev, NUM_TRBS * sizeof(struct aotg_trb),
+ &dma, GFP_ATOMIC);
+ if (!new_trb_q) {
+ pr_err("dma_alloc_coherent trb error!!!\n" );
+ return;
+ }
+ memset(new_trb_q, 0, NUM_TRBS * sizeof(struct aotg_trb));
+ prev_trb_q = ring->first_trb;
+ ring->first_trb = new_trb_q;
+ prev_dma = ring->trb_dma;
+ ring->trb_dma = (u32)dma;
+ ring->last_trb = ring->first_trb + NUM_TRBS - 1;
+ ring->ring_trb = ring->last_trb;
+ atomic_set(&ring->num_trbs_free, NUM_TRBS);
+ ring->enqueue_trb = ring->first_trb;
+ ring->dequeue_trb = ring->first_trb;
+
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ if (td) {
+ trb = td->trb_vaddr;
+ td->trb_vaddr = ring->enqueue_trb;
+ td->trb_dma = ring_trb_virt_to_dma(ring, ring->enqueue_trb);
+ for (i = 0; i < td->num_trbs; i++) {
+ enqueue_trb(ring, trb->hw_buf_ptr, trb->hw_buf_len, trb->hw_token &(~TRB_COF));
+ }
+ }
+ }
+ dma_free_coherent(dev, NUM_TRBS * sizeof(struct aotg_trb), prev_trb_q, prev_dma);
+}
+
+int aotg_ring_enqueue_intr_td(struct aotg_hcd *acthcd, struct aotg_ring *ring,
+ struct aotg_hcep *ep, struct urb *urb, gfp_t mem_flags)
+{
+ u8 is_out;
+ u32 addr, token, this_trb_len;
+ int i;
+ int mem_size;
+ dma_addr_t dma;
+ struct aotg_td *td, *next;
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+
+ if (!is_room_on_ring(ring, INTR_TRBS)) {
+ printk("%s err, check it!\n", __FUNCTION__);
+ return -1;
+ }
+
+ is_out = usb_pipeout(urb->pipe);
+ //mem_size = max(urb->transfer_buffer_length,usb_maxpacket(ep->udev, urb->pipe, is_out));
+ mem_size = urb->transfer_buffer_length;
+ //printk("====ep:%p,mem_size:%d...........====\n",ep,mem_size);
+ ring->intr_mem_size = mem_size;
+ ring->intr_dma_buf_vaddr = (u8 *)dma_alloc_coherent(dev, mem_size * INTR_TRBS,
+ &dma, mem_flags);
+ if (!ring->intr_dma_buf_vaddr) {
+ printk("%s err, alloc dma buf for intr fail!\n", __FUNCTION__);
+ return -1;
+ }
+ ring->intr_dma_buf_phyaddr = dma;
+ //printk("dma_buf_vaddr:0x%p, dma_buf_phyaddr:0x%x\n",
+ // ring->intr_dma_buf_vaddr, (u32)ring->intr_dma_buf_phyaddr);
+
+ for (i = 0; i < INTR_TRBS; i++) {
+ td = aotg_alloc_td(mem_flags);
+ if (!td) {
+ printk("%s err, alloc td fail\n", __FUNCTION__);
+ goto fail;
+ }
+ td->intr_mem_vaddr = ring->intr_dma_buf_vaddr + mem_size * i;
+ td->intr_men_phyaddr = ring->intr_dma_buf_phyaddr + mem_size * i;
+ //td->intr_mem_phyaddr = virt_to_phys(td->intr_mem_vaddr);
+ memset(td->intr_mem_vaddr, 0, mem_size);
+// printk("buf_%d virt_addr:0x%p, phy_addr:0x%x, size:%d\n",
+// i, td->intr_mem_vaddr, (u32)td->intr_men_phyaddr, mem_size);
+
+ td->num_trbs = 1;
+ td->trb_vaddr = ring->enqueue_trb;
+ td->trb_dma = ring_trb_virt_to_dma(ring, ring->enqueue_trb);
+
+ this_trb_len = mem_size;
+ if (is_out) {
+ token = TRB_OF | TRB_ITE | TRB_LT;
+ enqueue_trb(ring, urb->transfer_dma, this_trb_len, token);
+ } else {
+ token = TRB_OF | TRB_ICE | TRB_CSP;
+ addr = (u32)td->intr_men_phyaddr;
+ enqueue_trb(ring, addr, this_trb_len, token);
+ }
+
+
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ ring->enring_cnt++;
+ }
+
+ ring->intr_inited = 1;
+ return 0;
+
+fail:
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ aotg_release_td(td);
+ }
+
+ dma_free_coherent(dev, ring->intr_mem_size * INTR_TRBS,
+ ring->intr_dma_buf_vaddr, ring->intr_dma_buf_phyaddr);
+
+ return -1;
+}
+
+int aotg_intr_get_finish_trb(struct aotg_ring *ring)
+{
+ int i,count = 0;
+ struct aotg_trb *trb = ring->first_trb;
+
+ for (i=0; i<INTR_TRBS; i++) {
+ if ((trb->hw_token&TRB_OF) == 0) {
+ count++;
+ }
+ trb++;
+ }
+ return count;
+}
+
+int aotg_intr_chg_buf_len(struct aotg_hcd *acthcd, struct aotg_ring *ring, int len)
+{
+ struct aotg_td *td;
+ dma_addr_t dma;
+ int i = 0;
+ u32 token;
+ struct aotg_hcep *ep = (struct aotg_hcep *)ring->priv;
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+ //aotg_stop_ring(ring);
+ writel(DMACTRL_DMACC,ring->reg_dmactrl);
+ usb_clearbitsb(0x80, ep->reg_hcepcon);
+ usb_settoggle(ep->udev, ep->epnum, ep->is_out, 0);
+ aotg_hcep_reset(acthcd, ep->mask, ENDPRST_FIFORST);
+ writeb(ep->epnum, ep->reg_hcepctrl);
+ usb_setbitsb(0x80, ep->reg_hcepcon);
+
+ dma_free_coherent(dev, ring->intr_mem_size * INTR_TRBS,
+ ring->intr_dma_buf_vaddr, ring->intr_dma_buf_phyaddr);
+
+ ring->intr_mem_size = len;
+ ring->intr_dma_buf_vaddr = (u8 *)dma_alloc_coherent(dev, len * INTR_TRBS,
+ &dma, GFP_ATOMIC);
+ if (!ring->intr_dma_buf_vaddr) {
+ printk("%s err, alloc dma buf for intr fail!\n", __FUNCTION__);
+ return -1;
+ }
+ ring->intr_dma_buf_phyaddr = dma;
+
+ aotg_reorder_intr_td(ep);
+ list_for_each_entry(td, &ep->enring_td_list, enring_list) {
+ td->intr_mem_vaddr = ring->intr_dma_buf_vaddr + len * i;
+ td->intr_men_phyaddr = ring->intr_dma_buf_phyaddr + len * i;
+ memset(td->intr_mem_vaddr, 0, len);
+
+ if (ring->is_out)
+ token = TRB_OF | TRB_ITE | TRB_LT;
+ else
+ token = TRB_OF | TRB_ICE | TRB_CSP;
+
+ enqueue_trb(ring, td->intr_men_phyaddr, len, token);
+ i++;
+ }
+ mb();
+ writel(DMACTRL_DMACS,ep->ring->reg_dmactrl);
+
+ return 0;
+}
+
+void aotg_intr_dma_buf_free(struct aotg_hcd *acthcd, struct aotg_ring *ring)
+{
+ struct aotg_td *td, *next;
+ struct aotg_hcep *ep = (struct aotg_hcep *)ring->priv;
+ struct device *dev = aotg_to_hcd(acthcd)->self.controller;
+
+ list_for_each_entry_safe(td, next, &ep->enring_td_list, enring_list) {
+ aotg_release_td(td);
+ }
+
+ dma_free_coherent(dev, ring->intr_mem_size * INTR_TRBS,
+ ring->intr_dma_buf_vaddr, ring->intr_dma_buf_phyaddr);
+}
+
+int aotg_ring_enqueue_isoc_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td)
+{
+ u8 is_out;
+ u32 start_addr;
+ u32 addr, token, this_trb_len;
+ int i = 0;
+ int start_frame;
+ int num_trbs;
+ struct urb *urb = td->urb;
+
+ if (!acthcd || !td || !ring || !urb) {
+ ACT_HCD_ERR
+ return -1;
+ }
+
+ num_trbs = urb->number_of_packets;
+ if (unlikely(num_trbs == 0)) {
+ ACT_HCD_ERR
+ return -1;
+ }
+
+ if (unlikely(!is_room_on_ring(ring, num_trbs))) {
+ ACT_HCD_DBG
+ return -1;
+ }
+
+ is_out = usb_pipeout(urb->pipe);
+
+ td->num_trbs = num_trbs;
+ td->trb_vaddr = ring->enqueue_trb;
+ td->trb_dma = ring_trb_virt_to_dma(ring, ring->enqueue_trb);
+
+ start_frame = readw(acthcd->base + HCFRMNRL);
+ start_frame &= 0x3fff;
+ urb->start_frame = start_frame;
+
+ start_addr = (u32)urb->transfer_dma;
+
+ if (is_out) {
+ token = TRB_OF;
+ } else {
+ token = TRB_CSP | TRB_OF;
+ }
+
+ do {
+ addr = start_addr + urb->iso_frame_desc[i].offset;
+ this_trb_len = urb->iso_frame_desc[i].length;
+ if (num_trbs == 1) {
+ token &= ~TRB_CHN;
+ if (is_out)
+ token |= TRB_ITE;
+ else
+ token |= TRB_ICE;
+
+ enqueue_trb(ring, addr, this_trb_len, token);
+ break;
+ }
+ enqueue_trb(ring, addr, this_trb_len, token);
+ i++;
+ num_trbs--;
+ } while(num_trbs);
+
+ return 0;
+}
+
+void dequeue_td(struct aotg_ring *ring, struct aotg_td *td, int dequeue_flag)
+{
+ int i,num_trbs;
+ struct aotg_trb *trb;
+
+ if (!ring || !td || ((struct list_head *)(&td->enring_list)->next == LIST_POISON1)) {
+ ACT_HCD_ERR
+ return;
+ }
+ trb = td->trb_vaddr;
+ num_trbs = td->num_trbs;
+ for (i = 0; i < num_trbs; i++) {
+ if (dequeue_flag != TD_IN_RING) {
+ inc_dequeue_safe(ring);
+ memset(trb,0,sizeof(struct aotg_trb));
+ }
+ else {
+ /*perhaps the dequeue urb in the middle of queue_list,don't change ring->dequeue here*/
+ trb->hw_token = 0xaa;
+ }
+ if (trb == ring->last_trb) {
+ trb = ring->first_trb;
+ }
+ else {
+ trb++;
+ }
+ }
+ list_del(&td->enring_list);
+ aotg_release_td(td);
+ ring->dering_cnt++;
+}
+
+void dequeue_intr_td(struct aotg_ring *ring, struct aotg_td *td)
+{
+ u32 addr, token, this_trb_len;
+ struct aotg_trb *trb;
+ struct aotg_hcep *ep;
+
+ if (!ring || !td) {
+ ACT_HCD_ERR
+ return;
+ }
+
+ trb = td->trb_vaddr;
+ inc_dequeue_safe(ring);
+ list_del(&td->enring_list);
+ ring->dering_cnt++;
+
+ td->urb = NULL;
+ memset(td->intr_mem_vaddr, 0, ring->intr_mem_size);
+
+ if (ring->is_out)
+ token = TRB_OF | TRB_ITE | TRB_LT;
+ else
+ token = TRB_OF | TRB_ICE | TRB_CSP;
+ this_trb_len = ring->intr_mem_size;
+ addr = (u32)td->intr_men_phyaddr;
+
+ ep = (struct aotg_hcep *)ring->priv;
+ enqueue_trb(ring, addr, this_trb_len, token);
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ ring->enring_cnt++;
+ return;
+}
+
+#if (1)
+int aotg_ring_dequeue_intr_td(struct aotg_hcd *acthcd, struct aotg_hcep *ep,
+ struct aotg_ring *ring, struct aotg_td *td)
+{
+ u32 addr;
+ struct aotg_td *td_tmp;
+
+ /*To INTR transfer: first dequeue happens at the last step of insertion
+ while there isn't any data transmission, so we just empty the urb of
+ the first td but don't dequeue the td.*/
+ // aotg_stop_ring(ring);
+ if (td->trb_vaddr->hw_token & TRB_OF)
+ td->urb = NULL;
+ else
+ dequeue_intr_td(ring, td);
+
+ td_tmp = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if ((td_tmp) && (td_tmp->urb)) {
+ printk("%s, unormal circumstances, pls check it...\n", __FUNCTION__);
+ printk("restart ep%d intr ring\n", ep->index);
+ addr = ring_trb_virt_to_dma(ring, ring->dequeue_trb);
+ aotg_start_ring(ring, addr);
+ }
+ return 0;
+}
+#else
+int aotg_ring_dequeue_intr_td(struct aotg_hcd *acthcd, struct aotg_hcep *ep,
+ struct aotg_ring *ring, struct aotg_td *td)
+{
+ struct aotg_trb *trb;
+ trb = td->trb_vaddr;
+
+ writel(DMACTRL_DMACC,ep->ring->reg_dmactrl);
+ usb_clearbitsb(0x80, ep->reg_hcepcon);
+ usb_settoggle(ep->udev, ep->epnum, ep->is_out, 0);
+ aotg_hcep_reset(acthcd, ep->mask, ENDPRST_FIFORST);
+ writeb(ep->epnum, ep->reg_hcepctrl);
+ usb_setbitsb(0x80, ep->reg_hcepcon);
+
+ td->urb = NULL;
+ mb();
+ trb->hw_token |= TRB_OF;
+ trb->hw_token &= ~(AOTG_TRB_IOC|AOTG_TRB_IOZ|AOTG_TRB_IOS);
+ aotg_reorder_intr_td(ep);
+
+ /*td_tmp = list_first_entry(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (td_tmp->urb) {
+ printk("%s, unormal circumstances, pls check it...\n", __FUNCTION__);
+ printk("restart ep%d intr ring\n", ep->index);
+ addr = ring_trb_virt_to_dma(ring, ring->dequeue_trb);
+ aotg_start_ring(ring, addr);
+ }*/
+
+ return 0;
+}
+#endif
+
+int aotg_ring_dequeue_td(struct aotg_hcd *acthcd, struct aotg_ring *ring,
+ struct aotg_td *td, int dequeue_flag)
+{
+ int index;
+ struct aotg_hcep *ep;
+ struct urb *urb = td->urb;
+ td->urb = NULL;
+ //u32 addr;
+
+ //u32 ring_curaddr;
+
+ //ring_curaddr = readl(ring->reg_curaddr);
+
+ //aotg_hcd_dump_td(ring, td);
+
+ if (dequeue_flag == TD_IN_QUEUE) {
+ /*
+ * must hold the spin_lock_irq, prevent td will be enqueue in ep->enring_list
+ * in interrupt contex
+ */
+ list_del(&td->queue_list);
+ aotg_release_td(td);
+ //ACT_HCD_DBG
+ return 0;
+ } else if (dequeue_flag == TD_IN_RING) {
+ //if (ring_curaddr < td->trb_dma ||
+ // ring_curaddr > ring_trb_virt_to_dma(ring, td->trb_vaddr + td->num_trbs -1)) {
+ // printk(KERN_ERR"%s, unknow situation!\n", __FUNCTION__);
+ //}
+ ep = (struct aotg_hcep *)urb->ep->hcpriv;
+ //aotg_stop_ring(ring);
+ writel(DMACTRL_DMACC,ep->ring->reg_dmactrl);
+ usb_clearbitsb(0x80, ep->reg_hcepcon);
+ usb_settoggle(ep->udev, ep->epnum, ep->is_out, 0);
+ aotg_hcep_reset(acthcd, ep->mask, ENDPRST_FIFORST);
+ writeb(ep->epnum, ep->reg_hcepctrl);
+ usb_setbitsb(0x80, ep->reg_hcepcon);
+ /*
+ * dequeue urb, when the urb complete in hardware contex
+ */
+ index = ring->mask & 0xf;
+ if ((0x1 << index) & (readw(acthcd->base + HCINxDMAIRQ0)) ||
+ (0x1 << index) & (readw(acthcd->base + HCOUTxBUFEMPTYIRQ0))) {
+ printk("noticd:%s, IN%dIRQ:0x%x; OUT%dIRQ:0x%x\n",
+ __FUNCTION__, index, readw(acthcd->base + HCINxDMAIRQ0),
+ index, readw(acthcd->base + HCOUTxBUFEMPTYIRQ0));
+ clear_ring_irq(acthcd, ring->mask);
+ }
+
+ dequeue_td(ring, td, dequeue_flag);
+ //ACT_HCD_DBG
+ /*
+ * need restart the remain td in the ring or wait to be dequeue ?
+ */
+ /*if (!ring_empty(ring)) {
+ addr = ring_trb_virt_to_dma(ring, ring->dequeue_trb);
+ aotg_start_ring(ring, addr);
+ //ACT_HCD_DBG
+ }*/
+ }
+
+ return 0;
+}
+
+unsigned int get_ring_irq(struct aotg_hcd *acthcd)
+{
+ unsigned int data;
+ unsigned int i;
+ unsigned int pending = 0;
+
+// printk("%s,INdma(0x%p):0x%x\n", __FUNCTION__,
+// acthcd->base + HCINxDMAIRQ0,
+// readw(acthcd->base + HCINxDMAIRQ0));
+
+ data = readw(acthcd->base+ HCINxDMAIRQ0);
+
+ if (data) {
+ for (i = 1; i < 16; i++) {
+ if (data & (0x1 << i)) {
+ pending = i;
+ return pending;
+ }
+ }
+ }
+
+ data = readw(acthcd->base + HCOUTxBUFEMPTYIRQ0);
+
+ if (data) {
+ for (i = 1; i < 16; i++) {
+ if (data & (0x1 << i)) {
+ pending = i | AOTG_DMA_OUT_PREFIX;
+ return pending;
+ }
+ }
+ }
+
+ return pending;
+}
+
+void clear_ring_irq(struct aotg_hcd *acthcd, unsigned int irq_mask)
+{
+ int index;
+ u8 is_out = irq_mask & AOTG_DMA_OUT_PREFIX;
+ index = irq_mask & 0xf;
+// u32 cnt;
+
+
+ if (is_out) {
+ writew((0x1 << index), (acthcd->base + HCOUTxBUFEMPTYIRQ0));
+ } else {
+ writew((0x1 << index), (acthcd->base + HCINxDMAIRQ0));
+ }
+
+// printk("%s,(0x%p):0x%x\n", __FUNCTION__,
+// acthcd->base + HCOUTxBUFEMPTYIRQ0,
+// readw(acthcd->base + HCOUTxBUFEMPTYIRQ0));
+
+ return;
+}
+
+int finish_td(struct aotg_hcd *acthcd, struct aotg_ring *ring, struct aotg_td *td)
+{
+ struct urb *urb;
+ struct aotg_trb *trb;
+ int num_trbs;
+ int i, trb_tx_len, length = 0;
+ int status;
+
+ urb = td->urb;
+ trb = td->trb_vaddr;
+ num_trbs = td->num_trbs;
+
+ if (td->cross_ring) {
+ if ((ring->last_trb->hw_token & TRB_OF) != 0)
+ return -1;
+ td->cross_ring = 0;
+ aotg_set_trb_as_ring_linkaddr(ring, ring->first_trb);
+ usb_setbitsl(DMACTRL_DMACS, ring->reg_dmactrl);
+ //aotg_hcd_dump_trb(ring, ring->first_trb);
+ return 1;
+ }
+
+ for (i = 0; i < num_trbs; i++) {
+ if (trb->hw_token & (AOTG_TRB_IOS | AOTG_TRB_IOZ)){
+ trb_tx_len = trb->hw_buf_len - trb->hw_buf_remain;
+ length += trb_tx_len;
+ break;
+ } else if (trb->hw_token & AOTG_TRB_IOC) {
+ length += trb->hw_buf_len;
+ } else {
+// printk("%s, td still not finish\n", __FUNCTION__);
+ //aotg_hcd_dump_td(ring, td);
+ return -1;
+ }
+ if (trb == ring->last_trb)
+ trb = ring->first_trb;
+ else
+ trb += 1;
+ }
+
+#if 0
+ if (usb_pipetype(urb->pipe) == PIPE_BULK)
+ aotg_hcd_dump_td(ring, td);
+#endif
+
+ dequeue_td(ring, td, TD_IN_FINISH);
+
+ urb->actual_length = length;
+ status = 0;
+
+
+ if (urb->actual_length > urb->transfer_buffer_length) {
+ ACT_HCD_DBG
+ urb->actual_length = 0;
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+ status = -EREMOTEIO;
+ else
+ status = 0;
+ }
+
+ usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
+ spin_lock(&acthcd->lock);
+ /* when unlock,maybe list_del(&td->enring_list) in dequeue_td*/
+ if ((urb->ep) && unlikely(!urb->ep->enabled)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int intr_finish_td(struct aotg_hcd *acthcd, struct aotg_ring *ring, struct aotg_td *td)
+{
+ int length;
+ int status;
+ struct urb *urb;
+ struct aotg_trb *trb;
+
+ trb = td->trb_vaddr;
+ if (td->urb == NULL) {
+ //printk("%s err, pls fix it!\n", __FUNCTION__);
+ if ((trb->hw_token&TRB_OF) == 0) {
+ aotg_stop_ring(ring);
+ }
+ return -1;
+ }
+
+
+ urb = td->urb;
+
+ if (trb->hw_token & (AOTG_TRB_IOS | AOTG_TRB_IOZ)){
+ length = trb->hw_buf_len - trb->hw_buf_remain;
+ } else if (trb->hw_token & AOTG_TRB_IOC) {
+ length = trb->hw_buf_len;
+ } else {
+ return -1;
+ }
+
+ if (!ring->is_out)
+ memcpy(urb->transfer_buffer, td->intr_mem_vaddr, length);
+ dequeue_intr_td(ring, td);
+
+ urb->actual_length = length;
+ status = 0;
+
+ usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
+ spin_lock(&acthcd->lock);
+
+ return 0;
+}
+
+int isoc_finish_td(struct aotg_hcd *acthcd, struct aotg_ring *ring, struct aotg_td *td)
+{
+ struct urb *urb;
+ struct aotg_trb *trb;
+ int num_trbs;
+ int i, trb_tx_len, length = 0;
+ int status;
+
+// mb();
+ if (!ring || !td || ((struct list_head *)(&td->enring_list)->next == LIST_POISON1)) {
+ ACT_HCD_ERR
+ return -1;
+ }
+
+ urb = td->urb;
+ if (!urb || !urb->dev)
+ return -1;
+ trb = td->trb_vaddr;
+ num_trbs = td->num_trbs;
+
+ for (i = 0; i < num_trbs; i++) {
+ if (trb->hw_token & (AOTG_TRB_IOS | AOTG_TRB_IOZ)){
+ trb_tx_len = trb->hw_buf_len - trb->hw_buf_remain;
+ urb->iso_frame_desc[i].actual_length = trb_tx_len;
+ urb->iso_frame_desc[i].status = 0;
+ length += trb_tx_len;
+ } else if (trb->hw_token & AOTG_TRB_IOC) {
+ trb_tx_len = trb->hw_buf_len;
+ urb->iso_frame_desc[i].actual_length = trb_tx_len;
+ urb->iso_frame_desc[i].status = 0;
+ length += trb->hw_buf_len;
+ } else {
+ //printk("%s, td still not finish\n", __FUNCTION__);
+ //aotg_hcd_dump_td(ring, td);
+ return -1;
+ }
+ if (trb == ring->last_trb)
+ trb = ring->first_trb;
+ else
+ trb += 1;
+ }
+
+ td->urb = NULL;
+ dequeue_td(ring, td, TD_IN_FINISH);
+
+ urb->actual_length = length;
+ status = 0;
+
+ usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
+ spin_unlock(&acthcd->lock);
+ usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
+ spin_lock(&acthcd->lock);
+
+ return 0;
+}
+
+void handle_ring_dma_tx(struct aotg_hcd *acthcd, unsigned int irq_mask)
+{
+ int ret;
+ struct aotg_td *td = NULL, *next;
+ struct aotg_ring *ring;
+ struct aotg_hcep *ep;
+
+ if (AOTG_IS_DMA_OUT(irq_mask)) {
+ ep = acthcd->outep[AOTG_GET_DMA_NUM(irq_mask)];
+ } else {
+ ep = acthcd->inep[AOTG_GET_DMA_NUM(irq_mask)];
+ }
+ if (ep == NULL) {
+ ACT_HCD_ERR
+ return;
+ }
+ ep->error_count = 0;
+
+ ring = ep->ring;
+ if (!ring) {
+ ACT_HCD_ERR
+ return;
+ }
+
+ if (list_empty(&ep->enring_td_list) || ring_empty(ring))
+ return;
+
+ if (ring->type == PIPE_ISOCHRONOUS) {
+ do {
+ mb();
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td)
+ break;
+ ret = isoc_finish_td(acthcd, ring, td);
+ } while (ret == 0);
+
+ if (!list_empty(&ep->queue_td_list)) {
+ list_for_each_entry_safe(td, next, &ep->queue_td_list, queue_list) {
+ ret = aotg_ring_enqueue_isoc_td(acthcd, ring, td);
+ if (ret)
+ return;
+ list_del(&td->queue_list);
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ ring->enring_cnt++;
+ }
+ }
+
+ if (!list_empty(&ep->enring_td_list) && !is_ring_running(ring)) {
+ if (ring->dequeue_trb != ring->first_trb)
+ aotg_reorder_iso_td(acthcd, ring);
+ aotg_start_ring(ring, ring_trb_virt_to_dma(ring, ring->dequeue_trb));
+ }
+ else if (list_empty(&ep->enring_td_list) && is_ring_running(ring)) {
+ aotg_stop_ring(ring);
+ }
+ return;
+ } else if (ring->type == PIPE_INTERRUPT) {
+ if (!ring->intr_started)
+ return;
+ do {
+ mb();
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td)
+ break;
+ ret = intr_finish_td(acthcd, ring, td);
+ } while (ret == 0);
+
+ if (!is_ring_running(ring)) {
+ pr_debug("%s, intr stop!\n", __func__);
+ }
+ return;
+ }
+
+ do {
+ mb();
+ td = list_first_entry_or_null(&ep->enring_td_list, struct aotg_td, enring_list);
+ if (!td)
+ break;
+ ret = finish_td(acthcd, ring, td);
+ } while (ret == 0);
+
+ if (ret == 1)
+ return;
+
+ if (!list_empty(&ep->queue_td_list)) {
+ list_for_each_entry_safe(td, next, &ep->queue_td_list, queue_list) {
+ ret = aotg_ring_enqueue_td(acthcd, ring, td);
+ if (ret) {
+ return;
+ }
+ list_del(&td->queue_list);
+ list_add_tail(&td->enring_list, &ep->enring_td_list);
+ ring->enring_cnt++;
+ }
+ }
+
+ if (!list_empty(&ep->enring_td_list) && !is_ring_running(ring))
+ aotg_start_ring(ring, ring_trb_virt_to_dma(ring, ring->dequeue_trb));
+ else if (list_empty(&ep->enring_td_list) && is_ring_running(ring))
+ aotg_stop_ring(ring);
+}
+
+void aotg_ring_irq_handler(struct aotg_hcd *acthcd)
+{
+ unsigned int irq_mask;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acthcd->lock, flags);
+ acthcd->check_trb_mutex = 1;
+
+ do {
+ irq_mask = get_ring_irq(acthcd);
+ if (irq_mask == 0) {
+ acthcd->check_trb_mutex = 0;
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return;
+ }
+ clear_ring_irq(acthcd, irq_mask);
+
+ handle_ring_dma_tx(acthcd, irq_mask);
+ } while (irq_mask);
+ acthcd->check_trb_mutex = 0;
+ spin_unlock_irqrestore(&acthcd->lock, flags);
+ return;
+}
+
+
+
diff --git a/drivers/usb/host/aotg_ring.h b/drivers/usb/host/aotg_ring.h
new file mode 100644
index 0000000..fe69508
--- /dev/null
+++ b/drivers/usb/host/aotg_ring.h
@@ -0,0 +1,48 @@
+#ifndef __LINUX_USB_AOTG_RING_H__
+#define __LINUX_USB_AOTG_RING_H__
+
+/* about dma_no: if (dma_no & 0x10) == 0x10, it's hcout, otherwise it's hcin. */
+
+
+void aotg_hcd_dump_trb(struct aotg_trb *trb);
+void aotg_hcd_dump_td(struct aotg_td *td);
+void enable_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep);
+void disable_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep);
+void clear_overflow_irq(struct aotg_hcd *acthcd, struct aotg_hcep *ep);
+struct aotg_td *aotg_alloc_td(gfp_t mem_flags);
+void aotg_release_td(struct aotg_td *td);
+int is_ring_running(struct aotg_ring *ring);
+void start_ring(struct aotg_ring *ring);
+void stop_ring(struct aotg_ring *ring);
+struct aotg_ring *aotg_alloc_ring(struct aotg_hcd *acthcd,
+ struct aotg_hcep *ep, unsigned int num_trbs,
+ gfp_t mem_flags);
+void aotg_free_ring(struct aotg_hcd *acthcd, struct aotg_ring *ring);
+dma_addr_t ring_trb_virt_to_dma(struct aotg_ring *ring, struct aotg_trb *trb_vaddr);
+int ring_empty(struct aotg_ring *ring);
+inline int is_room_on_ring(struct aotg_ring *ring, unsigned int num_trbs);
+inline unsigned int count_urb_need_trbs(struct urb *urb);
+void aotg_fill_trb(struct aotg_trb *trb,
+ u32 dma_addr, u32 len, u32 token);
+int aotg_sg_map_trb(struct aotg_trb *trb,
+ struct scatterlist *sg, int len, u32 token);
+void inc_enqueue_safe(struct aotg_ring *ring);
+void enqueue_trb(struct aotg_ring *ring, u32 buf_ptr, u32 buf_len,
+ u32 token);
+int ring_enqueue_sg_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td);
+int aotg_ring_enqueue_td(struct aotg_hcd *acthcd,
+ struct aotg_ring *ring, struct aotg_td *td);
+void inc_dequeue_safe(struct aotg_ring *ring);
+void aotg_ring_dequeue_td(struct aotg_ring *ring, struct aotg_td *td);
+unsigned int get_ring_irq(struct aotg_hcd *acthcd);
+void clear_ring_irq(struct aotg_hcd *acthcd, unsigned int irq_mask);
+int finish_td(struct aotg_ring *ring, struct aotg_td *td);
+void handle_ring_dma_tx(struct aotg_hcd *acthcd, unsigned int irq_mask);
+void aotg_ring_irq_handler(struct aotg_hcd *acthcd);
+
+#endif
+
+
+
+
diff --git a/drivers/usb/host/uhost_hotplug_handle.c b/drivers/usb/host/uhost_hotplug_handle.c
new file mode 100644
index 0000000..f135771
--- /dev/null
+++ b/drivers/usb/host/uhost_hotplug_handle.c
@@ -0,0 +1,34 @@
+#define SUPPORT_NOT_RMMOD_USBDRV 1
+#if SUPPORT_NOT_RMMOD_USBDRV
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+enum plugstate{
+ PLUGSTATE_A_OUT=0,
+ PLUGSTATE_B_OUT,
+ PLUGSTATE_A_IN,
+ PLUGSTATE_B_IN,
+ PLUGSTATE_A_SUSPEND,
+ PLUGSTATE_A_RESUME,
+};
+
+extern int xhci_resume_host(void);
+extern int xhci_suspend_host(void);
+
+ int xhci_set_plugstate(int state)
+{
+ if((state==PLUGSTATE_A_SUSPEND)){
+ printk("\n----xhci_set_plugstate--HOST_SUSPEND--\n");
+ xhci_suspend_host();
+ }
+ else if((state==PLUGSTATE_A_RESUME)){
+ printk("\n----xhci_set_plugstate--HOST_RESUME--\n");
+ xhci_resume_host();
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_set_plugstate);
+
+#endif
\ No newline at end of file
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
old mode 100644
new mode 100755
index 896b928..4eaf1e6
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -31,12 +31,22 @@
#include "xhci.h"
#include "xhci-trace.h"
+#define XHCI_SUPPORT_SUPERSPEED
+#ifdef XHCI_SUPPORT_SUPERSPEED
+#include "xhci_ss_retry_mode.c"
+#include "xhci_ss_phy_setting.c"
+#endif
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
#define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
+struct xhci_hcd *xhci_host;
+extern void dwc3_phy_init(u8 mode, unsigned char port_num);
+extern void disable_bias(void);
+extern void enable_bias(void);
+
/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
static int link_quirk;
module_param(link_quirk, int, S_IRUGO | S_IWUSR);
@@ -129,6 +139,12 @@ static int xhci_start(struct xhci_hcd *xhci)
u32 temp;
int ret;
+#ifdef XHCI_SUPPORT_SUPERSPEED
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+
+ ss_lfps_init(hcd->regs) ;
+#endif
+
temp = readl(&xhci->op_regs->command);
temp |= (CMD_RUN);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
@@ -149,6 +165,29 @@ static int xhci_start(struct xhci_hcd *xhci)
/* clear state flags. Including dying, halted or removing */
xhci->xhc_state = 0;
+#ifdef XHCI_SUPPORT_SUPERSPEED
+ printk("\n#xhci_start#\n");
+#ifdef XHCI_SS_SUPPORT_RETRY
+ int val,retry_cnt = 0;
+ ReRxDetectLoop_notResetXhci:
+ do{
+ ss_retry_mode(hcd->regs);
+ printk("ss retry %d times\n",retry_cnt++);
+ msleep(10);
+ if(ss_detect_ltssm_change(hcd->regs)==0)
+ {
+ if((retry_cnt >10))
+ break;
+ goto ReRxDetectLoop_notResetXhci;
+ }
+ val = readl(hcd->regs+XHCI_PORT2_STATUS);
+ }
+ while(((val & PORT_CONNECT) ==0)&&(retry_cnt <10) );// try 10 times ,then try hs
+#else
+ ss_retry_mode(hcd->regs);
+#endif
+#endif
+
return ret;
}
@@ -165,6 +204,12 @@ int xhci_reset(struct xhci_hcd *xhci)
u32 state;
int ret, i;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+
+#ifndef XHCI_SUPPORT_SUPERSPEED
+ enable_bias();
+#endif
+
state = readl(&xhci->op_regs->status);
if ((state & STS_HALT) == 0) {
xhci_warn(xhci, "Host controller not halted, aborting reset.\n");
@@ -206,6 +251,15 @@ int xhci_reset(struct xhci_hcd *xhci)
xhci->bus_state[i].resuming_ports = 0;
}
+ dwc3_phy_init(1,0);
+
+#ifdef XHCI_SUPPORT_SUPERSPEED
+ ss_phy_init(hcd->regs,1);
+ ss_retry_mode_init(hcd->regs);
+#else
+ disable_bias();
+#endif
+
return ret;
}
@@ -578,6 +632,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
if (xhci->quirks & XHCI_NEC_HOST)
xhci_ring_cmd_db(xhci);
+ xhci_host = xhci;
+
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Finished xhci_run for USB3 roothub");
return 0;
@@ -906,6 +962,15 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
* This is called when the machine transition into S3/S4 mode.
*
*/
+int xhci_suspend_host(void)
+{
+ struct usb_hcd *hcd = xhci_to_hcd(xhci_host);
+
+ xhci_suspend(xhci_host, device_may_wakeup(hcd->self.controller));
+
+ return 0;
+}
+
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
{
int rc = 0;
@@ -991,6 +1056,12 @@ EXPORT_SYMBOL_GPL(xhci_suspend);
* This is called when the machine transition from S3/S4 mode.
*
*/
+int xhci_resume_host(void)
+{
+ xhci_resume(xhci_host, 0);
+ return 0;
+}
+
int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
{
u32 command, temp = 0, status;
diff --git a/drivers/usb/host/xhci_ss_phy_setting.c b/drivers/usb/host/xhci_ss_phy_setting.c
new file mode 100644
index 0000000..893d6ab
--- /dev/null
+++ b/drivers/usb/host/xhci_ss_phy_setting.c
@@ -0,0 +1,131 @@
+#ifdef XHCI_SUPPORT_SUPERSPEED
+
+static void set_reg32_val(void __iomem *base , unsigned int mask, unsigned int val, unsigned int reg)
+{
+ unsigned int Wtmp;
+
+ Wtmp =readl(base + reg);
+ Wtmp &= ~(mask);
+ val &= mask;
+ Wtmp |= val ;
+ writel(Wtmp,base + reg);
+}
+
+static void ss_phy_rx_init(void __iomem *base)
+{
+
+ //modified by lchen
+ set_reg32_val(base , 0x1f<<1, 0x15<<1, USB3_ANA03); //for lowest OOBS_sensitivity
+ set_reg32_val(base ,0x3<<14, 0x2<<14, USB3_ANA0B); //for OOBS CM, default 10
+ set_reg32_val(base ,0x3<<12, 0x2<<12, USB3_ANA0B); //for OOBS DM, default 10
+ writel( 0x9555, base + USB3_ANA04); //for CMU_LDO=2.1V
+ writel(0x2d91,base + USB3_ANA08); //for proper DC gain
+
+ set_reg32_val(base ,0x1<<6, 0x0<<6, USB3_ANA09); //for RXIDLE=LFPS_DET & NSQ(1) or NSQ(0)
+ set_reg32_val(base , 0x7<<12, 0x3<<12, USB3_ANA09); //for IB_TX and IB_OOBS
+ writel(0xFF68 ,base + USB3_ANA0D); //for CDR_PI and RX_Z0
+ writel(0x2020,base + USB3_ANA0E); //for TX_CM mode
+ writel(0xFF0C, base + USB3_REV2); //for CDR and PI in 0x1B---[0xFF08--BAD]
+ set_reg32_val(base , 0x7<<2, 0x7<<2, USB3_REV3); //for CP0 selected
+
+ //set_reg32_val(base , 0x1<<0, 0x0<<0, USB3_FLD0); //for disable BER checker
+
+ writel(0xD4FF,base + USB3_PAGE1_REG00); //for 0x20 TX_DRV
+ writel(0xAAFF,base + USB3_PAGE1_REG01); // TX_DRV
+ writel(0x0051,base + USB3_PAGE1_REG02); // TX_DRV and BER ckecker sel
+ writel(0xDB60,base + USB3_PAGE1_REG03); // TX_DRV
+
+ //for force offset value
+ set_reg32_val(base , 0xf<<5, 0x9<<5, USB3_ANA0B);
+ //set_reg32_val(base , 0x1<<13, 0x0<<13, USB3_ANA0D); //manual set when 0
+
+ //for CDR loop setup earlier
+ set_reg32_val(base ,0x1<<1, 0x1<<1, USB3_ANA0B); //for PIEN select change
+ set_reg32_val(base ,0x1<<15, 0x0<<15, USB3_ANA0C); //for POW_CLK(PSAVE) select change
+ set_reg32_val(base ,0x1<<3, 0x0<<3, USB3_ANA00); //for cdr RESET select change(POWER DISPPU)
+ set_reg32_val(base ,0x1<<10, 0x0<<10, USB3_ANA0D); //for CDR digitalLFP ENABLE select change
+
+ //for manual mode CDR_ST<31:0>
+ set_reg32_val(base ,0x1<<15, 0x1<<15, USB3_ANA02); //for enable manual set ST value
+ set_reg32_val(base ,0xffff<<0, 0x0<<0, USB3_PAGE1_REG0C); //for ST[31:16]
+ set_reg32_val(base ,0xffff<<0, 0xff<<0, USB3_PAGE1_REG0D); //for ST[15:0]
+
+ //for PI bias
+ set_reg32_val(base ,0x3<<3, 0x1<<3, USB3_REV2); //for PI bias[3:2] default=1
+ set_reg32_val(base ,0x3<<11, 0x2<<11, USB3_ANA0D); //for PI bias[1:0] default=2
+
+ //for force EQ value
+ //setReg32_val(0x1<<14, 0x0<<14, USB3_PAGE1_REG00); //for manual mode when REG_CDR_SEL=0
+ set_reg32_val(base ,0x1<<5, 0x1<<5, USB3_ANA0A); //for manual set when REG_RX_EQ_SELREG=1
+ set_reg32_val(base ,0x1f<<11, 0x7<<11, USB3_REV0); //for REG_FILTER_OUT=from 11100 to 10000
+
+ //APHY Dbg Switch
+ set_reg32_val(base , 1<<0, 1<<0, USB3_ANA0D); //for TX_TEST_EN=1
+ set_reg32_val(base ,1<<6, 1<<6, USB3_ANA0D); //for RX_TEST_EN=1
+ set_reg32_val(base , 1<<9, 1<<9, USB3_ANA02); //for CDR_TEST_EN=1
+ set_reg32_val(base , 0x7<<10, 0x2<<10, USB3_ANA02); //for CDR_TESTOUT_SEL=CLKDEBUG
+}
+
+static void ss_phy_analog_setting(void __iomem *base)
+{
+ writel(0x8000,base + USB3_ANA0F);
+ writel(0x6046,base + USB3_ANA02);
+ writel(0x2020,base + USB3_ANA0E);
+
+ writel(0x0,base + USB3_REV1);
+ writel(0x0013,base + USB3_PAGE1_REG02);
+ writel(0x0004,base + USB3_PAGE1_REG06);
+ writel(0x22ed,base + USB3_PAGE1_REG07);
+ writel(0xf802,base + USB3_PAGE1_REG08);
+ writel(0x3080,base + USB3_PAGE1_REG09);
+ writel(0x2030,base + USB3_PAGE1_REG0B);
+
+ ss_phy_rx_init(base);
+
+ set_reg32_val(base , ((1<<5)|(1<<4)),((1<<5)|(0<<4)),USB3_ANA0E);//bit4: [0=cmfb mode=usingRxDetect] [1=opab mode=Nomal Using]
+ set_reg32_val(base , (3<<12),(2<<12),USB3_ANA0E);//Tx_SCE_VCM
+ set_reg32_val(base , (3<<2),(0<<2),USB3_ANA0C);//RxSel---time
+ set_reg32_val(base , (1<<15),(0<<15),USB3_FLD0);
+
+ set_reg32_val(base , (3<<0),(2<<0),USB3_ANA08); //Rx DC gain
+ set_reg32_val(base ,(3<<1),(3<<1),USB3_PAGE1_REG06); // DC gain--DB
+ set_reg32_val(base ,((7<<0)|(7<<3)|(7<<6)),((1<<0)|(1<<3)|(4<<6)),USB3_ANA01);
+}
+/*
+* host_dev: 0: device; 1: host
+*/
+void ss_phy_init(void __iomem *base,int host_dev)
+{
+ ss_phy_analog_setting(base);
+
+ set_reg32_val(base ,((1<<5)|(1<<3)),((1<<5)|(0<<3)), USB3_PAGE1_REG0B);//must bit3=0---20140925
+ set_reg32_val(base ,(1<<7),(0<<7), USB3_PAGE1_REG0A);//must bit7=0---20140925
+ set_reg32_val(base ,(0xF<<2),(0x7<<2), USB3_ANA0D);
+ //set_reg32_val(base ,(1<<3),(0<<3), USB3_PAGE1_REG0B);//
+ //set_reg32_val(base ,((1<<8)|(1<<10)),((0<<8)|(0<<10)), USB3_FLD1);//
+ //set_reg32_val(base ,(1<<7),(0<<7), USB3_PAGE1_REG0A);//
+ set_reg32_val(base ,(1<<0),(0x1<<0), USB3_FLD0); //Biterr Checker Function Disable---20141127
+ writel(0,base + USB3_IER);
+ set_reg32_val(base ,(1<<11),(1<<11), USB3_REV3);//rcv clock sample
+
+ set_reg32_val(base ,(0xf<<12),(0x6<<12), USB3_ANA02); //care---or will go to HS
+ set_reg32_val(base ,(0xf<<0),(0xd<<0), USB3_ANA03); //care---or will sometime goto HS
+ set_reg32_val(base ,(0xff<<8),(0xfc<<8), USB3_IER); //care
+ if(host_dev==1){
+ set_reg32_val(base ,(0xf<<0),(0x8<<0), USB3_PAGE1_REG0B);//care
+ set_reg32_val(base , (3<<0),(3<<0),USB3_ANA08); //Rx DC gain
+ }
+ else{
+
+ set_reg32_val(base , (1<<22) , (0<<22), BACKDOOR); //LUP timing select--20140624
+ set_reg32_val(base ,(1<<9)|(1<<8) , (1<<9)|(1<<8), BACKDOOR); //Mac SampleEdge select--20140624
+ set_reg32_val(base ,((1<<3)|(0x3f<<4)), ((0<<3)|(36<<4)), USB3_DMR);//enableDebug Out
+ set_reg32_val(base , (1<<9) , (1<<9) , BACKDOOR); //Mac SampleEdge select
+
+ }
+ set_reg32_val(base ,(1<<14),(1<<14), GUCTL);//fix asix usbnet dongle retry hangup
+ set_reg32_val(base ,(1<<17),(1<<17), GUCTL);//fix some udisk control transfer too slow,set config fail
+ writel(0x2408,base + GUSB2CFG0);
+}
+EXPORT_SYMBOL_GPL(ss_phy_init);
+#endif
diff --git a/drivers/usb/host/xhci_ss_retry_mode.c b/drivers/usb/host/xhci_ss_retry_mode.c
new file mode 100644
index 0000000..42ff795
--- /dev/null
+++ b/drivers/usb/host/xhci_ss_retry_mode.c
@@ -0,0 +1,224 @@
+#ifdef XHCI_SUPPORT_SUPERSPEED
+
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include "xhci_usb3_regs.h"
+
+extern int usb_set_vbus_power(int value);
+#define LfpsSrc_Mode_LPFS_DET (1)
+#define LfpsSrc_Mode_NSQ (2)
+#define LfpsSrc_Mode_BOTH (3)
+
+//unsigned int capltssm[64/4]; //char[64]
+//unsigned int capltssm_curr_idx;
+static int lfps_src_mode = LfpsSrc_Mode_LPFS_DET;
+unsigned int ltssm_old,ltssm_curr;
+static void set_reg32_val(void __iomem *base , unsigned int mask, unsigned int val, unsigned int reg);
+void ss_mac_sample_edge_init(void __iomem *base );
+#ifdef XHCI_SS_SUPPORT_RETRY
+static int ss_detect_ltssm_change(void __iomem *base)
+{
+ volatile unsigned int Wtmp ;
+ //int ret=1;
+ //volatile unsigned int tmp_ts1;
+ //unsigned int cap;
+ //unsigned char * pU8= (unsigned char *)capltssm;
+ int cnt = 0xffff;
+
+ for(cnt = 0;cnt <100;cnt++){
+ mdelay(1);
+ Wtmp =readl(GDBGLTSSM+base);
+ if((Wtmp&(0xf<<22))==0) {
+ // connected
+ printk(KERN_ERR"\n== in U0 ,don't need retry ==\n");
+ return 1;
+ }
+ }
+ printk(KERN_ERR"\n----wait U0 fail!!---\n");
+ return 0;
+
+#if 0
+ Wtmp =readl(USB3_GDBGLTSSM+base);
+ ltssm_curr = Wtmp & ((0xf<<22)|(0xf<<18));
+ if(ltssm_curr != ltssm_old )
+ {
+ //pU8[capltssm_curr_idx++] = (ltssm_curr>>18);
+ //capltssm_curr_idx &= (64-1);
+ printk("\n-----detectLtssChange-----USB3_GDBGLTSSM=0x%x----Ltssm_curr=0x%x--Ltssm_old=0x%x--\n",\
+ Wtmp,ltssm_curr,ltssm_old);
+
+ if((Wtmp &(0xf<<22))==(0x7<<22))
+ {
+ while(1)
+ {
+ tmp_ts1 = readl(USB3_GDBGLTSSM+base) & ((0xf<<22)|(0xf<<18));
+ Wtmp =tmp_ts1 & (0xf<<22);
+ if(Wtmp==0){
+ printk("\n=============in U0============\n");
+ break; //if=U0
+ }
+ else if(Wtmp==(0xa<<22)) //if=Complaint
+ {
+ Wtmp =Wtmp>>18; //add for easy to see Ltssm State
+ ret =0;
+ return ret;
+ }else if(Wtmp==(0x5<<22)) //if =RxDetect again
+ {
+ printk("\n===========RxDetect again========\n\n");
+ while(1)
+ {
+ Wtmp = readl(USB3_GDBGLTSSM+base) & (0xf<<22);
+ Wtmp = Wtmp>>22;
+ if(Wtmp==(0xa<<0)) {
+ ret =0;
+ return ret;
+ }
+ else if(Wtmp==0 )
+ break;
+ cnt--;
+ if(cnt <= 0)
+ return 0;
+ }
+ break;
+ }
+ else if(Wtmp==(0x7<<22))
+ cap = tmp_ts1>>18;
+ }
+ }
+ }
+ ltssm_old= ltssm_curr;
+ ret = 1;// connect
+ return ret;
+#endif
+}
+#endif
+static void ss_try_next_mode(void __iomem *base)
+{
+ printk(" ss_try_next_mode:lfps_src_mode=%d\n",lfps_src_mode );
+ switch(lfps_src_mode)
+ {
+ case LfpsSrc_Mode_LPFS_DET :
+ {
+ set_reg32_val(base , (1<<9), (0<<9), GUSB3PIPECTL); // for Test=LFPS Filter
+ set_reg32_val(base , ((1<<8)|(1<<15)),((0<<8)|(0<<15)), USB3_FLD0);
+ set_reg32_val(base , (1<<3),(0<<3), USB3_PAGE1_REG0B); //active--will remove false Lfps In JiaJun--20150330
+ break;
+ }
+
+ case LfpsSrc_Mode_NSQ :
+ {
+ set_reg32_val(base , (1<<9), (0<<9), GUSB3PIPECTL); // for Test=LFPS Filter
+ set_reg32_val(base , ((1<<8)|(1<<15)),((0<<8)|(0<<15)), USB3_FLD0);
+ set_reg32_val(base , ((1<<3)|(1<<5)),((1<<3)|(1<<5)), USB3_PAGE1_REG0B); //active--will remove false Lfps In JiaJun--20150330
+ break;
+ }
+
+ case LfpsSrc_Mode_BOTH :
+ {
+ set_reg32_val(base , (1<<9), (0<<9), GUSB3PIPECTL); // for Test=LFPS Filter
+ set_reg32_val(base , ((1<<8)|(1<<15)),((0<<8)|(0<<15)), USB3_FLD0);
+ set_reg32_val(base , ((1<<3)|(1<<5)),((1<<3)|(1<<5)), USB3_PAGE1_REG0B); //active--will remove false Lfps In JiaJun--20150330
+ set_reg32_val(base , (1<<6),(1<<6), USB3_ANA09);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ //if(++lfps_src_mode >LfpsSrc_Mode_BOTH)
+ // lfps_src_mode = LfpsSrc_Mode_LPFS_DET;
+}
+
+void ss_retry_phy_softrest(void __iomem *base)
+{
+ set_reg32_val(base , (1<<31),(1<<31), GUSB3PIPECTL); //PHY softRest
+ mdelay(10);
+ set_reg32_val(base , (1<<31),(0<<31), GUSB3PIPECTL); //PHY softRest
+}
+
+void ss_retry_mode(void __iomem *base)
+{
+ unsigned int val;
+
+ writel((1<<14),USB3_ANA0F+base);
+
+ usb_set_vbus_power(0);
+
+ ss_retry_phy_softrest(base);
+ mdelay(5);
+ ss_mac_sample_edge_init(base );
+ ss_try_next_mode(base);
+ mdelay(5);
+
+ usb_set_vbus_power(1);
+
+ mdelay(1);
+
+ val = 0x200;
+ writel(val,base+XHCI_PORT2_STATUS);
+ set_reg32_val(base ,0xff, 2, GBDGFIFOSPACE); //select port2
+
+}
+
+void ss_mac_sample_edge_init(void __iomem *base )
+{
+ set_reg32_val(base , (1<<22) , (0<<22), BACKDOOR); //LUP timing select--20140624
+ set_reg32_val(base ,(1<<9)|(1<<8) , (1<<9)|(0<<8), BACKDOOR); //Mac SampleEdge select--20140624
+ set_reg32_val(base , (1<<9) , (1<<9) , BACKDOOR); //Mac SampleEdge select
+}
+
+void ss_lfps_init(void __iomem *base)
+{
+ set_reg32_val(base , (1<<8), (0<<8), USB3_GCTL); //Not Infinit
+ set_reg32_val(base , (1<<12), (1<<12), GUSB3PIPECTL); // for Test=LFPS P0 Align (LFPSP0Algn)
+ set_reg32_val(base , (1<<9), (0<<9), GUSB3PIPECTL); // for Test=LFPS Filter
+ set_reg32_val(base , (3<<12), (1<<12), USB3_GCTL);
+}
+#if 0
+void ss_detect_ltssm_init(void __iomem *base)
+{
+ set_reg32_val(base ,0xff, 2, USB3_GBDGFIFOSPACE); //select port2
+ ltssm_old =readl(USB3_GDBGLTSSM+base) & ((0xf<<22)|(0xf<<18)) ;
+ ltssm_curr = ltssm_old;
+ capltssm_curr_idx =0;
+
+ unsigned char * pU8= (unsigned char *)capltssm;
+ pU8[capltssm_curr_idx++] = (ltssm_curr>>18);
+}
+#endif
+void ss_retry_mode_init(void __iomem *base)
+{
+#if 0
+ int i;
+
+ void __iomem *cmu_base = (void __iomem *)IO_ADDRESS(0xB0168000);
+ set_reg32_val(cmu_base ,((1<<7)|(1<<6)),((1<<7)|(1<<6)), USB3_ECS);//softvbus =1
+ set_reg32_val(cmu_base ,((1<<31)|(7<<28)),((1<<31)|(4<<28)), USB3_ECS); //USB3 USB2PLL LDO Enable
+#endif
+
+ ss_mac_sample_edge_init(base );
+
+#if 0
+ for (i=0;i<1000;i++);
+ ss_detect_ltssm_init(base);
+
+ writel(0x00001448 ,base + USB3_GUSB2CFG0);
+ set_reg32_val(base , (3<<4), (0<<4), USB3_GCTL); //clean the scale down
+#endif
+ set_reg32_val(base , (0xff<<0), (0x6<<0), GSBUSCFG0);//enable burst 8 and burst 4
+ set_reg32_val(base , (0xf<<8), (0x7<<8), GSBUSCFG1); //AXI busrt requst limit is 3
+
+ /*set_reg32_val(base , (0x1<<29), (1<<29), USB3_GTXTHRCFG);
+ set_reg32_val(base , (0xf<<24), (0xf<<24), USB3_GTXTHRCFG);
+ set_reg32_val(base , (0xf<<16), (0xf<<16), USB3_GTXTHRCFG);
+
+ set_reg32_val(base , (0x1<<29), (1<<29), USB3_GRXTHRCFG);
+ set_reg32_val(base , (0xf<<24), (0x3<<24), USB3_GRXTHRCFG);
+ set_reg32_val(base , (0xf<<19), (0x3<<19), USB3_GRXTHRCFG);*/
+
+}
+#endif
diff --git a/drivers/usb/host/xhci_usb3_regs.h b/drivers/usb/host/xhci_usb3_regs.h
new file mode 100644
index 0000000..59ff164
--- /dev/null
+++ b/drivers/usb/host/xhci_usb3_regs.h
@@ -0,0 +1,79 @@
+#ifdef XHCI_SUPPORT_SUPERSPEED
+
+#ifndef __USB3_REGS_H__
+#define __USB3_REGS_H__
+
+//--------------USB3_Register-------------------------------------------//
+//--------------Register Address---------------------------------------//
+#define USB3_ANA00 (0+0xCD00)
+#define USB3_ANA01 (0+0xCD04)
+#define USB3_ANA02 (0+0xCD08)
+#define USB3_ANA03 (0+0xCD0C)
+#define USB3_ANA04 (0+0xCD10)
+
+#define USB3_ANA05 (0+0xCD14)
+#define USB3_ANA06 (0+0xCD18)
+#define USB3_ANA07 (0+0xCD1C)
+#define USB3_ANA08 (0+0xCD20)
+#define USB3_ANA09 (0+0xCD24)
+#define USB3_ANA0A (0+0xCD28)
+#define USB3_ANA0B (0+0xCD2C)
+#define USB3_ANA0C (0+0xCD30)
+#define USB3_ANA0D (0+0xCD34)
+#define USB3_ANA0E (0+0xCD38)
+#define USB3_ANA0F (0+0xCD3C)
+#define USB3_DMR (0+0xCD40)
+#define USB3_BACR (0+0xCD44)
+#define USB3_IER (0+0xCD48)
+#define USB3_BCSR (0+0xCD4C)
+#define USB3_BPNR2 (0+0xCD54)
+#define USB3_BRNR2 (0+0xCD5C)
+#define USB3_BENR (0+0xCD60)
+#define USB3_REV0 (0+0xCD64)
+#define USB3_REV1 (0+0xCD68)
+#define USB3_REV2 (0+0xCD6C)
+#define USB3_REV3 (0+0xCD70)
+#define USB3_FLD0 (0+0xCD74)
+#define USB3_FLD1 (0+0xCD78)
+#define USB3_ANA1F (0+0xCD7C)
+#define USB3_PAGE1_REG00 (0+0xCD80)
+#define USB3_PAGE1_REG01 (0+0xCD84)
+#define USB3_PAGE1_REG02 (0+0xCD88)
+#define USB3_PAGE1_REG03 (0+0xCD8C)
+#define USB3_PAGE1_REG04 (0+0xCD90)
+#define USB3_PAGE1_REG05 (0+0xCD94)
+#define USB3_PAGE1_REG06 (0+0xCD98)
+#define USB3_PAGE1_REG07 (0+0xCD9C)
+#define USB3_PAGE1_REG08 (0+0xCDA0)
+#define USB3_PAGE1_REG09 (0+0xCDA4)
+#define USB3_PAGE1_REG0A (0+0xCDA8)
+#define USB3_PAGE1_REG0B (0+0xCDAC)
+#define USB3_PAGE1_REG0C (0+0xCDB0)
+#define USB3_PAGE1_REG0D (0+0xCDB4)
+#define USB3_PAGE1_REG0E (0+0xCDB8)
+#define USB3_PAGE1_REG0F (0+0xCDBC)
+#define USB3_PAGE1_REG10 (0+0xCDC0)
+#define USB2_P0_VDCTRL (0+0xCE00)
+#define BACKDOOR (0+0xCE04)
+#define USB3_EXT_CONTROL (0+0xCE08)
+#define USB2_P1_VDCTRL (0+0xCE10)
+
+#define GUSB3PIPECTL (0+0xC2C0)
+#define USB3_GCTL (0+0xC110)
+#define GUCTL (0+0xC12C)
+#define GBDGFIFOSPACE (0+0xC160)
+#define GDBGLTSSM (0+0xC164)
+#define XHCI_PORT2_STATUS (0x0430+0)
+#define GUSB2CFG0 (0+0xC200)
+#define GSBUSCFG0 (0+0xC100)
+#define GSBUSCFG1 (0+0xC104)
+#define GTXTHRCFG (0+0xC108)
+#define GRXTHRCFG (0+0xC10C)
+#define USB3_ECS (0+0x0080)
+
+
+#define USB3_ACTIONS_START (0xcd00)
+#define USB3_ACTIONS_END (0xcd58)
+
+#endif
+#endif
diff --git a/drivers/usb/monitor/Kconfig b/drivers/usb/monitor/Kconfig
new file mode 100644
index 0000000..e58bcd4
--- /dev/null
+++ b/drivers/usb/monitor/Kconfig
@@ -0,0 +1,23 @@
+#
+# USB Monitor configuration
+#
+
+config USB_ACTIONS_MON
+ tristate "USB Actions Monitor"
+ depends on ARCH_OWL
+ help
+ If you select this option, a component which captures the USB traffic
+ between peripheral-specific drivers and HC drivers will be built.
+ For more information, see <file:Documentation/usb/usbmon.txt>.
+
+ If unsure, say Y, if allowed, otherwise M.
+
+config USB_PLATFORM_LINUX
+ tristate "USB Monitor For Linux"
+ depends on ARCH_OWL && USB_ACTIONS_MON
+ help
+ If you select this option usb monitor just detect usb plug in/out ,sent uevent & open
+ or close usb controller.
+ if not , usb monitor will support android system by sent uevent to vold;
+
+ If unsure, say Y, if allowed, otherwise M.
diff --git a/drivers/usb/monitor/Makefile b/drivers/usb/monitor/Makefile
new file mode 100644
index 0000000..4ccdbc4
--- /dev/null
+++ b/drivers/usb/monitor/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for USB monitor
+#
+
+monitor-y := umonitor_core.o umonitor_hal.o umonitor_api.o
+
+obj-$(CONFIG_USB_ACTIONS_MON) += monitor.o
+
+
+
diff --git a/drivers/usb/monitor/aotg_regs.h b/drivers/usb/monitor/aotg_regs.h
new file mode 100644
index 0000000..22f018f
--- /dev/null
+++ b/drivers/usb/monitor/aotg_regs.h
@@ -0,0 +1,162 @@
+/*
+ * for Actions AOTG
+ *
+ */
+
+#ifndef __AOTG_REGS_H__
+#define __AOTG_REGS_H__
+
+
+#define USB3_REGISTER_BASE 0xB0400000
+
+#define DWC3_DCFG 0xc700
+
+
+#define DWC3_ACTIONS_REGS_START (0xcd00)
+#define DWC3_ACTIONS_REGS_END (0xcd54)
+
+
+
+
+
+#define DWC3_CDR_KIKD (0xcd00)
+#define DWC3_CDR_KP1 (0xcd04)
+#define DWC3_TIMER_INIT (0xcd08)
+#define DWC3_CDR_CONTROL (0xcd0c)
+#define DWC3_RX_OFFSET_PS (0xcd10)
+#define DWC3_EQ_CONTROL (0xcd14)
+#define DWC3_RX_OOBS_SSC0 (0xcd18)
+#define DWC3_CMU_SSC1 (0xcd1C)
+#define DWC3_CMU_DEBUG_LDO (0xcd20)
+#define DWC3_TX_AMP_DEBUG (0xcd24)
+#define DWC3_Z0 (0xcd28)
+#define DWC3_DMR_BACR (0xcd2C)
+#define DWC3_IER_BCSR (0xcd30)
+#define DWC3_BPR (0xcd34)
+#define DWC3_BFNR (0xcd38)
+#define DWC3_BENR_REV (0xcd3C)
+#define DWC3_FLD (0xcd40)
+#define DWC3_CMU_PLL2_BISTDEBUG (0xcd44)
+#define DWC3_USB2_P0_VDCTL (0xcd48)
+#define DWC3_BACKDOOR (0xcd4C)
+#define DWC3_EXT_CTL (0xcd50)
+#define DWC3_EFUSE_CTR (0xcd54)
+#define DWC3_GCTL (0xc110)
+
+
+#define USB3_MOD_RST (1 << 14)
+#define CMU_BIAS_EN (1 << 20)
+
+
+#define BIST_QINIT(n) ((n) << 24)
+#define EYE_HEIGHT(n) ((n) << 20)
+#define PLL2_LOCK (1 << 15)
+#define PLL2_RS(n) ((n) << 12)
+#define PLL2_ICP(n) ((n) << 10)
+#define CMU_SEL_PREDIV (1 << 9)
+#define CMU_DIVX2 (1 << 8)
+#define PLL2_DIV(n) ((n) << 3)
+#define PLL2_POSTDIV(n) ((n) << 1)
+#define PLL2_PU (1 << 0)
+
+#define DWC3_GCTL_CORESOFTRESET (1 << 11)
+
+
+#define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12)
+#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12)
+#define DWC3_GCTL_PRTCAP_HOST 1
+#define DWC3_GCTL_PRTCAP_DEVICE 2
+#define DWC3_GCTL_PRTCAP_OTG 3
+
+#define HOST_DETECT_STEPS 5
+#define DEVICE_DETECT_STEPS 5
+
+#define HOST_CONFIRM_STEPS 3
+#define DEVICE_CONFIRM_STEPS 4
+
+
+#define USB3_P0_CTL_VBUS_P0 5
+#define USB3_P0_CTL_ID_P0 11
+#define USB3_P0_CTL_DPPUEN_P0 14
+#define USB3_P0_CTL_DMPUEN_P0 15
+#define USB3_P0_CTL_DPPDDIS_P0 12
+#define USB3_P0_CTL_DMPDDIS_P0 13
+#define USB3_P0_CTL_SOFTIDEN_P0 8
+#define USB3_P0_CTL_SOFTID_P0 9
+#define USB3_P0_CTL_SOFTVBUSEN_P0 6
+#define USB3_P0_CTL_SOFTVBUS_P0 7
+#define USB3_P0_CTL_PLLLDOEN 28
+#define USB3_P0_CTL_LDOVREFSEL_SHIFT 29
+
+#define USB3_P0_CTL_LDOVREFSEL_SHIFT_IC1 28
+#define USB3_P0_CTL_PLLLDOEN_IC1 31
+
+#define USB3_P0_CTL_LS_P0_SHIFT 3
+#define USB3_P0_CTL_LS_P0_MASK (0x3<<3)
+
+
+#define VBUS_THRESHOLD 3000
+
+enum{
+ IC_ATM7039C = 0,
+ IC_ATM7059A
+};
+#define ANA00 (0+0xCD00)
+#define ANA01 (0+0xCD04)
+#define ANA02 (0+0xCD08)
+#define ANA03 (0+0xCD0C)
+#define ANA04 (0+0xCD10)
+
+#define ANA05 (0+0xCD14)
+#define ANA06 (0+0xCD18)
+#define ANA07 (0+0xCD1C)
+#define ANA08 (0+0xCD20)
+#define ANA09 (0+0xCD24)
+#define ANA0A (0+0xCD28)
+#define ANA0B (0+0xCD2C)
+#define ANA0C (0+0xCD30)
+#define ANA0D (0+0xCD34)
+#define ANA0E (0+0xCD38)
+#define ANA0F (0+0xCD3C)
+#define DMR (0+0xCD40)
+#define BACR (0+0xCD44)
+#define IER (0+0xCD48)
+#define BCSR (0+0xCD4C)
+#define BPR (0+0xCD50)
+#define BPNR2 (0+0xCD54)
+#define BFNR (0+0xCD58)
+#define BRNR2 (0+0xCD5C)
+#define BENR (0+0xCD60)
+#define REV0 (0+0xCD64)
+#define REV1 (0+0xCD68)
+#define REV2 (0+0xCD6C)
+#define REV3 (0+0xCD70)
+#define FLD0 (0+0xCD74)
+#define FLD1 (0+0xCD78)
+#define ANA1F (0+0xCD7C)
+#define PAGE1_REG00 (0+0xCD80)
+#define PAGE1_REG01 (0+0xCD84)
+#define PAGE1_REG02 (0+0xCD88)
+#define PAGE1_REG03 (0+0xCD8C)
+#define PAGE1_REG04 (0+0xCD90)
+#define PAGE1_REG05 (0+0xCD94)
+#define PAGE1_REG06 (0+0xCD98)
+#define PAGE1_REG07 (0+0xCD9C)
+#define PAGE1_REG08 (0+0xCDA0)
+#define PAGE1_REG09 (0+0xCDA4)
+#define PAGE1_REG0A (0+0xCDA8)
+#define PAGE1_REG0B (0+0xCDAC)
+#define PAGE1_REG0C (0+0xCDB0)
+#define PAGE1_REG0D (0+0xCDB4)
+#define PAGE1_REG0E (0+0xCDB8)
+#define PAGE1_REG0F (0+0xCDBC)
+#define PAGE1_REG10 (0+0xCDC0)
+#define USB2_P0_VDCTRL (0+0xCE00)
+#define BACKDOOR (0+0xCE04)
+#define EXT_CONTROL (0+0xCE08)
+#define EFUSE_CTR (0+0xCE0C)
+#define USB2_P1_VDCTRL (0+0xCE10)
+
+#endif /* __AOTG_REGS_H__ */
+
+
diff --git a/drivers/usb/monitor/umonitor_api.c b/drivers/usb/monitor/umonitor_api.c
new file mode 100644
index 0000000..b22c3ae
--- /dev/null
+++ b/drivers/usb/monitor/umonitor_api.c
@@ -0,0 +1,1341 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <mach/switch.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
+#include <linux/kallsyms.h>
+#include <linux/suspend.h>
+
+#include <mach/hardware.h>
+#include <mach/bootdev.h>
+
+#include <asm/uaccess.h>
+
+#include "umonitor_config.h"
+#include "umonitor_core.h"
+#include "aotg_regs.h"
+
+typedef void (*FUNC)(int);
+FUNC set_usb_plugin_type;
+
+#define CONNECT_USB_PORT 1
+#define CONNECT_USB_ADAPTOR 2
+
+
+struct delayed_work monitor_work;
+struct delayed_work monitor_resume_work;
+atomic_t wake_lock_atomic;
+unsigned int monitor_work_pending;
+unsigned int wake_lock_register_cnt;
+
+#if SUPPORT_NOT_RMMOD_USBDRV
+extern int dwc3_set_plugstate(int s);
+extern int xhci_set_plugstate(int s);
+
+enum plugstate{
+ PLUGSTATE_A_OUT=0,
+ PLUGSTATE_B_OUT,
+ PLUGSTATE_A_IN,
+ PLUGSTATE_B_IN,
+ PLUGSTATE_A_SUSPEND,
+ PLUGSTATE_A_RESUME,
+ PLUGSTATE_B_SUSPEND,
+ PLUGSTATE_B_RESUME,
+};
+#endif
+extern umonitor_dev_status_t *umonitor_status;
+
+struct mon_sysfs_status {
+ unsigned int charger_connected;
+ unsigned int pc_connected;
+ unsigned int udisk_connected;
+};
+
+struct port_dev {
+ struct switch_dev sdev;
+ char state_msg[64];
+};
+
+struct monitor_con {
+ unsigned int thread_chk_times;
+ int run;
+
+ spinlock_t lock;
+ struct mutex mon_mutex;
+ struct port_dev port_dev;
+ umon_port_config_t port_config;
+ umonitor_api_ops_t port_ops;
+ struct kobject *mon_obj; /* just for sysfs. */
+ struct kobject *mon_port;
+ struct mon_sysfs_status port_status;
+
+ atomic_t port_exit;
+ struct task_struct *tsk;
+ wait_queue_head_t mon_wait;
+
+ volatile unsigned int det_plugin_req;
+ volatile unsigned int det_plugout_req;
+ struct timer_list port_timer;
+ struct timer_list check_timer;
+ struct wake_lock monitor_wake_lock;
+#if SUPPORT_NOT_RMMOD_USBDRV
+ int dwc3_status;
+ int xhci_status;
+ int dwc3_timeout_cnt;
+ int xhci_timeout_cnt;
+ int (*dwc3_set_plugstate)(int s);
+ int (*xhci_set_plugstate)(int s);
+#endif
+ void __iomem *base;
+ int probe_fail;
+ int resume_status;
+};
+
+struct monitor_con monitor_mon_dev;
+static struct monitor_con *my_mon = &monitor_mon_dev;
+static unsigned long pm_status;
+
+static ssize_t mon_status_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf);
+static ssize_t mon_config_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf);
+static ssize_t mon_config_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *instr, size_t bytes);
+
+#define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))
+#define MONITOR_ATTR_LIST(x) (&x ## _attribute.attr)
+#define MON_STATUS_ATTR(x) static struct kobj_attribute x##_attribute = \
+ __ATTR(x, S_IRUGO, mon_status_show, NULL)
+#define MON_CONFIG_ATTR(x) static struct kobj_attribute x##_attribute = \
+ __ATTR(x, (S_IRUGO|S_IWUSR), mon_config_show, mon_config_store)
+
+/* default just for usb port0. */
+static void mon_port_putt_msg(unsigned int msg);
+static int usb_detect_plugout_event(void);
+int usb_set_vbus_power(int value);
+static void monitor_resume_delay_work(struct work_struct *work);
+
+#ifdef SUPPORT_NOT_RMMOD_USBDRV
+static void monitor_handle_plug_in_out_msg(char * usb_con_msg)
+{
+ if (!strncmp(usb_con_msg, "USB_B_IN", 8))
+ {
+ my_mon->dwc3_set_plugstate(PLUGSTATE_B_IN);
+ my_mon->xhci_set_plugstate(PLUGSTATE_B_IN);
+ }
+ else if(!strncmp(usb_con_msg, "USB_B_OUT", 9))
+ {
+ my_mon->xhci_set_plugstate(PLUGSTATE_B_OUT);
+ my_mon->dwc3_set_plugstate(PLUGSTATE_B_OUT);
+ }
+ else if(!strncmp(usb_con_msg, "USB_A_IN", 8))
+ {
+ my_mon->dwc3_set_plugstate(PLUGSTATE_A_IN);
+ my_mon->xhci_set_plugstate(PLUGSTATE_A_IN);
+ }
+ else if(!strncmp(usb_con_msg, "USB_A_OUT", 9))
+ {
+ my_mon->xhci_set_plugstate(PLUGSTATE_A_OUT);
+ my_mon->dwc3_set_plugstate(PLUGSTATE_A_OUT);
+ }
+ else{
+ printk("usb monitor handle msg err! %s\n",usb_con_msg);
+ }
+}
+#endif
+/* check in and out message, and check whether it accordant with driver state. */
+static int usb_check_msg_and_drv_state(void)
+{
+ usb_hal_monitor_t *p_hal;
+ umonitor_dev_status_t *pStatus;
+ pStatus = umonitor_status;
+ p_hal = &umonitor_status->umonitor_hal;
+
+ my_mon->thread_chk_times++;
+ /* at system startup will do a plugout, make 5 seconds to detect usb status
+ * after that will modify the wrong status by checking udisk_connected & pc_connected
+ */
+ if (my_mon->thread_chk_times <5) {
+ return 0;
+ }
+
+ if (my_mon->port_status.udisk_connected == 0) {
+ if ((my_mon->xhci_status == PLUGSTATE_A_IN) ||
+ (my_mon->xhci_status == PLUGSTATE_A_SUSPEND) ||
+ (my_mon->xhci_status == PLUGSTATE_A_RESUME)) {
+ my_mon->xhci_timeout_cnt++;
+ goto mon_adjust_state;
+ }
+ } else {
+ if (my_mon->xhci_status != PLUGSTATE_A_IN) {
+ my_mon->xhci_timeout_cnt++;
+ goto mon_adjust_state;
+ }
+ }
+
+ if (my_mon->port_status.pc_connected == 0) {
+ if (my_mon->dwc3_status == PLUGSTATE_B_IN) {
+ my_mon->dwc3_timeout_cnt++;
+ goto mon_adjust_state;
+ }
+ } else {
+ if (my_mon->dwc3_status != PLUGSTATE_B_IN) {
+ my_mon->dwc3_timeout_cnt++;
+ goto mon_adjust_state;
+ }
+ }
+ return 0;
+
+mon_adjust_state:
+ printk("xhci_status:%d, dwc3:%d\n", my_mon->xhci_status, my_mon->dwc3_status);
+ printk("udisk_con:%d, pc:%d\n", my_mon->port_status.udisk_connected, my_mon->port_status.pc_connected);
+
+ /* process host unnormal state. */
+ if (my_mon->xhci_status == PLUGSTATE_A_SUSPEND) {
+ p_hal->suspend_or_resume(p_hal, 0);
+ my_mon->dwc3_set_plugstate(PLUGSTATE_A_RESUME);
+ my_mon->xhci_set_plugstate(PLUGSTATE_A_RESUME);
+ wake_lock_timeout(&my_mon->monitor_wake_lock, 12*HZ);
+ printk("----now lock for 12*HZ\n");
+ }
+ if (my_mon->port_status.udisk_connected == 0) {
+ if ((my_mon->xhci_status == PLUGSTATE_A_IN) || (my_mon->xhci_status == PLUGSTATE_A_RESUME)) {
+ if (my_mon->xhci_timeout_cnt > 4) {
+ printk("%s:%d! \n", __func__, __LINE__);
+ my_mon->xhci_timeout_cnt = 0;
+ my_mon->xhci_set_plugstate(PLUGSTATE_A_OUT);
+ my_mon->dwc3_set_plugstate(PLUGSTATE_A_OUT);
+ umonitor_detection(1);
+ }
+ }
+ } else {
+ if (my_mon->xhci_status != PLUGSTATE_A_IN) {
+ if (my_mon->xhci_timeout_cnt > 10) {
+ printk("%s:%d! \n", __func__, __LINE__);
+ my_mon->xhci_timeout_cnt = 0;
+ pStatus->core_ops->putt_msg(MON_MSG_USB_A_OUT);
+ pStatus->message_status &= ~(0x1 << MONITOR_A_IN);
+ //umonitor_core_resume();
+ umonitor_detection(1);
+ }
+ }
+ }
+
+ /* process device unnormal state. */
+ if (my_mon->port_status.pc_connected == 0) {
+ if (my_mon->dwc3_status == PLUGSTATE_B_IN) {
+ if (my_mon->dwc3_timeout_cnt > 10) {
+ printk("%s:%d! \n", __func__, __LINE__);
+ my_mon->dwc3_timeout_cnt = 0;
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status &= ~(0x1 << MONITOR_B_IN);
+ //my_mon->xhci_set_plugstate(PLUGSTATE_B_OUT);
+ //my_mon->dwc3_set_plugstate(PLUGSTATE_B_OUT);
+ umonitor_detection(1);
+ }
+ }
+ } else {
+ if (my_mon->dwc3_status != PLUGSTATE_B_IN) {
+ if (my_mon->dwc3_timeout_cnt > 10) {
+ printk("%s:%d! \n", __func__, __LINE__);
+ my_mon->dwc3_timeout_cnt = 0;
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status &= ~(0x1 << MONITOR_B_IN);
+ umonitor_detection(1);
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int mon_thread_port(void *data)
+{
+ unsigned int mtime = 0;
+
+ while (!kthread_should_stop() && (atomic_read(&my_mon->port_exit) == 0)) {
+
+ if (my_mon->run == 0) {
+ wait_event_interruptible(my_mon->mon_wait, my_mon->run);
+ }
+ wait_event_interruptible(my_mon->mon_wait, (my_mon->det_plugin_req != 0) ||
+ kthread_should_stop() ||
+ (my_mon->det_plugout_req != 0));
+ mutex_lock(&my_mon->mon_mutex);
+
+ if (usb_check_msg_and_drv_state()) {
+ spin_lock(&my_mon->lock);
+ if (my_mon->det_plugout_req) {
+ my_mon->det_plugout_req = 0;
+ mod_timer(&my_mon->check_timer, jiffies+ (CHECK_TIMER_INTERVAL*HZ)/2000 + (CHECK_TIMER_INTERVAL*HZ)/1000);
+ }
+ if (my_mon->det_plugin_req) {
+ my_mon->det_plugin_req = 0;
+ mod_timer(&my_mon->port_timer, jiffies+ 3+(CHECK_TIMER_INTERVAL*HZ)/2000 + (CHECK_TIMER_INTERVAL*HZ)/1000);
+ }
+ spin_unlock(&my_mon->lock);
+ mutex_unlock(&my_mon->mon_mutex);
+ continue;
+ }
+
+ if (my_mon->det_plugout_req == 1) {
+ usb_detect_plugout_event();
+ my_mon->det_plugout_req = 0;
+ mutex_unlock(&my_mon->mon_mutex);
+ continue;
+ }
+
+ if (my_mon->det_plugin_req) {
+ umonitor_timer_func();
+ mtime = umonitor_get_timer_step_interval();
+ spin_lock(&my_mon->lock);
+ mod_timer(&my_mon->port_timer, jiffies+(mtime*HZ)/1000);
+ my_mon->det_plugin_req = 0;
+ spin_unlock(&my_mon->lock);
+ mutex_unlock(&my_mon->mon_mutex);
+ continue;
+ }
+ }
+
+ /* mon_thread_port0 already exited */
+ MONITOR_PRINTK("monitor: mon_thread_port0 is going to exit.\n");
+ atomic_set(&my_mon->port_exit, 0);
+ return 0;
+}
+
+static void mon_timer_func_port(unsigned long h)
+{
+ if (!spin_trylock(&my_mon->lock)) {
+ MONITOR_PRINTK("timer0 my_mon->lock unavailable!\n");
+ mod_timer(&my_mon->port_timer, jiffies+1);
+ return;
+ }
+ my_mon->det_plugin_req = 1;
+ spin_unlock(&my_mon->lock);
+ wake_up(&my_mon->mon_wait);
+ return;
+}
+
+static void mon_timer_func_check(unsigned long h)
+{
+ if (!spin_trylock(&my_mon->lock)) {
+ mod_timer(&my_mon->check_timer, jiffies+1);
+ return;
+ }
+ my_mon->det_plugout_req = 1;
+ spin_unlock(&my_mon->lock);
+ wake_up(&my_mon->mon_wait);
+ return;
+}
+
+static ssize_t umonitor_switch_state(struct switch_dev *sdev, char *buf)
+{
+ struct port_dev *port_dev = container_of(sdev, struct port_dev, sdev);
+ return sprintf(buf, "%s\n",port_dev->state_msg);
+}
+
+/*release wake lock*/
+static void monitor_release_wakelock(struct work_struct *work)
+{
+ if (wake_lock_register_cnt > 0) {
+ wake_lock_register_cnt--;
+ printk("\n monitor_release_wakelock wake_unlock %d-\n",wake_lock_register_cnt);
+ wake_unlock(&my_mon->monitor_wake_lock);;
+ }
+}
+
+
+#ifdef CONFIG_OF
+
+struct monitor_data{
+ int ic_type;
+};
+static struct monitor_data atm7039c_data = {
+ .ic_type = IC_ATM7039C,
+
+};
+
+static struct monitor_data atm7059a_data = {
+ .ic_type = IC_ATM7059A,
+};
+
+static const struct of_device_id owl_monitor_of_match[] = {
+ {.compatible = "actions,atm7039c-usbmonitor", .data = &atm7039c_data},
+ {.compatible = "actions,atm7059tc-usbmonitor", .data = &atm7059a_data },
+ {.compatible = "actions,atm7059a-usbmonitor", .data = &atm7059a_data },
+ {}
+
+};
+MODULE_DEVICE_TABLE(of, owl_monitor_of_match);
+#else
+static void monitor_release(struct device *dev)
+{
+ MONITOR_PRINTK("monitor_release\n");
+}
+
+static struct platform_device monitor_device = {
+ .name = "usb_monitor",
+ .id = -1,
+ .num_resources = 0,
+ .resource = NULL,
+ .dev = {
+ .release = monitor_release,
+ },
+};
+#endif
+static int get_configuration_from_dts(struct of_device_id *id )
+{
+ int ret = 0;
+ struct device_node *fdt_node;
+ const char *pp;
+ enum of_gpio_flags flags;
+ umon_port_config_t *port_config = &my_mon->port_config;
+
+ fdt_node = of_find_compatible_node(NULL, NULL, id->compatible);
+ if (NULL == fdt_node) {
+ printk("<umonitor>err: no usb3-fdt-compatible [%s]\n", id->compatible);
+ goto DEFAULT_SETTING;
+ }
+
+ pp = of_get_property(fdt_node, "detect_type", NULL);
+ if (!pp) {
+ printk("<umonitor>err: no config detect_type!use default value:UMONITOR_HOST_AND_DEVICE\n");
+ port_config->detect_type = UMONITOR_HOST_AND_DEVICE;
+ }else{
+ port_config->detect_type = be32_to_cpup((const __be32 *)pp);
+ }
+
+ pp = of_get_property(fdt_node, "idpin_type", NULL);
+ if (!pp) {
+ printk("<umonitor>err: no config idpin_type!use default value:UMONITOR_USB_IDPIN\n");
+ port_config->idpin_type = UMONITOR_USB_IDPIN;
+ }else{
+ port_config->idpin_type = be32_to_cpup((const __be32 *)pp);
+ }
+
+ if(port_config->idpin_type == UMONITOR_GPIO_IDPIN){
+ if (of_find_property(fdt_node, "idpin_gpio", NULL)){
+ port_config->idpin_gpio_no = of_get_named_gpio_flags(fdt_node, "idpin_gpio",0, &flags);
+ if (gpio_request(port_config->idpin_gpio_no, id->compatible)){
+ printk("<umonitor>err: fail to request idpin gpio [%d]\n", port_config->idpin_gpio_no);
+ port_config->idpin_gpio_no = -1;
+ return -1;
+ }else{
+ gpio_direction_input(port_config->idpin_gpio_no);
+ printk("<umonitor> : idpin_type is GPIO_IDPIN, gpio_no=%d\n",port_config->idpin_gpio_no);
+ }
+ }else{
+ port_config->idpin_type = UMONITOR_USB_IDPIN;
+ printk("<umonitor>err : idpin_type is GPIO_IDPIN,but can't find idpin gpio,set idpin_type = UMONITOR_USB_IDPIN\n");
+ }
+
+ }
+
+ pp = of_get_property(fdt_node, "vbus_type", NULL);
+ if (!pp) {
+ printk("<umonitor>err: no config vbus_type!use default value:UMONITOR_DC5V_VBUS\n");
+ port_config->vbus_type = UMONITOR_DC5V_VBUS;
+ }else{
+ port_config->vbus_type = be32_to_cpup((const __be32 *)pp);
+ }
+
+ if (!of_find_property(fdt_node, "vbus_otg_en_gpios", NULL)) {
+ printk("<umonitor>err: no config vbus_otg_engpio!\n");
+ port_config->power_switch_gpio_no = 0xffff;
+ port_config->power_switch_active_level = 1;
+ goto REQUEST_OTG_VBUS;
+ }
+ port_config->power_switch_gpio_no = of_get_named_gpio_flags(fdt_node, "vbus_otg_en_gpios",0, &flags);
+ port_config->power_switch_active_level = flags & OF_GPIO_ACTIVE_LOW;
+
+ REQUEST_OTG_VBUS:
+
+ printk("====otgvbus_gpio: num-%d, active-%s---detect_type=%d,idpin_type=%d,vbus_type=%d---\n",\
+ port_config->power_switch_gpio_no, port_config->power_switch_active_level ? "high" : "low",port_config->detect_type,\
+ port_config->idpin_type,port_config->vbus_type);
+ if (gpio_request(port_config->power_switch_gpio_no, id->compatible)) {
+ printk("<umonitor>err: fail to request vbus gpio [%d]\n", port_config->power_switch_gpio_no);
+ port_config->power_switch_gpio_no = 0xffff;
+ return 0;
+ }
+ //power gpio oupru, power switch off
+ gpio_direction_output(port_config->power_switch_gpio_no, !port_config->power_switch_active_level);
+ gpio_set_value_cansleep(port_config->power_switch_gpio_no, !port_config->power_switch_active_level);
+
+ return ret;
+
+ DEFAULT_SETTING:
+ printk("<umonitor>err: use default setting... \n" );
+ port_config->detect_type = UMONITOR_HOST_AND_DEVICE;
+ port_config->idpin_type = UMONITOR_USB_IDPIN;
+ port_config->vbus_type = UMONITOR_DC5V_VBUS;
+ port_config->power_switch_gpio_no = 0xffff;
+ port_config->power_switch_active_level = 1;
+ goto REQUEST_OTG_VBUS;
+}
+
+
+static int s_dwc3_set_plugstate(int s)
+{
+ int ret;
+
+ my_mon->dwc3_timeout_cnt = 0;
+ if (my_mon->dwc3_status == s)
+ return 0;
+ my_mon->dwc3_status = s;
+ if(s == PLUGSTATE_A_OUT){
+ lock_system_sleep();
+ wake_lock_timeout(&my_mon->monitor_wake_lock, 10*HZ);
+ unlock_system_sleep();
+ ret = dwc3_set_plugstate(s);
+ return ret;
+ }
+ else {
+ return dwc3_set_plugstate(s);
+ }
+}
+
+static int s_xhci_set_plugstate(int s)
+{
+ my_mon->xhci_timeout_cnt = 0;
+ if (my_mon->xhci_status == s)
+ return 0;
+ my_mon->xhci_status = s;
+ return xhci_set_plugstate(s);
+}
+
+static int monitor_probe(struct platform_device *_dev)
+{
+ int ret = 0;
+ void __iomem *base;
+ struct monitor_data *monitor_owl;
+ struct of_device_id *id = (struct of_device_id *)of_match_device(owl_monitor_of_match, &_dev->dev);
+
+ if(id ==NULL)
+ {
+ printk("<umonitor>err: get dts fail !! \n");
+ ret= -EINVAL;
+ goto err_monitor_probe_fail;
+ }
+
+ monitor_owl =(struct monitor_data *) id->data;
+ platform_set_drvdata(_dev, monitor_owl);
+ ret = get_configuration_from_dts(id );
+
+ if (ret != 0)
+ goto err_monitor_probe_fail;
+
+ /*init &my_mon->lock */
+ spin_lock_init(&my_mon->lock);
+ mutex_init(&my_mon->mon_mutex);
+ my_mon->thread_chk_times = 0;
+ my_mon->run = 0;
+ my_mon->tsk = NULL;
+
+ /* status init. */
+ my_mon->port_status.charger_connected = 0;
+ my_mon->port_status.pc_connected = 0;
+ my_mon->port_status.udisk_connected = 0;
+
+ my_mon->port_config.idpin_debug = 0xff;
+ my_mon->port_config.vbus_debug = 0xff;
+ /*
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ printk("missing memory base resource\n");
+ return -EINVAL;
+ }
+
+ base = devm_ioremap(dev, res->start, resource_size(res));
+ */
+
+ base = (void __iomem *)IO_ADDRESS(USB3_REGISTER_BASE);
+ if (!base) {
+ MONITOR_ERR("ioremap failed\n");
+ my_mon->port_config.port_type = PORT_DWC3;
+ ret = -ENOMEM;
+ goto err_monitor_probe_fail;
+ }
+#if SUPPORT_NOT_RMMOD_USBDRV
+ my_mon->dwc3_status = -1;
+ my_mon->xhci_status = -1;
+ my_mon->dwc3_timeout_cnt = 0;
+ my_mon->xhci_timeout_cnt = 0;
+ my_mon->dwc3_set_plugstate = s_dwc3_set_plugstate;
+ my_mon->xhci_set_plugstate = s_xhci_set_plugstate;
+#endif
+
+ my_mon->base = base;
+ MONITOR_PRINTK("my_mon->base is %08x\n",(unsigned int )my_mon->base);
+
+ ret = umonitor_core_init(&my_mon->port_ops, &my_mon->port_config, (unsigned int)my_mon->base);
+ if (ret != 0)
+ goto err_monitor_probe_fail;
+
+ umonitor_status->umonitor_hal.ic_type = monitor_owl->ic_type;
+ /* add for switch device. */
+ my_mon->port_dev.sdev.name = "monitor_dev";
+ my_mon->port_dev.sdev.print_state = umonitor_switch_state;
+ ret = switch_dev_register(&my_mon->port_dev.sdev);
+ if (ret < 0) {
+ MONITOR_ERR("failed to register switch dev0 in umonitor. \n");
+ goto err_monitor_probe_fail;
+ }
+
+ /*WAKE_LOCK_SUSPEND Ϊsuspend lock\A3\AC\BB\B9\D3\D0һ\D6\D6idle lock*/
+ MONITOR_PRINTK(KERN_EMERG"%s--%d, initalize a wake_lock\n", __FILE__, __LINE__);
+ wake_lock_init(&my_mon->monitor_wake_lock, WAKE_LOCK_SUSPEND, "usb_monitor");
+
+ init_waitqueue_head(&my_mon->mon_wait);
+ my_mon->det_plugin_req = 0;
+
+ my_mon->tsk =
+ kthread_create(mon_thread_port, NULL, "usb_monitor");
+
+ if (IS_ERR(my_mon->tsk)) {
+ ret = PTR_ERR(my_mon->tsk);
+ my_mon->tsk = NULL;
+ MONITOR_ERR("err: create monitor thread failed\n");
+ goto out;
+ }
+ wake_up_process(my_mon->tsk);
+ /*register timer and function "mon_timer_func"*/
+ setup_timer(&my_mon->port_timer, mon_timer_func_port, 0);
+ my_mon->port_timer.expires = jiffies + HZ/2;
+ add_timer(&my_mon->port_timer);
+
+ setup_timer(&my_mon->check_timer, mon_timer_func_check, 0);
+ my_mon->check_timer.expires = jiffies + HZ/2;
+ add_timer(&my_mon->check_timer);
+
+ monitor_work_pending =0;
+ wake_lock_register_cnt =0;
+ INIT_DELAYED_WORK(&monitor_work, monitor_release_wakelock);
+ INIT_DELAYED_WORK(&monitor_resume_work, monitor_resume_delay_work);
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ if(owl_get_boot_mode() != OWL_BOOT_MODE_UPGRADE){
+ umonitor_detection(1);
+ my_mon->dwc3_status = PLUGSTATE_B_IN;
+ umonitor_status->message_status |= 0x1 << MONITOR_B_IN;
+ my_mon->port_status.pc_connected = 1;
+ my_mon->port_status.charger_connected = CONNECT_USB_PORT;
+ umonitor_status->detect_valid = 0; //disable detection
+ my_mon->run = 1;
+ }
+#endif
+ my_mon->resume_status = -1;
+ return 0;
+out:
+ switch_dev_unregister(&my_mon->port_dev.sdev);
+err_monitor_probe_fail:
+ my_mon->probe_fail =1;
+ return ret;
+}
+
+static int __exit monitor_remove(struct platform_device *_dev)
+{
+ del_timer_sync(&my_mon->port_timer);
+ del_timer_sync(&my_mon->check_timer);
+ cancel_delayed_work_sync(&monitor_resume_work);
+ //wake_unlock(&my_mon->monitor_wake_lock);
+ wake_lock_destroy(&my_mon->monitor_wake_lock);
+
+ /* wait for mon_thread exit */
+ if (my_mon->tsk != NULL) {
+ atomic_set(&my_mon->port_exit, 1);
+ kthread_stop(my_mon->tsk);
+ }
+
+ msleep(2);
+ if (atomic_read(&my_mon->port_exit) != 0) {
+ MONITOR_ERR("error unable to stop mon_thread_port\n");
+ }
+ my_mon->tsk = NULL;
+
+ switch_dev_unregister(&my_mon->port_dev.sdev);
+ MONITOR_PRINTK("monitor driver remove successufully\n");
+ return 0;
+}
+
+static int monitor_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ unsigned int mtime;
+
+ if (pm_status == PM_HIBERNATION_PREPARE) {
+ return 0;
+ }
+ my_mon->resume_status = 0;
+
+ /*
+ usb charger plugin will triger PLUGSTATE_B_IN ;
+ if usb charger plugin &battery is full,will go into suspend.
+ So here need to plugout before suspend;
+ */
+ if (my_mon->xhci_status == PLUGSTATE_A_IN) {
+ my_mon->xhci_set_plugstate(PLUGSTATE_A_SUSPEND);
+ my_mon->dwc3_set_plugstate(PLUGSTATE_A_SUSPEND);
+ }
+ if (my_mon->dwc3_status == PLUGSTATE_B_IN) {
+ my_mon->xhci_set_plugstate(PLUGSTATE_B_SUSPEND);
+ my_mon->dwc3_set_plugstate(PLUGSTATE_B_SUSPEND);
+ }
+ mtime = 0x70000000;
+ umonitor_core_suspend();
+
+ //delay timer for a long time;may reset timer in resume
+ mod_timer(&my_mon->port_timer, jiffies+(mtime*HZ)/1000);
+ mod_timer(&my_mon->check_timer, jiffies+(mtime*HZ)/1000);
+
+ return 0;
+}
+
+static void monitor_resume_delay_work(struct work_struct *work)
+{
+ umonitor_core_resume();
+ /*mod timer*/
+ mod_timer(&my_mon->port_timer, jiffies+(3100*HZ)/1000);
+ mod_timer(&my_mon->check_timer, jiffies+(4*CHECK_TIMER_INTERVAL*HZ)/1000);
+}
+
+static int monitor_resume(struct platform_device *pdev)
+{
+ my_mon->resume_status = 1;
+ if (pm_status == PM_HIBERNATION_PREPARE) {
+ return 0;
+ }
+ /*in android ,will close controller through vold,so usb device driver is ready*/
+#ifndef CONFIG_USB_PLATFORM_LINUX
+ umonitor_core_resume();
+ /*mod timer*/
+ mod_timer(&my_mon->port_timer, jiffies+(3100*HZ)/1000);
+ mod_timer(&my_mon->check_timer, jiffies+(4*CHECK_TIMER_INTERVAL*HZ)/1000);
+#endif
+ return 0;
+}
+
+static void monitor_shutdown(struct platform_device *pdev)
+{
+ umonitor_core_suspend();
+}
+
+static struct platform_driver monitor_driver = {
+ .probe = monitor_probe,
+ .remove = monitor_remove,
+ .suspend = monitor_suspend,
+ .resume = monitor_resume,
+ .shutdown = monitor_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "usb_monitor",
+ .of_match_table = owl_monitor_of_match,
+ },
+};
+
+static int monitor_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+ unsigned int mtime = 0x70000000;
+
+ if (event == PM_HIBERNATION_PREPARE) {
+ pm_status = PM_HIBERNATION_PREPARE;
+ umonitor_core_suspend();
+ //delay timer for a long time;may reset timer in resume
+ mod_timer(&my_mon->port_timer, jiffies+(mtime*HZ)/1000);
+ mod_timer(&my_mon->check_timer, jiffies+(mtime*HZ)/1000);
+ } else if (event == PM_POST_HIBERNATION) {
+ pm_status = 0;
+ MONITOR_PRINTK(KERN_INFO "monitor resume!\n");
+ umonitor_core_resume();
+ /*mod timer*/
+ mod_timer(&my_mon->port_timer, jiffies+(500*HZ)/1000);
+ mod_timer(&my_mon->check_timer, jiffies+(CHECK_TIMER_INTERVAL*HZ)/1000);
+ }
+ /*in ubuntu ,will close controller after resume finish,so usb device driver is ready*/
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ if(event ==PM_POST_SUSPEND){
+ printk("\n monitor_pm_notify %d\n",__LINE__);
+ if(my_mon->resume_status == 1)
+ schedule_delayed_work(&monitor_resume_work, msecs_to_jiffies(500));
+ }
+#endif
+ return NOTIFY_OK;
+}
+
+static struct notifier_block monitor_pm_notifier = {
+ .notifier_call = monitor_pm_notify,
+};
+
+#if 0
+static int owl_hibernate_notifier_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+
+ switch (event) {
+ case PM_HIBERNATION_PREPARE:
+ //umonitor_dwc_otg_init();
+ break;
+ case PM_POST_HIBERNATION: //\B5ڶ\FE\B4ο\AA\BB\FAʱ\A3\AC\B3ɹ\A6\BBָ\B4\B5\BD\B5\DAһ\B4ιػ\FA\B5\C4״̬ʱ\B5\F7\D3\C3
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block owl_hibernate_notifier = {
+ .notifier_call = owl_hibernate_notifier_event,
+};
+#endif
+
+#if 1 /* add sysfs info. */
+MON_STATUS_ATTR(charger_connected);
+MON_STATUS_ATTR(pc_connected);
+MON_STATUS_ATTR(udisk_connected);
+
+MON_CONFIG_ATTR(run);
+MON_CONFIG_ATTR(detect_type);
+MON_CONFIG_ATTR(port_type);
+/* for idpin config. */
+MON_CONFIG_ATTR(idpin_type);
+MON_CONFIG_ATTR(idpin_gpio_group);
+MON_CONFIG_ATTR(idpin_gpio_no);
+/* for vbus config. */
+MON_CONFIG_ATTR(vbus_type);
+MON_CONFIG_ATTR(vbus_gpio_group);
+MON_CONFIG_ATTR(vbus_gpio_no);
+/* in host state, if vbus power switch onoff use gpio, set it. */
+MON_CONFIG_ATTR(power_switch_gpio_group);
+MON_CONFIG_ATTR(power_switch_gpio_no);
+MON_CONFIG_ATTR(power_switch_active_level);
+MON_CONFIG_ATTR(idpin_debug);
+MON_CONFIG_ATTR(vbus_debug);
+#ifdef SUPPORT_NOT_RMMOD_USBDRV
+MON_CONFIG_ATTR(usb_con_msg);
+#endif
+static struct attribute *mon_status_attrs[] = {
+ MONITOR_ATTR_LIST(charger_connected),
+ MONITOR_ATTR_LIST(pc_connected),
+ MONITOR_ATTR_LIST(udisk_connected),
+ NULL, /* terminator */
+};
+
+static struct attribute_group mon_port_status = {
+ .name = "status",
+ .attrs = mon_status_attrs,
+};
+
+static struct attribute *mon_config_attrs[] = {
+ MONITOR_ATTR_LIST(run),
+ MONITOR_ATTR_LIST(detect_type),
+ MONITOR_ATTR_LIST(port_type),
+ /* for idpin config. */
+ MONITOR_ATTR_LIST(idpin_type),
+ MONITOR_ATTR_LIST(idpin_gpio_group),
+ MONITOR_ATTR_LIST(idpin_gpio_no),
+ /* for vbus config. */
+ MONITOR_ATTR_LIST(vbus_type),
+ MONITOR_ATTR_LIST(vbus_gpio_group),
+ MONITOR_ATTR_LIST(vbus_gpio_no),
+ /* in host state, if vbus power switch onoff use gpio, set it. */
+ MONITOR_ATTR_LIST(power_switch_gpio_group),
+ MONITOR_ATTR_LIST(power_switch_gpio_no),
+ MONITOR_ATTR_LIST(power_switch_active_level),
+ MONITOR_ATTR_LIST(idpin_debug),
+ MONITOR_ATTR_LIST(vbus_debug),
+#ifdef SUPPORT_NOT_RMMOD_USBDRV
+ MONITOR_ATTR_LIST(usb_con_msg),
+#endif
+ NULL, /* terminator */
+};
+
+static struct attribute_group mon_port_config = {
+ .name = "config",
+ .attrs = mon_config_attrs,
+};
+
+
+static ssize_t mon_status_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct mon_sysfs_status *p_status;
+
+ if(my_mon->probe_fail ==1){
+ printk("\n monitor: probe_fail =1!!");
+ return -ENOENT;
+ }
+ if (kobj == my_mon->mon_port) {
+ p_status = &my_mon->port_status;
+ } else {
+ return -ENOENT;
+ }
+
+ if (ATTRCMP(charger_connected)) {
+ return sprintf(buf, "%d\n", p_status->charger_connected);
+ } else if (ATTRCMP(pc_connected)) {
+ return sprintf(buf, "%d\n", p_status->pc_connected);
+ } else if (ATTRCMP(udisk_connected)) {
+ return sprintf(buf, "%d\n", p_status->udisk_connected);
+ } else {
+ }
+ return -ENOENT;
+}
+
+static ssize_t mon_config_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ umon_port_config_t *pconfig;
+
+ if(my_mon->probe_fail ==1){
+ printk("\n monitor: probe_fail =1!!");
+ return -ENOENT;
+ }
+ if (kobj == my_mon->mon_port) {
+ pconfig = &my_mon->port_config;
+ } else {
+ return -ENOENT;
+ }
+
+ if (ATTRCMP(run)) {
+ //return sprintf(buf, "%d\n", umonitor_get_run_status());
+ return sprintf(buf, "%d\n", my_mon->run);
+ } else if(ATTRCMP(detect_type)) {
+ return sprintf(buf, "%d\n", pconfig->detect_type);
+ } else if(ATTRCMP(idpin_type)) {
+ return sprintf(buf, "%d\n", pconfig->idpin_type);
+ } else if(ATTRCMP(port_type)) {
+ *buf = pconfig->port_type;
+ return sizeof(char);
+ } else if(ATTRCMP(idpin_gpio_group)) {
+ return sprintf(buf, "%d\n", pconfig->idpin_gpio_group);
+ } else if(ATTRCMP(idpin_gpio_no)) {
+ return sprintf(buf, "%d\n", pconfig->idpin_gpio_no);
+ } else if(ATTRCMP(vbus_type)) {
+ return sprintf(buf, "%d\n", pconfig->vbus_type);
+ } else if(ATTRCMP(vbus_gpio_group)) {
+ return sprintf(buf, "%d\n", pconfig->vbus_gpio_group);
+ } else if(ATTRCMP(vbus_gpio_no)) {
+ return sprintf(buf, "%d\n", pconfig->vbus_gpio_no);
+ }else if(ATTRCMP(power_switch_gpio_group)) {
+ return sprintf(buf, "%d\n", pconfig->power_switch_gpio_group);
+ } else if(ATTRCMP(power_switch_gpio_no)) {
+ return sprintf(buf, "%d\n", pconfig->power_switch_gpio_no);
+ } else if(ATTRCMP(power_switch_active_level)) {
+ return sprintf(buf, "%d\n", pconfig->power_switch_active_level);
+ }else if(ATTRCMP(idpin_debug)) {
+ return sprintf(buf, "%d\n", pconfig->idpin_debug);
+ }else if(ATTRCMP(vbus_debug)) {
+ return sprintf(buf, "%d\n", pconfig->vbus_debug);
+ }
+#ifdef SUPPORT_NOT_RMMOD_USBDRV
+ else if(ATTRCMP(usb_con_msg)) {
+ return sprintf(buf, "%s\n", pconfig->usb_con_msg);
+ }
+#endif
+ else {
+ /* do nothing. */
+ }
+
+ return -ENOENT;
+}
+
+static ssize_t mon_config_store(struct kobject *kobj, struct kobj_attribute *attr, const char *instr, size_t bytes)
+{
+ unsigned long val;
+ unsigned int ret, plugstatus;
+ umon_port_config_t *pconfig;
+
+ if(my_mon->probe_fail ==1){
+ printk("\n monitor: probe_fail =1!!");
+ return -ENOENT;
+ }
+ mutex_lock(&my_mon->mon_mutex);
+
+ if (kobj == my_mon->mon_port) {
+ pconfig = &my_mon->port_config;
+ } else {
+ MONITOR_PRINTK("store no err!\n");
+ goto out;
+ }
+
+ ret = kstrtoul(instr, 0, &val);
+ MONITOR_PRINTK("kstrtoul:%d\n", (unsigned int)val);
+
+ if (ATTRCMP(run)) {
+ my_mon->run = val;
+ if(val == 1) {
+#ifndef CONFIG_USB_PLATFORM_LINUX
+ umonitor_detection(val);
+#endif
+ } else if (val == 2) {
+ MONITOR_PRINTK("vbus on off\n");
+ usb_set_vbus_power(0);
+ mdelay(500);
+ plugstatus = umonitor_get_message_status();
+ if( (plugstatus & (0x1 << MONITOR_A_IN)) !=0)
+ usb_set_vbus_power(1);
+
+ } else if (val == 3) {
+ mon_port_putt_msg(MON_MSG_USB_B_OUT);
+ } else if (val == 4) {
+ mon_port_putt_msg(MON_MSG_USB_B_IN);
+ } else if (val == 5) {
+#ifndef CONFIG_USB_PLATFORM_LINUX
+#if SUPPORT_NOT_RMMOD_USBDRV
+ my_mon->dwc3_set_plugstate(PLUGSTATE_B_OUT);
+ my_mon->xhci_set_plugstate(PLUGSTATE_B_OUT);
+#endif
+#endif
+ }else {
+ }
+ } else if(ATTRCMP(detect_type)) {
+ pconfig->detect_type = val;
+ } else if(ATTRCMP(idpin_type)) {
+ pconfig->idpin_type = val;
+ } else if(ATTRCMP(idpin_gpio_group)) {
+ pconfig->idpin_gpio_group = val;
+ } else if(ATTRCMP(idpin_gpio_no)) {
+ pconfig->idpin_gpio_no = val;
+ } else if(ATTRCMP(vbus_type)) {
+ pconfig->vbus_type = val;
+ } else if(ATTRCMP(vbus_gpio_group)) {
+ pconfig->vbus_gpio_group = val;
+ } else if(ATTRCMP(vbus_gpio_no)) {
+ pconfig->vbus_gpio_no = val;
+ } else if(ATTRCMP(power_switch_gpio_group)) {
+ pconfig->power_switch_gpio_group = val;
+ } else if(ATTRCMP(power_switch_gpio_no)) {
+ pconfig->power_switch_gpio_no = val;
+ } else if(ATTRCMP(power_switch_active_level)) {
+ /* backdoor for debug. */
+ if (val == 2) {
+ umonitor_printf_debuginfo();
+ }else{
+ pconfig->power_switch_active_level = val;
+ }
+ }else if(ATTRCMP(idpin_debug)) {
+ pconfig->idpin_debug = val;
+ if((val ==0)||(val ==1))
+ printk("\n debug idpin set =%d !!\n",pconfig->idpin_debug);
+ else
+ printk("\n debug idpin clear!!\n");
+ }else if(ATTRCMP(vbus_debug)) {
+ pconfig->vbus_debug = val;
+ if((val ==0)||(val ==1))
+ printk("\n debug vbus set =%d!!\n",pconfig->vbus_debug);
+ else
+ printk("\n debug vbus clear!!\n");
+ }
+#ifndef CONFIG_USB_PLATFORM_LINUX
+#ifdef SUPPORT_NOT_RMMOD_USBDRV
+ else if(ATTRCMP(usb_con_msg)) {
+ strcpy(pconfig->usb_con_msg,instr);
+ monitor_handle_plug_in_out_msg(instr);
+ printk("\n write usb_con_msg %s\n",instr);
+ }
+#endif
+#endif
+ else {
+ /* do nothing. */
+ MONITOR_PRINTK("store attr err!\n");
+ }
+
+out:
+ mutex_unlock(&my_mon->mon_mutex);
+ return bytes;
+}
+
+int mon_sysfs_init(void)
+{
+ int ret = 0;
+
+ my_mon->mon_obj = kobject_create_and_add("monitor", NULL);
+ if (!my_mon->mon_obj) {
+ MONITOR_ERR("unable to create monitor kobject\n");
+ }
+ my_mon->mon_port = kobject_create_and_add("usb_port", my_mon->mon_obj);
+ if (!my_mon->mon_port) {
+ MONITOR_ERR("unable to create usb_port kobject\n");
+ }
+
+ ret = sysfs_create_group(my_mon->mon_port, &mon_port_status);
+ if (ret != 0) {
+ MONITOR_ERR("create usb_port status group failed\n");
+ }
+ ret = sysfs_create_group(my_mon->mon_port, &mon_port_config);
+ if (ret != 0) {
+ MONITOR_ERR("create usb_port cofig group failed\n");
+ }
+ /* ignore failed case. */
+ return 0;
+}
+
+int mon_sysfs_exit(void)
+{
+ sysfs_remove_group(my_mon->mon_port, &mon_port_status);
+ sysfs_remove_group(my_mon->mon_port, &mon_port_config);
+ kobject_del(my_mon->mon_port);
+ kobject_del(my_mon->mon_obj);
+ return 0;
+}
+#endif /* add sysfs info. */
+
+static int usb_detect_plugout_event(void)
+{
+ usb_hal_monitor_t * p_hal;
+ unsigned int val;
+ unsigned int message;
+ int ret;
+
+ p_hal = &umonitor_status->umonitor_hal;
+ message = umonitor_status->message_status;
+
+ if(umonitor_status->detect_valid == 0) {
+
+ if (umonitor_status->det_phase == 0) {
+ if(((message & (0x1 << MONITOR_B_IN)) != 0) ||
+ ((message & (0x1 << MONITOR_CHARGER_IN)) != 0)) {
+ if(( my_mon->port_status.charger_connected == CONNECT_USB_ADAPTOR) &&
+ (wake_lock_register_cnt > 0)) {
+ printk("wakelock release!!!!!!!!\n");
+ wake_lock_register_cnt--;
+ wake_unlock(&my_mon->monitor_wake_lock);
+ }
+ umonitor_status->vbus_status = (unsigned char) p_hal->get_vbus_state(p_hal);
+ ret = p_hal->get_idpin_state(p_hal);
+ if((umonitor_status->vbus_status == USB_VBUS_LOW)||(ret==USB_ID_STATE_HOST)) {
+ my_mon->port_status.charger_connected = 0;
+ umonitor_detection(1);
+ printk("\n========usb_detect_plugout_event===start det!!========\n");
+ //wake_up(&my_mon->mon_wait);
+ }
+ }
+ } else {
+ /*host set monitor flag*/
+ if((message & (0x1 << MONITOR_A_IN)) != 0) {
+ val = p_hal->get_idpin_state(p_hal);
+ if(val != USB_ID_STATE_HOST) {
+ umonitor_detection(1);
+ //wake_up(&my_mon->mon_wait);
+ }
+ }
+ }
+
+ mod_timer(&my_mon->check_timer, jiffies + (CHECK_TIMER_INTERVAL*HZ)/1000);
+ } else {
+ mod_timer(&my_mon->check_timer, jiffies + 3 + (2 * CHECK_TIMER_INTERVAL * HZ)/1000);
+ }
+
+ return 0;
+}
+
+int notify_driver_state(int driver_state, int driver_type)
+{
+ return 0;
+}
+EXPORT_SYMBOL(notify_driver_state);
+
+static void mon_port_wakeup_func(void)
+{
+ my_mon->det_plugin_req = 1;
+ wake_up(&my_mon->mon_wait);
+ return;
+}
+
+static void mon_port_putt_msg(unsigned int msg)
+{
+ struct mon_sysfs_status * pStatus;
+ usb_hal_monitor_t *p_hal;
+
+ pStatus = &my_mon->port_status;
+ p_hal = &umonitor_status->umonitor_hal;
+
+ switch (msg) {
+ case MON_MSG_USB_B_IN:
+ //printk("%s--%d, wake_lock !!! \n", __FILE__, __LINE__);
+ if(monitor_work_pending == 1) {
+ cancel_delayed_work_sync(&monitor_work);
+ monitor_work_pending = 0;
+ }
+ if(!wake_lock_register_cnt) {
+ printk("%s--%d, wake_lock !!! \n", __FILE__, __LINE__);
+ wake_lock(&my_mon->monitor_wake_lock);
+ wake_lock_register_cnt++;
+ }
+ pStatus->pc_connected = 1;
+ pStatus->charger_connected = CONNECT_USB_PORT;//set usb pc first,it'll jude by dwc3 interrupt
+ sprintf(my_mon->port_dev.state_msg, "USB_B_IN");
+
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ monitor_handle_plug_in_out_msg(my_mon->port_dev.state_msg);//handle usb msg in monitor
+#else
+ switch_set_state(&my_mon->port_dev.sdev, msg); //handle usb msg through vold
+#endif
+ break;
+ case MON_MSG_USB_B_OUT:
+ //printk("%s--%d, wake_unlock !!! \n", __FILE__, __LINE__);
+ if(wake_lock_register_cnt) {
+ schedule_delayed_work(&monitor_work, msecs_to_jiffies(1000));
+ monitor_work_pending = 1;
+ }
+ pStatus->pc_connected = 0;
+ pStatus->charger_connected = 0;
+ sprintf(my_mon->port_dev.state_msg, "USB_B_OUT");
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ monitor_handle_plug_in_out_msg(my_mon->port_dev.state_msg);//handle usb msg in monitor
+#else
+ switch_set_state(&my_mon->port_dev.sdev, msg); //handle usb msg through vold
+#endif
+ break;
+ case MON_MSG_USB_A_IN:
+ pStatus->udisk_connected = 1;
+ printk("%s--%d, wake_lock !!! \n", __FILE__, __LINE__);
+ //wake_lock(&my_mon->monitor_wake_lock);
+ sprintf(my_mon->port_dev.state_msg, "USB_A_IN");
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ monitor_handle_plug_in_out_msg(my_mon->port_dev.state_msg);//handle usb msg in monitor
+#else
+ switch_set_state(&my_mon->port_dev.sdev, msg); //handle usb msg through vold
+#endif
+ wake_lock_timeout(&my_mon->monitor_wake_lock, 10*HZ);
+ printk("----monitor_wake_lock for 10s \n");
+ break;
+ case MON_MSG_USB_A_OUT:
+ pStatus->udisk_connected = 0;
+ printk("%s--%d, wake_unlock !!! \n", __FILE__, __LINE__);
+ //wake_unlock(&my_mon->monitor_wake_lock);
+ sprintf(my_mon->port_dev.state_msg, "USB_A_OUT");
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ monitor_handle_plug_in_out_msg(my_mon->port_dev.state_msg);//handle usb msg in monitor
+#else
+ switch_set_state(&my_mon->port_dev.sdev, msg); //handle usb msg through vold
+#endif
+ wake_lock_timeout(&my_mon->monitor_wake_lock, 10*HZ);
+ break;
+ case MON_MSG_USB_CHARGER_IN:
+ pStatus->charger_connected = 1;
+ //printk("%s--%d, wake_lock !!! \n", __FILE__, __LINE__);
+ wake_lock(&my_mon->monitor_wake_lock);
+ sprintf(my_mon->port_dev.state_msg, "USB_CHARGER_IN");
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ monitor_handle_plug_in_out_msg(my_mon->port_dev.state_msg);//handle usb msg in monitor
+#else
+ switch_set_state(&my_mon->port_dev.sdev, msg); //handle usb msg through vold
+#endif
+ break;
+ case MON_MSG_USB_CHARGER_OUT:
+ pStatus->charger_connected = 0;
+ printk("%s--%d, wake_unlock !!! \n", __FILE__, __LINE__);
+ wake_unlock(&my_mon->monitor_wake_lock);
+ sprintf(my_mon->port_dev.state_msg, "USB_CHARGER_OUT");
+#ifdef CONFIG_USB_PLATFORM_LINUX
+ monitor_handle_plug_in_out_msg(my_mon->port_dev.state_msg);//handle usb msg in monitor
+#else
+ switch_set_state(&my_mon->port_dev.sdev, msg); //handle usb msg through vold
+#endif
+ break;
+ default:
+ MONITOR_ERR("err msg:%0x\n", msg);
+ break;
+ }
+ return;
+}
+
+int usb_set_vbus_power(int value)
+{
+ return umonitor_vbus_power_onoff(value);
+}
+EXPORT_SYMBOL_GPL(usb_set_vbus_power);
+
+void monitor_set_usb_plugin_type(int value)
+{
+ my_mon->port_status.charger_connected = value;
+ /* when connect to pc, some reason make pc send reset interrupt at a long time later,
+ * at this point maybe we have released wakelock;so we get wakelock again here!
+ */
+ if((wake_lock_active(&my_mon->monitor_wake_lock)==false)&&(value==CONNECT_USB_PORT)&&(my_mon->run==1)){
+ printk("\n usb reset interrupt,get wakelock!!\n");
+ wake_lock_register_cnt=1;
+ wake_lock(&my_mon->monitor_wake_lock);
+ }
+}
+EXPORT_SYMBOL_GPL(monitor_set_usb_plugin_type);
+static int __init monitor_init(void)
+{
+ int ret;
+
+ atomic_set(&my_mon->port_exit, 0);
+
+ my_mon->port_ops.wakeup_func = mon_port_wakeup_func;
+ my_mon->port_ops.putt_msg = mon_port_putt_msg;
+ my_mon->probe_fail =0;
+#ifndef CONFIG_OF
+ ret = platform_device_register(&monitor_device);
+ if (ret < 0) {
+ MONITOR_ERR("Can't register monitor platform device, ret:%d\n", ret);
+ }
+#endif
+
+ ret = platform_driver_register(&monitor_driver);
+ if (ret < 0) {
+ MONITOR_ERR("monitor driver register failed,err is %d\n", ret);
+ }
+ /*create director "/sys/monitor", "/sys/usb_port" and attribute file: */
+ ret = mon_sysfs_init();
+ if (ret < 0) {
+ MONITOR_ERR("mon_sysfs_init failed,err is %d\n", ret);
+ }
+
+ set_usb_plugin_type = (FUNC )kallsyms_lookup_name("atc260x_set_usb_plugin_type");
+ register_pm_notifier(&monitor_pm_notifier);
+ //register_hibernate_notifier(&owl_hibernate_notifier);
+
+ return ret;
+}
+
+static void __exit monitor_exit(void)
+{
+ //unregister_hibernate_notifier(&owl_hibernate_notifier);
+ unregister_pm_notifier(&monitor_pm_notifier);
+ platform_driver_unregister(&monitor_driver);
+#ifndef CONFIG_OF
+ platform_device_unregister(&monitor_device);
+#endif
+
+ umonitor_core_exit();
+
+ mon_sysfs_exit();
+
+ gpio_free(my_mon->port_config.power_switch_gpio_no);
+
+ MONITOR_PRINTK("end of monitor_exit\n");
+ return;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("houjingkun");
+
+late_initcall_sync(monitor_init);
+module_exit(monitor_exit);
+
diff --git a/drivers/usb/monitor/umonitor_config.h b/drivers/usb/monitor/umonitor_config.h
new file mode 100644
index 0000000..03bfaea
--- /dev/null
+++ b/drivers/usb/monitor/umonitor_config.h
@@ -0,0 +1,108 @@
+/*! \cond USBMONITOR*/
+/*********************************************************************************
+* Module: usb monitor driver
+* (c) Copyright 2003 - 2008, Actions Co,Ld.
+* All Right Reserved
+*
+* History:
+* <author> <time> <version > <desc>
+* houjingkun 2011/07/08 1.0 build this file
+********************************************************************************/
+/*!
+ * \file umonitor_config.h
+ * \brief
+ * usb monitor configure headfile.
+ * \author houjingkun
+ * \par GENERAL DESCRIPTION:
+ * \par EXTERNALIZED FUNCTIONS:
+ * null
+ *
+ * Copyright(c) 2008-2012 Actions Semiconductor, All Rights Reserved.
+ *
+ * \version 1.0
+ * \date 2011/07/08
+ *******************************************************************************/
+#ifndef _UMONITOR_CONFIG_H_
+#define _UMONITOR_CONFIG_H_
+#define SUPPORT_NOT_RMMOD_USBDRV 1
+//#ifdef ATM7029_EVB
+//#define GPIO_VBUS_SUPPLY 0x28 //KS_OUT1 GPIOB8 001 01000
+//#endif
+//
+//#ifdef ATM7029_DEMO
+//#define GPIO_VBUS_SUPPLY 0x11 //RMII_RXER GPIPA17 010 10001
+//#endif
+
+#define CHECK_TIMER_INTERVAL 1000
+
+
+#define __GPIO_GROUP(x) ((x) >> 5)
+#define __GPIO_NUM(x) ((x) & 0x1f)
+
+typedef struct umon_port_config {
+ #define UMONITOR_DISABLE 0
+ #define UMONITOR_DEVICE_ONLY 1
+ #define UMONITOR_HOST_ONLY 2
+ #define UMONITOR_HOST_AND_DEVICE 3
+ unsigned char detect_type; /* usb port detect request. */
+ /* if detect_type == UMONITOR_DISABLE, below is no use. */
+
+ unsigned char port_type;
+ #define PORT_DWC3 0
+ #define PORT_USB2 1
+
+
+ #define UMONITOR_USB_IDPIN 0
+ #define UMONITOR_SOFT_IDPIN 1
+ #define UMONITOR_GPIO_IDPIN 2 /* gpio detect idpin. */
+ unsigned char idpin_type;
+ /*
+ * if idpin_type set to UMONITOR_USB_IDPIN or UMONITOR_SOFT_IDPIN,
+ * below is no use.
+ */
+ unsigned char idpin_gpio_group;
+ unsigned int idpin_gpio_no;
+
+ #define UMONITOR_USB_VBUS 0
+ #define UMONITOR_GPIO_VBUS 1 /* gpio detect vbus. */
+ #define UMONITOR_DC5V_VBUS 2 /* use dc5v to detect vbus. */
+ unsigned char vbus_type;
+ /*
+ * if vbus_type set to UMONITOR_USB_VBUS, below is no use.
+ */
+ unsigned char vbus_gpio_group;
+ unsigned int vbus_gpio_no;
+
+ /* in host state, if vbus power switch onoff use gpio, set it. */
+ unsigned char power_switch_gpio_group;
+ unsigned int power_switch_gpio_no;
+ unsigned char power_switch_active_level;
+#ifdef SUPPORT_NOT_RMMOD_USBDRV
+ /* add a node to receive vold msg ,to open close controlers */
+ char usb_con_msg[32];
+#endif
+ /*add a node to fix idpin&vbus state, let user can detect host/device as wish*/
+ unsigned char idpin_debug;
+ unsigned char vbus_debug;
+} umon_port_config_t;
+
+
+
+//#define DEBUG_MONITOR
+//#define ERR_MONITOR
+
+#ifdef DEBUG_MONITOR
+#define MONITOR_PRINTK(fmt, args...) printk(KERN_INFO fmt, ## args)
+#else
+#define MONITOR_PRINTK(fmt, args...) /*not printk*/
+#endif
+
+#ifdef ERR_MONITOR
+#define MONITOR_ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
+#else
+#define MONITOR_ERR(fmt, args...) /*not printk*/
+#endif
+
+#endif /* _UMONITOR_CONFIG_H_ */
+/*! \endcond*/
+
diff --git a/drivers/usb/monitor/umonitor_core.c b/drivers/usb/monitor/umonitor_core.c
new file mode 100644
index 0000000..d768a7b
--- /dev/null
+++ b/drivers/usb/monitor/umonitor_core.c
@@ -0,0 +1,1016 @@
+/*********************************************************************************
+* Module: usb monitor driver
+* (c) Copyright 2003 - 2008, Actions Co,Ld.
+* All Right Reserved
+*
+* History:
+* <author> <time> <version > <desc>
+* houjingkun 2011/07/08 1.0 build this file
+********************************************************************************/
+/*!
+ * \file umonitor_core.c
+ * \brief
+ * usb monitor detect opration code.
+ * \author houjingkun
+ * \par GENERAL DESCRIPTION:
+ * \par EXTERNALIZED FUNCTIONS:
+ * null
+ *
+ * Copyright(c) 2008-2012 Actions Semiconductor, All Rights Reserved.
+ *
+ * \version 1.0
+ * \date 2011/07/08
+ *******************************************************************************/
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/poll.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include "aotg_regs.h"
+#include "umonitor_config.h"
+#include "umonitor_core.h"
+
+
+enum {
+ USB_DET_NONE = 0, /* nothing detected, maybe B plus is out. */
+ USB_DET_DEVICE_DEBUOUNCING, /* detected device, debouncing and confirming. */
+ USB_DET_DEVICE_PC, /* detected device confirmed. pc connected. */
+ USB_DET_DEVICE_CHARGER /* detected device confirmed. charger connected. */
+};
+
+enum {
+ USB_DET_HOST_NONE = 0, /* nothing detected. maybe udisk is plug out. */
+ USB_DET_HOST_DEBOUNCING, /* detecting host, debouncing and confirming. */
+ USB_DET_HOST_UDISK /* detected udisk confirmed. udisk connected. */
+};
+
+#define USB_DEVICE_DETECT_STEPS 4
+#define USB_HOST_DETECT_STEPS 4
+#define USB_MONITOR_DEF_INTERVAL 500 /* interval to check usb port state, unit: ms. */
+
+umonitor_dev_status_t *umonitor_status;
+static int usb_monitor_debug_status_inf( void )
+{
+#if 0
+ umonitor_dev_status_t *pStatus = umonitor_status;
+
+ printk(KERN_INFO ".det_phase %d %d %d %d %d \n",
+ (unsigned int) pStatus->det_phase,
+ (unsigned int) pStatus->vbus_status,
+ (unsigned int) pStatus->timer_steps,
+ (unsigned int) pStatus->host_confirm,
+ (unsigned int) pStatus->message_status);
+ printk(KERN_INFO "-----------------------------\n");
+ printk(KERN_INFO ".vbus_status %d %x \n", (unsigned int) pStatus->vbus_status,
+ (unsigned int) pStatus->vbus_status);
+ printk(KERN_INFO ".vbus_enable_power %d\n", (unsigned int) pStatus->vbus_enable_power);
+ printk(KERN_INFO ".det_phase %d \n", (unsigned int) pStatus->det_phase);
+ printk(KERN_INFO ".device_confirm %d\n", (unsigned int) pStatus->device_confirm);
+ printk(KERN_INFO ".host_confirm %d \n", (unsigned int) pStatus->host_confirm);
+ printk(KERN_INFO ".usb_pll_on %d \n", (unsigned int) pStatus->usb_pll_on);
+ printk(KERN_INFO ".dp_dm_status %d 0x%x \n", (unsigned int) pStatus->dp_dm_status,
+ (unsigned int) pStatus->dp_dm_status);
+ printk(KERN_INFO ".timer_steps %d \n", (unsigned int) pStatus->timer_steps);
+ printk(KERN_INFO ".timer_interval %d \n", (unsigned int) pStatus->timer_interval);
+ printk(KERN_INFO ".check_cnt %d \n", (unsigned int) pStatus->check_cnt);
+ printk(KERN_INFO ".sof_check_times %d\n", (unsigned int) pStatus->sof_check_times);
+ printk(KERN_INFO "\n \n ");
+#endif
+ return 0;
+}
+
+static int usb_init_monitor_status(umonitor_dev_status_t * pStatus)
+{
+
+ pStatus->detect_valid = 0;
+ pStatus->detect_running = 0;
+ pStatus->vbus_status = 0;
+ pStatus->dc5v_status = 0;
+ pStatus->det_phase = 0;
+ pStatus->device_confirm = 0;
+ pStatus->sof_check_times = 0;
+ pStatus->host_confirm = 0;
+ pStatus->usb_pll_on = 0;
+ pStatus->dp_dm_status = 0;
+ pStatus->timer_steps = 0;
+ pStatus->timer_interval = USB_MONITOR_DEF_INTERVAL;
+ pStatus->check_cnt = 0;
+ pStatus->message_status = 0;
+ pStatus->core_ops = NULL;
+
+ pStatus->vbus_enable_power = 0;
+
+ return 0;
+}
+
+/* \BB\F1ȡ\D4\CB\D0е\BD\CF\C2һ\B4μ\EC\B2\E2\B5\C4ʱ\BC\E4\BC\E4\B8\F4\A3\AC\B7\B5\BB\D8ֵ\D2Ժ\C1\C3\EBΪ\B5\A5λ\A1\A3 */
+unsigned int umonitor_get_timer_step_interval(void)
+{
+ umonitor_dev_status_t *pStatus;
+
+ pStatus = umonitor_status;
+
+ if ((pStatus->port_config->detect_type == UMONITOR_DISABLE)
+ || (pStatus->detect_valid == 0)) {
+ return 0x70000000; /* be longer enough that it would not run again. */
+ }
+
+ if (pStatus->timer_steps == 0) {
+ //pStatus->timer_interval = USB_MONITOR_DEF_INTERVAL;
+ pStatus->timer_interval = 30; /*\D6\D8\D0½\F8\C8\EBstep 0 \BC\EC\B2\E9 */
+ goto out;
+ }
+
+ if (pStatus->det_phase == 0) {
+ switch (pStatus->timer_steps) {
+ /*
+ * 1\A3\AD3\B2\BD\A3\AC\BC\EC\B2\E2ʱ\BC\E4\BC\E4\B8\F4500 ms\A3\A8\BFɵ\F7\D5\FB\A3\A9\A3\ACһ\B5\A9\B6˿\DA\D3б仯\C2\ED\C9ϵ\F7\B5\BD\B5\DA\CBIJ\BD\A3\AC
+ * \BD\F8\C8\EBdebounce\BA\CDconfirm״̬\A1\A3
+ */
+ case 1:
+ case 2:
+ case 3:
+ pStatus->timer_interval = USB_MONITOR_DEF_INTERVAL;
+ break;
+
+ case 4:
+ switch (pStatus->device_confirm) {
+ case 0: /* \BD\F8\C8\EB\B5\DA4\B2\BD\A3\AC\CF\C2һ\B2\BD\CAǼ\EC\B2\E2\B6˿\DAvbus\D3\D0\CEޱ仯\A1\A3 */
+ pStatus->timer_interval =
+ USB_MONITOR_DEF_INTERVAL;
+ break;
+
+ case 1: /* \D2Ѿ\AD\BC\EC\B2\B6˿\DAvbus\D3е磬\D0\E8Ҫ\CF\C2һ\B2\BD\D4\D9ȷ\C8\CFһ\B4Ρ\A3 */
+ pStatus->timer_interval = 10; /* 10 ms, 1 tick. */
+ break;
+
+ /*
+ * device_confirm == 2, \D2Ѿ\ADȷ\C8\CFvbus\D3е磬\B2\A2enable\C9\CF\C0\AD500k\A3\AC
+ * disable\CF\C2\C0\AD15k\A3\AC\CF\C2һ\B2\BD\BC\EC\B2\E2dp\A1\A2dm״̬\A1\A3
+ */
+ case 2:
+ pStatus->timer_interval = 300;
+ break;
+
+ /* \B5\DAһ\B4λ\F1ȡdp\A1\A2dm״̬\A3\AC\D0\E8Ҫ\CF\C2һ\B4\CE\D4\D9ȷ\C8\CFһ\B4Ρ\A3 */
+ case 3:
+ pStatus->timer_interval = 30;
+ break;
+
+ /*
+ * \BD\F8\C8\EB\D5\E2һ\B2\BD\A3\AC\D0\E8Ҫ\B6\E0\B4\CE\C5ж\CFpc\CAǷ\F1\D3\D0sof\BB\F2reset\D0źŸ\F8С\BB\FA\A3\AC\D5\E2\C0\EFÿ20\BA\C1\C3\EB\B2\E9ѯsof\D6ж\CFһ\B4Σ\AC
+ * \C0ۻ\FD\BB\E1\B2\E9ѯ MAX_DETECT_SOF_CNT \B4Σ\AC\B5ȴ\FDʱ\BC\E4\BF\C9\C4ܻ\E1\D3\D08\C3\EB\D2\D4\C9ϡ\A3
+ * \D2\F2Ϊ\B4\D3С\BB\FAdp\C9\CF\C0\AD\B5\BDpc\B7\A2sof\A3\AC\D6м\E4\BF\C9\C4\DC\D1\D3ʱ\B3\A4\B4\EF8\C3\EB\D2\D4\C9ϡ\A3
+ */
+ /* wait sof again time interval, the whole detect sof time is (20 * sof_check_times) msecond. */
+ case 4:
+ pStatus->timer_interval = 20;
+ break;
+
+ default:
+ USB_ERR_PLACE;
+ pStatus->timer_interval =
+ USB_MONITOR_DEF_INTERVAL;
+ break;
+ }
+ break;
+
+ default:
+ USB_ERR_PLACE;
+ pStatus->timer_interval = USB_MONITOR_DEF_INTERVAL;
+ break;
+ }
+ } else {
+ switch (pStatus->timer_steps) {
+ case 1: /* \B4\D3step 0\B5\C4idle״̬\C7л\BB\B5\BDvbus\B6\D4\CD\B5\E7\B5\C4ʱ\BC\E4\BC\E4\B8\F4\A1\A3 */
+ pStatus->timer_interval = 30;
+ break;
+
+ case 2: /* vbus\B6\D4\CD\B5\E7\BA\BD\BF\AAʼ\B5\DA2\B4μ\EC\B2⣬\C5ж\CFdp\CAǷ\F1\C9\CF\C0\AD\B5\C4ʱ\BC䡣 */
+ pStatus->timer_interval = 600;
+ break;
+
+ case 3: /* \B5\DA2\B4μ\EC\B2\B5\DA3\B4μ\EC\B2\E2֮\BC䣬\C5ж\CFdp\CAǷ\F1\C9\CF\C0\AD\B5\C4ʱ\BC䡣 */
+ pStatus->timer_interval = 600;
+ break;
+
+ case 4:
+ switch (pStatus->host_confirm) {
+ case 0:
+ pStatus->timer_interval =
+ USB_MONITOR_DEF_INTERVAL;
+ break;
+
+ case 1: /* debounce time. */
+ pStatus->timer_interval = 10; /* 10 ms, 1 tick. */
+ break;
+
+ default:
+ USB_ERR_PLACE;
+ pStatus->timer_interval =
+ USB_MONITOR_DEF_INTERVAL;
+ break;
+ }
+ break;
+
+ default:
+ USB_ERR_PLACE;
+ pStatus->timer_interval = USB_MONITOR_DEF_INTERVAL;
+ break;
+ }
+ }
+
+out:
+ return pStatus->timer_interval;
+}
+
+/*
+ * retval:
+ * refer to below macro:
+ * USB_DET_NONE,
+ * USB_DET_DEVICE_DEBUOUNCING,
+ * USB_DET_DEVICE_PC,
+ * USB_DET_DEVICE_CHARGER,
+ */
+static int usb_timer_det_pc_charger(umonitor_dev_status_t * pStatus)
+{
+ int ret = 0;
+ unsigned int val = 0;
+ usb_hal_monitor_t *p_hal = &pStatus->umonitor_hal;
+
+ MONITOR_PRINTK("entring usb_timer_det_pc_charger\n");
+
+ if (pStatus->device_confirm == 0) {
+ /* make sure power off. */
+ if (pStatus->vbus_enable_power != 0) {
+ p_hal->vbus_power_onoff(p_hal, 0);
+ pStatus->vbus_enable_power = 0;
+ p_hal->set_soft_id(p_hal, 1, 1);
+ }
+ }
+
+ pStatus->vbus_status = (unsigned char) p_hal->get_vbus_state(p_hal);
+
+ if (pStatus->vbus_status == USB_VBUS_HIGH) {
+ MONITOR_PRINTK("vbus is high!!!!!!!\n");
+ /*
+ * if B_IN is send out, needn't check device at all.
+ * \CE\D2\C3\C7ֻ\B4\A6\C0\ED\CFȲ\E5\C8\EB\B3\E4\B5\E7\C6\F7\B5\C4\C7\E9\BF\F6\CF£\AC\BC\EC\B2\E2pc\B5\C4\C1\AC\BDӺͶϿ\AA\A1\A3\C8\E7\B9\FB\CF\C8\C1\AC\BD\D3pc\A3\AC\D4\F2\B6\D4\D3ڳ\E4\B5\E7\C6\F7\B5IJ\E5\B0μ\EC\B2ⲻ\C1ˡ\A3
+ */
+ if ((pStatus->message_status & (0x1 << MONITOR_B_IN)) != 0) {
+#if 0
+ /*
+ * \B4˶δ\FA\C2뱾Ϊ\BC\EC\B2\E2Բ\BFڳ\E4\B5\E7\C6\F7\BA\CDpcͬʱ\B2\E5\C8\EB\B5\C4\C7\E9\BF\F6\CF¼\EC\B2\E2pc\B5İ\CE\CFߣ\AC\B5\ABʵ\BC\CA\C9ϴ\E6\D4\DA\CE\F3\C5ж\CFpc\B0\CE\CFߵ\C4\C7\E9\BF\F6\A3\AC
+ * \D2\F2Ϊpc\B5\C4sof\BF\C9\C4\DC\D4ڶ\E0\B4η\A2\CB\CDδ\B9\FB\BA\F3һ\B6\CEʱ\BC\E4\C4ڲ\BB\D4ٷ\A2\CB͡\A3
+ */
+ /* if pc is connected, and charger is new plug in, we ignore it. */
+ if ((pStatus->message_status &
+ (0x1 << MONITOR_CHARGER_IN)) == 0)
+#endif
+ pStatus->device_confirm = 0;
+ pStatus->timer_steps = 0;
+ ret = USB_DET_DEVICE_PC;
+ goto out2;
+ }
+ if ((pStatus->message_status & (0x1 << MONITOR_CHARGER_IN)) != 0) {
+ pStatus->device_confirm = 0;
+ pStatus->timer_steps = 0;
+ ret = USB_DET_DEVICE_CHARGER;
+ goto out2;
+ }
+
+ switch (pStatus->device_confirm) {
+ /* \BD\F8\C8\EB\B5\DA4\B2\BD\A3\AC\BC\EC\B2\B6˿\DAvbus\D3е硣\D6\C1\C9\D9deboundceһ\B4Σ\ACȷ\B1\A3\BC\EC\B2\E2\D5\FDȷ\A1\A3 */
+ case 0:
+ pStatus->timer_steps = USB_DEVICE_DETECT_STEPS; /* the last timer_steps is to confirm. */
+ pStatus->device_confirm = 1;
+ ret = USB_DET_DEVICE_DEBUOUNCING;
+ goto out2;
+
+ /* \D2Ѿ\ADȷ\C8\CFvbus\D3е磬\B2\A2enable\C9\CF\C0\AD500k\A3\ACdisable\CF\C2\C0\AD15k\A3\AC\CF\C2һ\B2\BD\BC\EC\B2\E2dp\A1\A2dm״̬\A1\A3 */
+ case 1:
+ p_hal->set_dp_500k_15k(p_hal, 1, 0); /* 500k up enable, 15k down disable; */
+ pStatus->device_confirm = 2;
+ ret = USB_DET_DEVICE_DEBUOUNCING;
+ goto out2;
+
+ /* \B5\DAһ\B4λ\F1ȡdp\A1\A2dm״̬\A3\AC\D0\E8Ҫ\D4\D9ȷ\C8\CFһ\B4Ρ\A3 */
+ case 2:
+ pStatus->dp_dm_status = p_hal->get_linestates(p_hal); // get dp dm status.
+ pStatus->device_confirm = 3;
+ //pStatus->device_confirm = 2; /* always in get dp dm states, just for test. */
+ ret = USB_DET_DEVICE_DEBUOUNCING;
+ goto out2;
+
+ /*
+ * \B5ڶ\FE\B4λ\F1ȡdp\A1\A2dm״̬\A3\AC\C8\E7\B9\FB\C1\BD\B4β\BB\B1䣬\D4\F2ȷ\C8\CFok\A3\AC\B7\F1\D4\F2\BD\F8һ\B2\BDdebounce\A1\A3
+ * dp\BA\CDdm\B7\C70״̬Ϊ\B3\E4\B5\E7\C6\F7\A3\AC\B7\B4֮\BD\F8һ\B2\BD\C5ж\CFsof\D6ж\CFλ\BF\B4\BF\B4\CAǷ\F1pc\A1\A3
+ */
+ case 3:
+ val = p_hal->get_linestates(p_hal); // get dp dm status.
+ pStatus->sof_check_times = 0;
+ if (val == pStatus->dp_dm_status) {
+ if (val == 0x00) {
+ pStatus->timer_steps = 0;
+ pStatus->device_confirm = 0;
+ ret = USB_DET_DEVICE_PC;
+
+ goto out2;
+ } else {
+ pStatus->device_confirm = 0;
+ /* if enable monitor again, it should begin from step 0. */
+ pStatus->timer_steps = 0;
+ ret = USB_DET_DEVICE_PC;
+ goto out2;
+ }
+ } else {
+ pStatus->device_confirm = 1;
+ ret = USB_DET_DEVICE_DEBUOUNCING;
+ goto out2;
+ }
+
+ /*
+ * \BD\F8\C8\EB\D5\E2һ\B2\BD\A3\AC\D0\E8Ҫ\B6\E0\B4\CE\C5ж\CFpc\CAǷ\F1\D3\D0sof\BB\F2reset\D0źŸ\F8С\BB\FA\A3\AC
+ * \B5ȴ\FDʱ\BC\E4\BF\C9\C4ܻ\E1\D3\D08\C3\EB\D2\D4\C9ϡ\A3 \D2\F2Ϊ\B4\D3С\BB\FAdp\C9\CF\C0\AD\B5\BDpc\B7\A2sof\A3\AC\D6м\E4\BF\C9\C4\DC\D1\D3ʱ\B3\A4\B4\EF8\C3\EB\D2\D4\C9ϡ\A3
+ */
+ /* for detect sof or reset irq. */
+ case 4:
+ val = p_hal->is_sof(p_hal);
+ if (val != 0) {
+ /* if enable monitor again, it should begin from step 0. */
+ pStatus->timer_steps = 0;
+ pStatus->device_confirm = 0;
+ pStatus->sof_check_times = 0;
+ p_hal->dp_down(p_hal);
+ ret = USB_DET_DEVICE_PC;
+ goto out2;
+ }
+ if (pStatus->sof_check_times < MAX_DETECT_SOF_CNT) { /* 10 * MAX_DETECT_SOF_CNT ms. */
+ pStatus->device_confirm = 4; /* next step still check again. */
+ pStatus->sof_check_times++;
+ ret = USB_DET_DEVICE_DEBUOUNCING;
+ goto out2;
+ }
+
+ /* if enable monitor again, it should begin from step 0. */
+ pStatus->timer_steps = 0;
+ pStatus->device_confirm = 0;
+ pStatus->sof_check_times = 0;
+ p_hal->dp_down(p_hal);
+ /* treated as charger in. */
+ ret = USB_DET_DEVICE_CHARGER;
+ goto out2;
+
+ default:
+ MONITOR_ERR("into device confirm default, err!\n");
+ pStatus->device_confirm = 0;
+ ret = USB_DET_NONE;
+ goto out;
+ }
+ } else {
+ pStatus->device_confirm = 0;
+ pStatus->timer_steps =USB_DEVICE_DETECT_STEPS;
+ ret = USB_DET_NONE;
+ goto out;
+ }
+
+ out:
+ pStatus->timer_steps++;
+ if (pStatus->timer_steps > USB_DEVICE_DETECT_STEPS) {
+ pStatus->timer_steps = 0;
+ }
+ out2:
+ return ret;
+}
+
+/*
+ * retval:
+ * refer to below macro:
+ * USB_DET_HOST_NONE,
+ * USB_DET_HOST_DEBOUNCING,
+ * USB_DET_HOST_UDISK,
+ */
+static int usb_timer_det_udisk(umonitor_dev_status_t * pStatus)
+{
+ unsigned int val;
+ usb_hal_monitor_t *p_hal = &pStatus->umonitor_hal;
+
+ if (pStatus->timer_steps == 1) {
+
+ p_hal->set_dp_500k_15k(p_hal, 0, 1); /* disable 500k, enable 15k. */
+
+ if (pStatus->vbus_enable_power == 0) {
+ p_hal->vbus_power_onoff(p_hal, 1);
+ pStatus->vbus_enable_power = 1;
+ p_hal->set_soft_id(p_hal, 1, 0);
+ }
+ goto out;
+ } else {
+ if (pStatus->vbus_enable_power != 1) {
+ USB_ERR_PLACE;
+ }
+
+ val = p_hal->get_linestates(p_hal); // get dp dm status.
+ MONITOR_PRINTK("host debounce!!!, linestate %04x\n", val);
+
+ pStatus->timer_steps = 0;
+ pStatus->host_confirm = 0;
+ return USB_DET_HOST_UDISK;
+
+ if ((val == 0x1) || (val == 0x2)) {
+ switch (pStatus->host_confirm) {
+ case 0:
+ pStatus->host_confirm = 1;
+ /* the last step is always debounce and confirm step. */
+ pStatus->timer_steps = USB_HOST_DETECT_STEPS;
+ pStatus->dp_dm_status = val;
+ return USB_DET_HOST_DEBOUNCING;
+
+ case 1:
+ if (val == pStatus->dp_dm_status) {
+ /* if enable monitor again, it should begin from step 0. */
+ pStatus->timer_steps = 0;
+ pStatus->host_confirm = 0;
+ return USB_DET_HOST_UDISK;
+ } else {
+ pStatus->dp_dm_status = val;
+ pStatus->host_confirm = 0;
+ return USB_DET_HOST_DEBOUNCING;
+ }
+
+ default:
+ break;
+ }
+ } else {
+ pStatus->host_confirm = 0;
+ goto out;
+ }
+ }
+
+out:
+ pStatus->timer_steps++;
+ if (pStatus->timer_steps > USB_HOST_DETECT_STEPS) {
+ pStatus->timer_steps = 0;
+ return USB_DET_HOST_NONE; /* nothing detect, maybe udisk is plug out. */
+ }
+ return USB_DET_HOST_DEBOUNCING;
+}
+
+/*
+ * \B4\A6\C0\ED\BBָ\B4\B5\BDstep 0\A3\A8\BC\B4\B5\DA0\B2\BD\A3\A9\B5\C4\C7\E9\BF\F6\A1\A3step 0\BDβ\BB\C7\F8\B7\D6device\BC\EC\B2\CA\C7host\BC\EC\B2⣬
+ * \CB\FCֻ\CAǻָ\B4\B5\BDһ\B8\F6Ĭ\C8\CF״̬\A3\ACΪ\CF\C2һ\B4\CEdevice\BB\F2host\BC\EC\B2\E2\D7\F6\B1\B8\A1\A3
+ */
+static int usb_timer_process_step0(umonitor_dev_status_t * pStatus)
+{
+ int ret = 0;
+ unsigned int status = 0;
+ usb_hal_monitor_t *p_hal = &pStatus->umonitor_hal;
+
+ MONITOR_PRINTK("entring usb_timer_process_step0\n");
+
+ if ((pStatus->message_status & (0x1 << MONITOR_B_IN)) != 0) {
+ MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status =pStatus->message_status & (~(0x1 << MONITOR_B_IN));
+ }
+
+ if ((pStatus->message_status & (0x1 << MONITOR_A_IN)) != 0) {
+ MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_A_OUT\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_A_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_A_OUT);
+ pStatus->message_status = pStatus->message_status & (~(0x1 << MONITOR_A_IN));
+ }
+
+ /*
+ * \B6\D4\D3\DA\D3\D0id pin, \BB\F2\D3\C3gpio\BC\EC\B2\E2idpin\B5\C4\C7\E9\BF\F6, \B5\B1idpinΪ0, \D4\F2\C8\C3\CB\FCһֱ\B4\A6\D3\DAhost\BC\EC\B2\E2״̬,
+ * \B2\BBҪ\C8\C3vbus\B5\F4\B5\E7. һֱvbus\B9\A9\B5\E7,\BF\C9\D2Լ\E6\C8ݲ\E5\C8\EBmp3,mp4\B5\C4\C7\E9\BF\F6. (\D2\F2Ϊ\D5\E2Щ\C9豸\D3п\C9\C4\DC\D4ڹ\A9\B5\E7
+ * \BC\B8ʮ\C3\EB\BA\F3dp\B2\C5\C9\CF\C0\AD\A1\A3
+ */
+ if (p_hal->config->detect_type == UMONITOR_DEVICE_ONLY) {
+ ret = USB_ID_STATE_DEVICE;
+ } else if (p_hal->config->detect_type == UMONITOR_HOST_ONLY) {
+ ret = USB_ID_STATE_HOST;
+ } else {
+ ret = p_hal->get_idpin_state(p_hal);
+ }
+ MONITOR_PRINTK("idpin is %d\n", ret);
+
+
+ if (ret != USB_ID_STATE_INVALID) {
+ if (ret == USB_ID_STATE_HOST) {
+host_detect:
+ MONITOR_PRINTK("host detecting!!!!\n");
+ if ((pStatus->message_status & (0x1 << MONITOR_B_IN)) != 0) {
+ MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status =pStatus->message_status & (~(0x1 << MONITOR_B_IN));
+ }
+ if ((pStatus->message_status & (0x1 << MONITOR_CHARGER_IN)) != 0) {
+ MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_CHARGER_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_CHARGER_OUT);
+ pStatus->message_status =pStatus->message_status & (~(0x1 << MONITOR_CHARGER_IN));
+ }
+
+ p_hal->set_dp_500k_15k(p_hal, 0, 1); /* disable 500k, enable 15k. */
+
+ if (pStatus->vbus_enable_power == 0) {
+ p_hal->vbus_power_onoff(p_hal, 1);
+ pStatus->vbus_enable_power = 1;
+ p_hal->set_soft_id(p_hal, 1, 0);
+ }
+ pStatus->det_phase = 1;
+ } else {
+ MONITOR_PRINTK("device detect prepare!!!!\n");
+ if ((pStatus->message_status & (0x1 << MONITOR_A_IN)) != 0) {
+ MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_A_OUT\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_A_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_A_OUT);
+ pStatus->message_status = pStatus->message_status & (~(0x1 << MONITOR_A_IN));
+ }
+ if (pStatus->vbus_enable_power) {
+ p_hal->vbus_power_onoff(p_hal, 0);
+ pStatus->vbus_enable_power = 0;
+ }
+ p_hal->set_dp_500k_15k(p_hal, 0, 0); /* disable 500k, disable 15k. */
+ p_hal->set_soft_id(p_hal, 1, 1);
+
+ pStatus->det_phase = 0;
+ }
+ pStatus->device_confirm = 0;
+ pStatus->host_confirm = 0;
+ pStatus->timer_steps = 1;
+ goto out;
+ }
+
+ /* the last time check host state before change to device detect phase. */
+ if ((pStatus->vbus_enable_power != 0) && (pStatus->det_phase != 0)) {
+ pStatus->dp_dm_status = p_hal->get_linestates(p_hal); // get dp dm status.
+ if ((pStatus->dp_dm_status == 0x1) || (pStatus->dp_dm_status == 0x2)) {
+ pStatus->timer_steps = USB_HOST_DETECT_STEPS;
+ pStatus->host_confirm = 0;
+ goto out;
+ }
+ }
+
+ p_hal->vbus_power_onoff(p_hal, 0);
+ pStatus->vbus_enable_power = 0;
+ p_hal->set_dp_500k_15k(p_hal, 0, 0); /* disable 500k, disable 15k. */
+ p_hal->set_soft_id(p_hal, 1, 1);
+
+ pStatus->check_cnt++;
+
+ /* if it's the first time to check, must in checking device phase. */
+ if ((pStatus->check_cnt == 1) ||
+ (pStatus->port_config->detect_type == UMONITOR_DEVICE_ONLY)) {
+ pStatus->det_phase = 0;
+ } else {
+ /* reverse detect phase. */
+ pStatus->det_phase = !pStatus->det_phase;
+
+ /* if it's B_IN status, it needn't to check host in, because there is just one usb port.
+ ͬʱ\A3\AC\C8\E7\B9\FBֻ\C1\AC\BD\D3usb\B3\E4\B5\E7\C6\F7\A3\AC\B4\CBʱ\D4\D9ʹ\D3\C3GPIO\B6\D4\CD\B5\E7\C0\B4\BC\EC\B2\E9host\CAǷ\F1\B2\E5\C8룬\D4\F2\BBᵼ\D6»\FA\C6\F7\B5\F4\B5硣
+ һ\D1\F9Ҳ\CA\C7\D0\E8Ҫ\B4\CBʱ\BD\FBֹ\BC\EC\B2\E2host */
+ status = pStatus->message_status & ((0x1 << MONITOR_B_IN) | (0x1 << MONITOR_CHARGER_IN));
+ if ((pStatus->det_phase == 1) && (status != 0)) {
+ pStatus->det_phase = 0;
+ goto out1;
+ }
+ pStatus->check_cnt = 0;
+ goto host_detect;
+
+ }
+out1:
+ pStatus->device_confirm = 0;
+ pStatus->host_confirm = 0;
+ pStatus->timer_steps = 1;
+
+out:
+ return 0;
+}
+
+/******************************************************************************/
+/*!
+* \brief check whether usb plug in/out
+*
+* \par Description
+* this function is a timer func, interval is 500ms.
+*
+* \param[in] null
+* \return null
+* \ingroup usbmonitor
+*
+* \par
+******************************************************************************/
+void umonitor_timer_func(void)
+{
+ int ret = 0;
+ unsigned int status = 0;
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t * p_hal;
+ u32 reg;
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ MONITOR_PRINTK("entring umonitor_timer_func\n");
+
+ if ((pStatus->port_config->detect_type == UMONITOR_DISABLE)
+ || (pStatus->detect_valid == 0)) {
+ goto out;
+ }
+ pStatus->detect_running = 1;
+
+ /* err check! */
+ if ((pStatus->timer_steps > USB_DEVICE_DETECT_STEPS)
+ && (pStatus->timer_steps > USB_HOST_DETECT_STEPS)) {
+ MONITOR_ERR("timer_steps err:%d \n", pStatus->timer_steps);
+ pStatus->timer_steps = 0;
+ goto out;
+ }
+ //usb_monitor_debug_status_inf(usb_ctrl_no);
+
+ if (pStatus->timer_steps == 0) { /* power on/off phase. */
+ usb_timer_process_step0(pStatus);
+ goto out;
+ }
+
+ if (pStatus->det_phase == 0) { /* power off, device detect phase. */
+ ret = usb_timer_det_pc_charger(pStatus);
+ switch (ret) {
+ case USB_DET_NONE:
+ if ((pStatus->message_status & (0x1 << MONITOR_B_IN)) != 0) {
+ //MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status =pStatus->message_status & (~(0x1 << MONITOR_B_IN));
+ }
+ if ((pStatus->message_status & (0x1 << MONITOR_CHARGER_IN)) != 0) {
+ printk("\n%s--%d, SYS_MSG_USB_CHARGER_OUT\n", __FILE__, __LINE__);
+ //MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_CHARGER_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_CHARGER_OUT);
+ pStatus->message_status = pStatus->message_status & (~(0x1 << MONITOR_CHARGER_IN));
+ }
+ break;
+
+ case USB_DET_DEVICE_DEBUOUNCING: /* debounce. */
+ break;
+
+ case USB_DET_DEVICE_PC:
+ if(p_hal->get_idpin_state(p_hal) != USB_ID_STATE_DEVICE){
+ pStatus->device_confirm = 0;
+ pStatus->timer_steps =0;
+ goto out;
+ }
+ status = pStatus->message_status & (0x1 << MONITOR_B_IN);
+ if (status != 0) {
+ goto out;
+ }
+ p_hal->set_mode(p_hal, USB_IN_DEVICE_MOD);
+ //need to reset dp/dm before dwc3 loading
+ reg = readl(p_hal->usbecs);
+ reg &= ~((0x1 << USB3_P0_CTL_DPPUEN_P0)|(0x1 << USB3_P0_CTL_DMPUEN_P0));
+ writel(reg, p_hal->usbecs );
+ //MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_B_IN\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_B_IN\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_IN);
+ pStatus->message_status |= 0x1 << MONITOR_B_IN;
+ pStatus->detect_valid = 0; //disable detection
+ goto out; /* todo stop timer. */
+
+ case USB_DET_DEVICE_CHARGER:
+ /* if B_IN message not clear, clear it. B_OUT when adaptor is in. */
+ status = pStatus->message_status & (0x1 << MONITOR_B_IN);
+ if (status != 0) {
+ printk("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ //MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_B_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status =pStatus->message_status & (~(0x1 << MONITOR_B_IN));
+ }
+ /* if adaptor in is send, it needn't sent again. */
+ status = pStatus->message_status & (0x1 << MONITOR_CHARGER_IN);
+ if (status != 0) {
+ goto out;
+ }
+ p_hal->set_mode(p_hal, USB_IN_DEVICE_MOD);
+ MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_CHARGER_IN\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_CHARGER_IN);
+ pStatus->message_status |= 0x1 << MONITOR_CHARGER_IN;
+ pStatus->detect_valid = 0; //disable detection
+ goto out; /* todo stop timer. */
+
+ default:
+ USB_ERR_PLACE;
+ break;
+ }
+ goto out;
+ } else { /* power on, host detect phase. */
+
+ ret = usb_timer_det_udisk(pStatus);
+ status = pStatus->message_status & (0x1 << MONITOR_A_IN);
+ if ((status != 0) && (ret == USB_DET_HOST_NONE)) {
+ //MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_A_OUT\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_A_OUT\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_A_OUT);
+ pStatus->message_status = pStatus->message_status & (~(0x1 << MONITOR_A_IN));
+ goto out;
+ }
+ if (ret == USB_DET_HOST_UDISK) {
+ p_hal->set_mode(p_hal, USB_IN_HOST_MOD);
+ //MONITOR_PRINTK("\n%s--%d, SYS_MSG_USB_A_IN\n", __FILE__, __LINE__);
+ printk("\n%s--%d, SYS_MSG_USB_A_IN\n", __FILE__, __LINE__);
+ pStatus->core_ops->putt_msg(MON_MSG_USB_A_IN);
+ pStatus->message_status |= 0x1 << MONITOR_A_IN;
+
+ /*\C8\E7\B9\FB\CA\C7A\CF߲\E5\C8룬\D4\F2\B9رն\A8ʱ\C6\F7\A3\BBB\CF߲\E5\C8룬\B6\A8ʱ\C6\F7\B2\BB\D3ùر\D5 */
+ pStatus->detect_valid = 0; //disable detection
+ goto out; /* todo stop timer. */
+ }
+ goto out;
+ }
+
+out:
+ pStatus->detect_running = 0;
+ return;
+}
+
+/******************************************************************************/
+/*!
+* \brief set monitor detect flag
+*
+* \par Description
+* set monitor detect flag
+*
+* \param[in] status
+* 1--- set detection flag to detect
+* 0--- reverse
+* \return 0------\C9\E8\D6óɹ\A6
+* \ingroup usbmonitor
+*
+* \par
+******************************************************************************/
+static int set_monitor_detect_flag(umonitor_dev_status_t *pStatus, unsigned int status)
+{
+ int i;
+ unsigned int ms_status = 0; /* record is a in ? */
+ usb_hal_monitor_t *p_hal = &pStatus->umonitor_hal;
+
+ pStatus->check_cnt = 0;
+ pStatus->det_phase = 0;
+ pStatus->timer_steps = 0;
+
+ if (status != 0) { /*enable detect flag */
+ p_hal->vbus_power_onoff(p_hal, 0);
+ pStatus->vbus_enable_power = 0;
+
+ if (pStatus->detect_valid == 0) {
+ MONITOR_PRINTK("%s,%d\n", __FUNCTION__, __LINE__);
+ pStatus->detect_valid = 1;
+ goto out;
+ } else {
+ MONITOR_PRINTK("usb detection flag is already setted, %s,%d\n", __FUNCTION__, __LINE__);
+ }
+ }
+ else { /*disable detection flag */
+ i = 0;
+ do {
+ if (pStatus->detect_running == 0) {
+ pStatus->detect_valid = 0;
+ break;
+ }
+ msleep(1);
+ ++i;
+ } while (i < 1000);
+ MONITOR_PRINTK("enable detection flag\n");
+
+ if (ms_status == 0) {
+ /* make sure power is off. */
+ p_hal->vbus_power_onoff(p_hal, 0);
+ pStatus->vbus_enable_power = 0;
+ p_hal->set_soft_id(p_hal, 1, 1);
+ }
+ }
+
+out:
+ if (pStatus->core_ops->wakeup_func != NULL) {
+ pStatus->core_ops->wakeup_func();
+ }
+ return 0;
+}
+
+/*! \cond USBMONITOR_INTERNAL_API*/
+/******************************************************************************/
+/*!
+* \brief enable or disable usb plug_in/out check
+*
+* \par Description
+* enable or disable the func of checking usb plug_in/out
+*
+*
+* \param[in] status
+* 1--- enable check func;
+* 0--- disable check func;
+* \return 0------ʹ\C4\DC/\BD\FBֹ\B3ɹ\A6
+ \B8\BAֵ---\C7\FD\B6\AF\B5\B1ǰæ\A3\AC\C7\EB\C9Ժ\F2\D6\D8\D0½\F8\D0д˲\D9\D7\F7
+* \ingroup usbmonitor
+*
+* \par
+******************************************************************************/
+int umonitor_detection(unsigned int status)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t * p_hal;
+
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+ MONITOR_PRINTK("umonitor_detection:%d\n", status);
+
+ if (status != 0) {
+ p_hal->dwc3_otg_mode_cfg(p_hal);
+ p_hal->aotg_enable(p_hal, 1);
+ p_hal->set_mode(p_hal, USB_IN_DEVICE_MOD);
+ set_monitor_detect_flag(pStatus, 1);
+ } else {
+ //\D5ⲿ\B7\D6\CF\D6\D4\DA\D2\D1\CE\DEЧ,\D3\C9\D4\DA\D2Ѿ\AD\BC\EC\B2B\BB\F2\D5\DFA\B2\E5\C8\EBʱ,\B7\A2\CB\CD\C1\CB\CF\FBϢ\BA\F3,\BD\AB\B6\A8ʱ\C6\F7port_timerֹͣ;
+ //checktimer\C8Ծ\C9\D4\CB\D0м\E0\B2\E2A(id\CAǷ\F1\B1仯)\BB\F2\D5\DFB(vbus\CAǷ\F1\B8ı\E4)\B2\E5\C8\EB\B5\C4״̬\CAǷ\F1\B7\A2\C9\FA\B8ı\E4.
+ //\B4˴\A6Ϊ\B1\A3\C1\F4ԭʼ\B4\FA\C2\EB,/*disable detection,\BC\D3\D4\D8UDC\C7\FD\B6\AFʱ\A3\AC\CFȹرն\A8ʱ\C6\F7\BC\EC\B2\E2 */
+ p_hal->aotg_enable(p_hal, 0);
+ set_monitor_detect_flag(pStatus, 0);
+ }
+ return 0;
+}
+
+/*! \cond NOT_INCLUDE*/
+/******************************************************************************/
+/*!
+* \brief parse the runtime args of monitor driver.
+* \par Description
+* \B3\F5ʼ\BB\AF\A3\AC\BF\AAʼ\B1\B8\BD\F8\D0м\EC\B2⡣
+*
+* \retval 0---args parse successed
+* \ingroup UsbMonitor
+******************************************************************************/
+int umonitor_core_init(umonitor_api_ops_t * core_ops,
+ umon_port_config_t * port_config , unsigned int base)
+{
+ umonitor_dev_status_t *pStatus;
+
+ pStatus = kmalloc(sizeof (umonitor_dev_status_t), GFP_KERNEL);
+ if (pStatus == NULL) {
+ return -1;
+ }
+ umonitor_status = pStatus;
+
+ usb_hal_init_monitor_hw_ops(&pStatus->umonitor_hal, port_config, base);
+ usb_init_monitor_status(pStatus);
+ pStatus->core_ops = core_ops;
+ pStatus->port_config = port_config;
+
+ return 0;
+}
+
+int umonitor_core_exit(void)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t *p_hal;
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ p_hal->enable_irq(p_hal, 0);
+ if (pStatus != NULL)
+ kfree(pStatus);
+
+ umonitor_status = NULL;
+ return 0;
+}
+
+unsigned int umonitor_get_run_status(void)
+{
+ umonitor_dev_status_t *pStatus;
+
+ pStatus = umonitor_status;
+
+ return (unsigned int)pStatus->detect_valid;
+}
+
+unsigned int umonitor_get_message_status(void)
+{
+ umonitor_dev_status_t *pStatus;
+
+ pStatus = umonitor_status;
+
+ return (unsigned int)pStatus->message_status;
+}
+
+void umonitor_printf_debuginfo(void)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t *p_hal;
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ usb_monitor_debug_status_inf();
+ printk("in printf_debuginfo\n");
+ p_hal->debug(p_hal);
+
+ return;
+}
+
+int umonitor_vbus_power_onoff(int value)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t *p_hal;
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ return p_hal->vbus_power_onoff(p_hal, value);
+}
+
+int umonitor_core_suspend(void)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t *p_hal;
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ pStatus->detect_valid = 0;
+
+ printk("SUSPEND pStatus->message_status is %d!!!!!!!!!!!!!!\n", pStatus->message_status);
+
+ if(pStatus->vbus_enable_power && p_hal->vbus_power_onoff)
+ p_hal->vbus_power_onoff(p_hal, 0);
+
+ p_hal->suspend_or_resume(p_hal, 1);
+
+ return 0;
+}
+
+int umonitor_core_resume(void)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t *p_hal;
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ printk(KERN_DEBUG"RESUME pStatus->message_status is %d!!!!!!!!!!!!!!\n", pStatus->message_status);
+
+ if((pStatus->message_status &(0x1 << MONITOR_B_IN)) != 0){
+ printk(KERN_DEBUG"RESUME SNED B_OUT\n");
+ pStatus->core_ops->putt_msg(MON_MSG_USB_B_OUT);
+ pStatus->message_status &= ~(0x1 << MONITOR_B_IN);
+ }
+ if((pStatus->message_status &(0x1 << MONITOR_A_IN)) != 0){
+ printk(KERN_DEBUG"RESUME SNED A_OUT\n");
+ //p_hal->vbus_power_onoff(p_hal, 1);
+ //pStatus->vbus_enable_power = 1;
+ pStatus->core_ops->putt_msg(MON_MSG_USB_A_OUT);
+ pStatus->message_status &= ~(0x1 << MONITOR_A_IN);
+ }
+ p_hal->suspend_or_resume(p_hal, 0);
+ umonitor_detection(1);
+ return 0;
+}
+
+/*\B1\A3֤\B9ػ\FA\C1\F7\B3\CC\D6вŻ\E1\B5\F7\D3\C3,\C6\E4\CB\FC\B5ط\BD\B2\BB\BB\E1\B5\F7\D3\C3*/
+int umonitor_dwc_otg_init(void)
+{
+ umonitor_dev_status_t *pStatus;
+ usb_hal_monitor_t *p_hal;
+
+ pStatus = umonitor_status;
+ p_hal = &pStatus->umonitor_hal;
+
+ p_hal->dwc3_otg_init(p_hal);
+
+ return 0;
+}
diff --git a/drivers/usb/monitor/umonitor_core.h b/drivers/usb/monitor/umonitor_core.h
new file mode 100644
index 0000000..3f7643e
--- /dev/null
+++ b/drivers/usb/monitor/umonitor_core.h
@@ -0,0 +1,130 @@
+/*! \cond USBMONITOR*/
+/*********************************************************************************
+* Module: usb monitor driver
+* (c) Copyright 2003 - 2008, Actions Co,Ld.
+* All Right Reserved
+*
+* History:
+* <author> <time> <version > <desc>
+* houjingkun 2011/07/08 1.0 build this file
+********************************************************************************/
+/*!
+ * \file umonitor_core.h
+ * \brief
+ * usb monitor detect opration headfile.
+ * \author houjingkun
+ * \par GENERAL DESCRIPTION:
+ * \par EXTERNALIZED FUNCTIONS:
+ * null
+ *
+ * Copyright(c) 2008-2012 Actions Semiconductor, All Rights Reserved.
+ *
+ * \version 1.0
+ * \date 2011/07/08
+ *******************************************************************************/
+#ifndef _UMONITOR_CORE_H_
+#define _UMONITOR_CORE_H_
+
+#include "umonitor_hal.h"
+
+#define USB_ERR_PLACE printk("err:%s,%d\n", __FILE__, __LINE__)
+
+typedef struct umonitor_api_ops {
+ /* wakeup_func -- wakeup usb monitor detect thread. */
+ void (* wakeup_func) (void);
+
+ #define MON_MSG_USB_B_IN 1
+ #define MON_MSG_USB_B_OUT 2
+ #define MON_MSG_USB_A_IN 3
+ #define MON_MSG_USB_A_OUT 4
+ #define MON_MSG_USB_CHARGER_IN 5
+ #define MON_MSG_USB_CHARGER_OUT 6
+ void (* putt_msg)(unsigned int msg);
+} umonitor_api_ops_t;
+
+
+
+typedef struct umonitor_dev_status {
+ usb_hal_monitor_t umonitor_hal;
+
+ /* detect valid or not. 1--valid, 0--invalid. */
+ volatile unsigned char detect_valid;
+ /* 1--usb monitor is detecting, 0--not in detecting state. */
+ volatile unsigned char detect_running;
+
+ volatile unsigned char vbus_status; /* detect vbus status. 1-- valid. */
+ volatile unsigned char dc5v_status; /* detect dc5v status. 1-- valid. */
+ volatile unsigned char vbus_enable_power; /* 1-- valid. */
+ volatile unsigned char det_phase; /* 0--device detecting, 1--host detecting. */
+ /*
+ * confirm device state. 0--not detect, 1--vbus on detected, enable 500k,
+ * 2--dp dm detect, 3-- dp dm debounce.
+ */
+ volatile unsigned char device_confirm;
+
+#define MAX_DETECT_SOF_CNT 50
+ volatile unsigned char sof_check_times;
+
+ /*
+ * confirm host state. 0--not detect, 1--dp,dm detected,
+ * 2--dp dm debounce.
+ */
+ volatile unsigned char host_confirm;
+ volatile unsigned char usb_pll_on; /* 1--on, 0--off. */
+ /*
+ * 0 ~ 3 bit - detect device or host. refer to DET_USB_MODE_T.
+ * 4 ~ 7 bit - vbus detect mode. refer to DET_VBUS_MODE_T.
+ * 8 ~ 11 bit - id detect mode. refer to DET_ID_MODE_T.
+ * 12 ~ 15 bit - dc5v detect mode. refer to DET_DC5V_MODE_T.
+ */
+ volatile unsigned int detect_mode;
+ volatile unsigned char reserv[2];
+ volatile unsigned int dp_dm_status; /* 00 or 11, connet to pc or charger; 01 or 10, connet with udisk. */
+ /*
+ * detect steps. device steps: USB_DEVICE_DETECT_STEPS
+ * host steps: USB_HOST_DETECT_STEPS
+ */
+ volatile int timer_steps;
+ volatile unsigned int timer_interval; /* msecond. */
+ volatile int check_cnt; /* total detect count. */
+
+ /* message status that indicate what message has been send. */
+#define MONITOR_B_IN 0
+#define MONITOR_CHARGER_IN 1
+#define MONITOR_A_IN 2
+ volatile unsigned int message_status;
+ //volatile unsigned int fix_bug_record;
+
+ umonitor_api_ops_t *core_ops;
+ umon_port_config_t *port_config;
+} umonitor_dev_status_t;
+
+int umonitor_core_init(umonitor_api_ops_t *core_ops, umon_port_config_t *port_config, unsigned int base);
+
+int umonitor_core_exit(void);
+
+/* status: 1--enable detecting, 0--disable detecting. */
+int umonitor_detection(unsigned int status);
+
+/* this function is a timer func. */
+void umonitor_timer_func(void);
+
+/* \BB\F1ȡ\D4\CB\D0е\BD\CF\C2һ\B4μ\EC\B2\E2\B5\C4ʱ\BC\E4\BC\E4\B8\F4\A3\AC\B7\B5\BB\D8ֵ\D2Ժ\C1\C3\EBΪ\B5\A5λ\A1\A3 */
+unsigned int umonitor_get_timer_step_interval(void);
+
+unsigned int umonitor_get_run_status(void);
+
+unsigned int umonitor_get_message_status(void);
+
+void umonitor_printf_debuginfo(void);
+
+int umonitor_vbus_power_onoff(int value);
+
+int umonitor_core_suspend(void);
+
+int umonitor_core_resume(void);
+
+int umonitor_dwc_otg_init(void);
+#endif /* _UMONITOR_CORE_H_ */
+/*! \endcond*/
+
diff --git a/drivers/usb/monitor/umonitor_hal.c b/drivers/usb/monitor/umonitor_hal.c
new file mode 100644
index 0000000..9f9aa3d
--- /dev/null
+++ b/drivers/usb/monitor/umonitor_hal.c
@@ -0,0 +1,534 @@
+/*********************************************************************************
+* Module: usb monitor driver
+* (c) Copyright 2003 - 2008, Actions Co,Ld.
+* All Right Reserved
+*
+* History:
+* <author> <time> <version > <desc>
+* houjingkun 2011/07/08 1.0 build this file
+********************************************************************************/
+
+/*!
+ * \file umonitor_hal.c
+ * \brief
+ * usb monitor hardware opration api code.
+ * \author houjingkun
+ * \par GENERAL DESCRIPTION:
+ * \par EXTERNALIZED FUNCTIONS:
+ * null
+ *
+ * Copyright(c) 2008-2012 Actions Semiconductor, All Rights Reserved.
+ *
+ * \version 1.0
+ * \date 2011/07/08
+ *******************************************************************************/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/atc260x/atc260x.h>
+#include <mach/hardware.h>
+
+#include "aotg_regs.h"
+#include "umonitor_hal.h"
+
+#define USB_PLUGED_PC 1
+#define USB_PLUGED_ADP 2
+
+
+static void dwc3_controllor_exit(usb_hal_monitor_t * pdev);
+void __dwc3_controllor_mode_cfg(usb_hal_monitor_t *pdev);
+
+extern int atc260x_enable_vbusotg(int on);
+
+
+void mon_dwc3_set_mode(usb_hal_monitor_t * pdev, int mode)
+{
+ u32 reg;
+
+ reg = readl(pdev->io_base + DWC3_GCTL);
+ reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+ reg |= DWC3_GCTL_PRTCAPDIR(mode);
+ writel(reg, pdev->io_base + DWC3_GCTL);
+}
+
+
+static int usb_monitor_vbus_power(usb_hal_monitor_t * pdev, int is_on)
+{
+ MONITOR_PRINTK("usb_monitor_vbus_power %04x\n", is_on);
+ if(is_on){
+ atc260x_enable_vbusotg(is_on);
+ if(pdev->config->power_switch_gpio_no !=0xffff)
+ gpio_set_value_cansleep(pdev->config->power_switch_gpio_no, pdev->config->power_switch_active_level);
+ }else{
+ if(pdev->config->power_switch_gpio_no !=0xffff)
+ gpio_set_value_cansleep(pdev->config->power_switch_gpio_no, !pdev->config->power_switch_active_level);
+ atc260x_enable_vbusotg(is_on);
+ }
+
+ return 0;
+}
+
+static int usb_get_dc5v_state(usb_hal_monitor_t * pdev)
+{
+ /* no use. */
+ return USB_DC5V_INVALID;
+}
+
+static int get_usb_plug_type(struct usb_hal_monitor *pdev)
+{
+ int ret = 0;
+ int reg_bk;
+ int reg;
+
+ reg_bk = readl(pdev->usbecs);
+ if ((reg_bk & (1 << 11))) {
+ reg = reg_bk;
+ writel(reg | 0x0000f000, pdev->usbecs); /* dp up enable, dp down disable */
+ udelay(200);
+ reg = readl(pdev->usbecs);
+ if((reg & 0x00000018) != 0) { /* bit 3, bit 4 not 0, this is usb_adapter */
+ //printf("----- current connect is USB_ADPT! \n");
+ ret = USB_PLUGED_ADP;
+ } else {
+ //printf("----- current connect is USB_PC! \n");
+ ret = USB_PLUGED_PC;
+ }
+ writel(reg_bk, pdev->usbecs); /*restore the USB3_P0_CTL */
+ }
+
+ return ret;
+}
+
+static int usb_get_vbus_state(usb_hal_monitor_t * pdev)
+{
+ int ret = USB_VBUS_INVALID;
+ s32 adc_val;
+
+ switch (pdev->config->vbus_type) {
+ case UMONITOR_USB_VBUS:
+ /* vbus valid. */
+ ret = readl(pdev->usbecs) & (1 << USB3_P0_CTL_VBUS_P0);
+ ret = ret ? USB_VBUS_HIGH: USB_VBUS_LOW;
+ break;
+ case UMONITOR_GPIO_VBUS:
+ break;
+ case UMONITOR_DC5V_VBUS:
+ ret = atc260x_ex_auxadc_read_by_name("VBUSV", &adc_val);
+ if(ret < 0)
+ break;
+ ret = (adc_val > VBUS_THRESHOLD) ? USB_VBUS_HIGH: USB_VBUS_LOW;
+ break;
+ default:
+ break;
+ }
+ /*for debug only:let user can detect host/device as wish*/
+ if((pdev->config->vbus_debug ==0)||(pdev->config->vbus_debug ==1))
+ return pdev->config->vbus_debug;
+ /* printk vbus state for debug*/
+ if(pdev->config->vbus_debug == 2)
+ printk("\n usb_get_vbus_state: %d \n",ret);
+
+ MONITOR_PRINTK("%s state: %u\n", __func__, ret);
+ return ret;
+}
+
+static int usb_hardware_init(usb_hal_monitor_t * pdev);
+static int usb_get_idpin_state(usb_hal_monitor_t * pdev)
+{
+ int value,ret = USB_ID_STATE_INVALID;
+
+ value = readl(pdev->usbpll) & 0x1f;
+ if(value == 0){
+ //need to open usbpll before read idpin status
+ __dwc3_controllor_mode_cfg(pdev);
+ }
+
+ switch (pdev->config->idpin_type) {
+ case UMONITOR_USB_IDPIN:
+ ret = (readl(pdev->usbecs) &
+ (1 << USB3_P0_CTL_ID_P0)) ? USB_ID_STATE_DEVICE:USB_ID_STATE_HOST;
+ break;
+ case UMONITOR_SOFT_IDPIN:
+ break;
+ case UMONITOR_GPIO_IDPIN:
+ if(0==gpio_get_value_cansleep(pdev->config->idpin_gpio_no))
+ ret=USB_ID_STATE_HOST;
+ else
+ ret = USB_ID_STATE_DEVICE;
+ break;
+ default:
+ break;
+ }
+ if(value == 0){
+ //need to close usbpll after read idpin status
+ dwc3_controllor_exit( pdev);
+ }
+ /*for debug only:let user can detect host/device as wish*/
+ if((pdev->config->idpin_debug ==0)||(pdev->config->idpin_debug ==1))
+ return (pdev->config->idpin_debug?USB_ID_STATE_DEVICE: USB_ID_STATE_HOST);
+ /* printk idpin state for debug*/
+ if(pdev->config->idpin_debug ==2)
+ printk("\n usb_get_idpin_state: %s \n",(ret==1)?"device":"host");
+ return ret;
+}
+
+static unsigned int usb_get_linestates(usb_hal_monitor_t * pdev)
+{
+ unsigned int ls;
+
+ ls = ((readl(pdev->usbecs) & USB3_P0_CTL_LS_P0_MASK) >> USB3_P0_CTL_LS_P0_SHIFT);
+ return ls;
+}
+
+static int usb_set_dp_500k_15k(usb_hal_monitor_t * pdev, int enable_500k_up,
+ int enable_15k_down)
+{
+ unsigned int val;
+
+ val = readl(pdev->usbecs) & (~((1 << USB3_P0_CTL_DPPUEN_P0) |
+ (1 << USB3_P0_CTL_DMPUEN_P0) |
+ (1 << USB3_P0_CTL_DPPDDIS_P0) |
+ (1 << USB3_P0_CTL_DMPDDIS_P0)));
+
+ if (enable_500k_up != 0) {
+ val |= (1 << USB3_P0_CTL_DPPUEN_P0)|(1 << USB3_P0_CTL_DMPUEN_P0);
+ }
+ if (enable_15k_down == 0) {
+ val |= (1 << USB3_P0_CTL_DPPDDIS_P0)|(1 << USB3_P0_CTL_DMPDDIS_P0);
+ }
+
+ MONITOR_PRINTK("dpdm is %08x\n", val);
+ writel(val, pdev->usbecs); /* 500k up enable, 15k down disable; */
+ return 0;
+
+}
+
+static int usb_set_soft_id(usb_hal_monitor_t * pdev, int en_softid,
+ int id_state)
+{
+#if 0 //no soft idpin in ATM7059
+ unsigned int val;
+
+ if (pdev->config->idpin_type == UMONITOR_USB_IDPIN) {
+ /* ignore soft idpin setting. */
+ en_softid = 0;
+ }
+ val = readl(pdev->usbecs);
+ if (en_softid != 0) {
+ val |= 0x1 << USB3_P0_CTL_SOFTIDEN_P0; /* soft id enable. */
+ } else {
+ val &= ~(0x1 << USB3_P0_CTL_SOFTIDEN_P0); /* soft id disable. */
+ }
+
+ if (id_state != 0) {
+ val |= (0x1 << USB3_P0_CTL_SOFTID_P0);
+ } else {
+ val &= ~(0x1 << USB3_P0_CTL_SOFTID_P0);
+ }
+ writel(val, pdev->usbecs);
+#endif
+ return 0;
+}
+
+static int usb_set_soft_vbus(usb_hal_monitor_t * pdev, int en_softvbus, int vbus_state)
+{
+ unsigned int val;
+
+ if (pdev->config->vbus_type == UMONITOR_USB_VBUS) {
+ /* ignore soft vbus setting. */
+ en_softvbus = 0;
+ }
+
+ val = readl(pdev->usbecs);
+ if (en_softvbus != 0) {
+ val |= 0x1 << USB3_P0_CTL_SOFTVBUSEN_P0; /* soft id enable. */
+ } else {
+ val &= ~(0x1 << USB3_P0_CTL_SOFTVBUSEN_P0); /* soft id disable. */
+ }
+
+ if (vbus_state != 0) {
+ val |= (0x1 << USB3_P0_CTL_SOFTVBUS_P0);
+ }else {
+ val &= ~(0x1 << USB3_P0_CTL_SOFTVBUS_P0);
+ }
+ writel(val, pdev->usbecs);
+
+ return 0;
+}
+
+static void usb_hal_set_cmu_usbpll(usb_hal_monitor_t *pdev, int enable)
+{
+ if (enable != 0) {
+ writel(readl(pdev->usbpll) | (0x1f), pdev->usbpll);
+ } else {
+ writel(readl(pdev->usbpll) & ~(0x1f),pdev->usbpll);
+ }
+ mdelay(2);
+}
+
+/******************************************************************************/
+/*!
+ * \par Description:
+ * \B6\D4usbģ\BF\E9\BD\F8\D0г\F5ʼ\BB\AF\A3\A8\B0\FC\C0\A8\BF\AA\C6\F4ʱ\D6ӣ\AC\B8\B4λ\D5\FB\B8\F6usbӲ\BC\FEģ\BF飬\B2\A2ȷ\B1\A3\B8\B4λ\D4ڷ\B5\BB\D8ǰ\CD\EA\B3\C9
+ * \param[in] void
+ * \param[in] void
+ * \return int
+ * \retval 0\A3\BAusbģ\BF\E9\B3\F5ʼ\BB\AF\CD\EA\B3\C9 \B8\BAֵ\A3\BAusbģ\BF\E9\B3\F5ʼ\BB\AFʧ\B0\DC
+ * \ingroup hal_usb
+ * \par
+ * \note
+ *
+ *******************************************************************************/
+static int usb_hardware_init(usb_hal_monitor_t * pdev)
+{
+ //writel((readl(pdev->usbecs) | 0x0000f000), pdev->usbecs);
+ //set VBUS detection threshold,VBUS_DET_THRESHOLD_LEVEL3
+ writel((readl(pdev->usbecs) | VBUS_DET_THRESHOLD_LEVEL3), pdev->usbecs);
+
+ MONITOR_PRINTK("usbecs value is %08x------>/n", readl(pdev->usbecs));
+
+ return 0;
+}
+
+/******************************************************************************/
+/*!
+* \par Description:
+* enable or disable the usb controller
+* \param[in] aotg contains the controller info
+* \param[in] enable enable(1) or disable(0) the controller
+* \return the result
+* \retval 0 sucess
+* \retval 1 failed
+* \ingroup USB_UOC
+*******************************************************************************/
+static int usb_hal_aotg_enable(usb_hal_monitor_t * pdev, int enable)
+{
+ if (enable != 0) {
+ MONITOR_PRINTK("aotg mon enable\n");
+ if (usb_hardware_init(pdev) != 0) {
+ return -1;
+ }
+ } else {
+ MONITOR_PRINTK("aotg mon disable\n");
+ }
+ return 0;
+}
+
+static int usb_hal_set_mode(usb_hal_monitor_t * pdev, int mode)
+{
+ if (mode == USB_IN_DEVICE_MOD) {
+ //writel(readl(pdev->usbecs) | (0xf << 12), pdev->usbecs);
+ }
+ if (mode == USB_IN_HOST_MOD) {
+ writel(readl(pdev->usbecs) & ((~0xf) << 12), pdev->usbecs);
+ }
+ return 0;
+}
+
+static void usb_hal_dp_up(usb_hal_monitor_t * pdev)
+{
+ return;
+}
+
+static void usb_hal_dp_down(usb_hal_monitor_t * pdev)
+{
+ return;
+}
+
+static int usb_hal_is_sof(usb_hal_monitor_t * pdev)
+{
+ return 0;
+}
+
+static int usb_hal_enable_irq(struct usb_hal_monitor *pdev, int enable)
+{
+ return 0;
+}
+
+static void usb_hal_debug(usb_hal_monitor_t * pdev)
+{
+ printk("%s:%d\n", __FILE__, __LINE__);
+ printk("pdev->usbecs addr: 0x%x\n\n", (unsigned int)pdev->usbecs);
+ return;
+}
+
+int usb_suspend_or_resume(usb_hal_monitor_t *pdev, int is_suspend)
+{
+ /* save/reload usbecs when suspend/resume */
+ if (is_suspend) {
+ pdev->usbecs_val = readl(pdev->usbecs);
+ }else{
+ usb_hardware_init(pdev);
+ //writel(pdev->usbecs_val, pdev->usbecs);
+ }
+ return 0;
+}
+
+static void dwc3_controllor_init(usb_hal_monitor_t * pdev)
+{
+
+ u32 reg;
+ int ic_type =pdev->ic_type;
+
+ /*USB3 PLL enable*/
+ reg = readl(pdev->usbpll);
+ if(ic_type == IC_ATM7059A){
+ reg |= (0x7f);
+ }
+ else if(ic_type == IC_ATM7039C){
+ reg |= (0x1f);
+ }
+ writel(reg, pdev->usbpll);
+
+ udelay(1000);
+
+ /*USB3 Cmu Reset */
+ reg = readl(pdev->devrst);
+ reg &= ~(USB3_MOD_RST);
+ writel(reg, pdev->devrst);
+
+ udelay(500);
+
+ reg = readl(pdev->devrst);
+ reg |= (USB3_MOD_RST);
+ writel(reg, pdev->devrst);
+
+ udelay(500);
+
+ if(ic_type == IC_ATM7059A){
+
+ writel(0x6046, pdev->io_base+ANA02 );
+ writel(0x2010,pdev->io_base+ANA0E );
+ writel(0x8000,pdev->io_base+ANA0F );
+ writel(0x0, pdev->io_base+ REV1 );
+ writel(0x0013,pdev->io_base+PAGE1_REG02 );
+ writel(0x0004,pdev->io_base+PAGE1_REG06 );
+ writel(0x22ed,pdev->io_base+PAGE1_REG07 );
+ writel(0xf802, pdev->io_base+PAGE1_REG08 );
+ writel(0x3080,pdev->io_base+PAGE1_REG09 );
+ writel(0x2030, pdev->io_base+PAGE1_REG0B );
+ writel((1<<14), pdev->io_base+ANA0F );
+ //enable bias
+ reg = readl(pdev->io_base + DWC3_CMU_DEBUG_LDO);
+ reg |= CMU_BIAS_EN;
+ writel(reg, pdev->io_base+ DWC3_CMU_DEBUG_LDO);
+ /*USB2 LDO enable*/
+ reg = readl(pdev->usbecs );
+ reg |= (1 << USB3_P0_CTL_PLLLDOEN_IC1 )|(/*2*/3 << USB3_P0_CTL_LDOVREFSEL_SHIFT_IC1);
+ writel(reg, pdev->usbecs );
+
+
+ }
+ else if(ic_type == IC_ATM7039C){
+ /*PLL1 enable*/
+ reg = readl(pdev->io_base + DWC3_CMU_DEBUG_LDO);
+ reg |= CMU_BIAS_EN;
+ writel(reg, pdev->io_base+ DWC3_CMU_DEBUG_LDO);
+
+ /*PLL2 enable*/
+ reg = (BIST_QINIT(0x3) | EYE_HEIGHT(0x4) | PLL2_LOCK | PLL2_RS(0x2) |
+ PLL2_ICP(0x1) | CMU_SEL_PREDIV | CMU_DIVX2 | PLL2_DIV(0x17) |
+ PLL2_POSTDIV(0x3) | PLL2_PU);
+ writel(reg, pdev->io_base + DWC3_CMU_PLL2_BISTDEBUG);
+ /*USB2 LDO enable*/
+ reg = readl(pdev->usbecs );
+ reg |= (1 << USB3_P0_CTL_PLLLDOEN )|(/*2*/3 << USB3_P0_CTL_LDOVREFSEL_SHIFT);
+ writel(reg, pdev->usbecs );
+ }
+
+
+
+ udelay(1000);
+
+}
+
+static void dwc3_controllor_exit(usb_hal_monitor_t * pdev)
+{
+ u32 reg;
+
+ int ic_type =pdev->ic_type;
+
+ /*USB3 PLL disable*/
+ reg = readl(pdev->usbpll);
+
+ if(ic_type == IC_ATM7059A){
+ reg &= ~(0x7f);
+ }
+ else if(ic_type == IC_ATM7039C){
+ reg &= ~(0x1f);
+ }
+ writel(reg, pdev->usbpll);
+}
+
+/*dwc3_controllor_otg_cfg\BA\AF\CA\FD\B5\F7\D3\C3\D3\D0\D2\D4\CF\C23\D6\D6\C7\E9\BF\F6;\D6\F7ҪĿ\B5\C4\CA\C7Ϊ\C1\CB\C9\E8\D6\C3\D6\F7\BF\D8\C6\F7\B4\A6\D3\DAotgģʽ;
+\D2Է\C0ֹid pin\B5\C4״̬\D4\DA\C6\E4\CB\FCģʽ\CF¼\EC\B2ⲻ.\B5\F7\D3õ\C4\C7\E9\BF\F6\C8\E7\CF\C2,resume\BA\AF\CA\FD,\BC\EC\B2usb\B0γ\F6,\BC\EC\B2\E2
+\B5\BDu\C5̰γ\F6.*/
+/*dwc3_controllor_exit\BA\AF\CA\FD\BBὫusbpll\B9ص\F4,Ŀǰ\B7\A2\CF\D6\D3з\E7\CF\D5,\B2\BB\C4\DC\D4\DA\D5\E2\C0\EF\B5\F7\D3\C3.\D2\F2\B0\CE\CF\DF\C7\E9\BF\F6\CF\C2,
+dwc3(usb)\C7\FD\B6\AF\BF\C9\C4ܻ\B9δж\D4\D8,\B6\F8\C8\D4Ȼ\BF\C9\C4ܷ\C3\CE\CAusb\D6\F7\BF\D8\D6\C6\C6\F7,\B6\F8\D5\E2ʱ\D2Ѿ\AD\B9ص\F4\C1\CBpll,\BBᵼ\D6\C2\CE\CA\CC\E2.*/
+void __dwc3_controllor_mode_cfg(usb_hal_monitor_t *pdev)
+{
+// u32 value;
+ /*\B2\BBΪ0,\B1\EDʾusb3֮ǰ\B5\C4Ƶ\C2ʴ\F2\BF\AA,\C7\FD\B6\AF\B4\E6\D4\DA;\B9\CA\D5\E2\B1߲\BB\D0\E8Ҫ\B4\F2\BF\AAƵ\C2\CA;\CD˳\F6ʱ\D2\D0\E8Ҫ\B9ر\D5Ƶ\C2\CA*/
+
+ dwc3_controllor_init(pdev);
+ mon_dwc3_set_mode(pdev, DWC3_GCTL_PRTCAP_OTG);
+
+#if 0
+ if(value == 0)
+ dwc3_controllor_exit(pdev);
+#endif
+
+}
+void dwc3_controllor_mode_cfg(usb_hal_monitor_t *pdev)
+{
+ return ;
+}
+int usb_hal_init_monitor_hw_ops(usb_hal_monitor_t * pdev,
+ umon_port_config_t * config, unsigned int base)
+{
+ int ret = 0;
+
+ pdev->name = "usb controller";
+ pdev->io_base =(void __iomem *) base;
+ pdev->usbecs = (void __iomem *)IO_ADDRESS(USB3_P0_CTL);
+ pdev->usbpll = (void __iomem *)IO_ADDRESS(CMU_USBPLL);
+ pdev->devrst =(void __iomem *)IO_ADDRESS( CMU_DEVRST1);
+
+ pdev->vbus_power_onoff = usb_monitor_vbus_power;
+ pdev->get_dc5v_state = usb_get_dc5v_state;
+ pdev->get_vbus_state = usb_get_vbus_state;
+ pdev->get_linestates = usb_get_linestates;
+ pdev->get_idpin_state = usb_get_idpin_state;
+ pdev->set_dp_500k_15k = usb_set_dp_500k_15k;
+ pdev->set_soft_id = usb_set_soft_id;
+ pdev->set_soft_vbus = usb_set_soft_vbus;
+ pdev->aotg_enable = usb_hal_aotg_enable;
+ pdev->set_mode = usb_hal_set_mode;
+ pdev->set_cmu_usbpll = usb_hal_set_cmu_usbpll;
+ pdev->dp_up = usb_hal_dp_up;
+ pdev->dp_down = usb_hal_dp_down;
+ pdev->is_sof = usb_hal_is_sof;
+ pdev->enable_irq = usb_hal_enable_irq;
+ pdev->debug = usb_hal_debug;
+ pdev->monitor_get_usb_plug_type = get_usb_plug_type;
+ pdev->suspend_or_resume = usb_suspend_or_resume;
+ pdev->dwc3_otg_mode_cfg = dwc3_controllor_mode_cfg;
+ pdev->dwc3_otg_exit = dwc3_controllor_exit;
+ pdev->dwc3_otg_init = dwc3_controllor_init;
+
+
+ pdev->config = config;
+ return ret;
+}
+
+
diff --git a/drivers/usb/monitor/umonitor_hal.h b/drivers/usb/monitor/umonitor_hal.h
new file mode 100644
index 0000000..8610878
--- /dev/null
+++ b/drivers/usb/monitor/umonitor_hal.h
@@ -0,0 +1,108 @@
+/*! \cond USBMONITOR*/
+/*********************************************************************************
+* Module: usb monitor driver
+* (c) Copyright 2003 - 2008, Actions Co,Ld.
+* All Right Reserved
+*
+* History:
+* <author> <time> <version > <desc>
+* houjingkun 2011/07/08 1.0 build this file
+********************************************************************************/
+/*!
+ * \file umonitor_hal.h
+ * \brief
+ * usb monitor hardware opration api.
+ * \author houjingkun
+ * \par GENERAL DESCRIPTION:
+ * \par EXTERNALIZED FUNCTIONS:
+ * null
+ *
+ * Copyright(c) 2008-2012 Actions Semiconductor, All Rights Reserved.
+ *
+ * \version 1.0
+ * \date 2011/07/08
+ *******************************************************************************/
+#ifndef _UMONITOR_HAL_H_
+#define _UMONITOR_HAL_H_
+
+#include "umonitor_config.h"
+
+//VBUS detection threshold control. reg USB3_P0_CTL [1:0]
+#define VBUS_DET_THRESHOLD_LEVEL0 0x00 //4.22v
+#define VBUS_DET_THRESHOLD_LEVEL1 0x01 //4.00v
+#define VBUS_DET_THRESHOLD_LEVEL2 0x02 //3.65v
+#define VBUS_DET_THRESHOLD_LEVEL3 0x03 //3.11v
+
+typedef struct usb_hal_monitor {
+ char * name;
+ unsigned int usbecs_val;
+ void __iomem * io_base;
+ void __iomem * usbecs;
+ void __iomem * usbpll;
+ unsigned int usbpll_bits;
+ void __iomem * devrst;
+ unsigned int devrst_bits;
+ unsigned int devclk;
+ unsigned int devclk_bits;
+
+ umon_port_config_t * config;
+
+ int ic_type;
+ int (* vbus_power_onoff)(struct usb_hal_monitor *pdev, int is_on);
+
+ #define USB_DC5V_LOW 0
+ #define USB_DC5V_HIGH 1
+ #define USB_DC5V_INVALID 2
+ int (* get_dc5v_state)(struct usb_hal_monitor *pdev);
+
+ #define USB_VBUS_LOW 0
+ #define USB_VBUS_HIGH 1
+ #define USB_VBUS_INVALID 2
+ int (* get_vbus_state)(struct usb_hal_monitor *pdev);
+
+ /* return state of linestate[1:0]. */
+ unsigned int (* get_linestates)(struct usb_hal_monitor *pdev);
+
+ /*
+ * \BC\EC\B2\E2id pin\B5\C4״̬,\D6\F7Ҫ\BF\BC\C2\C7\D3\C3gpioȥ\D7\F7idpin\BC\EC\B2\E2\B5\C4\C7\E9\BF\F6,
+ * \C6\E4\CB\FB\C7\E9\BF\F6\B5\F7\D3ô˺\AF\CA\FDʱ\B7\B5\BB\D8Ϊ0 (\B1\EDʾ\BC\EC\B2\E2\CE\DEЧ).
+ * retval:
+ * USB_ID_STATE_INVALID -- \BC\EC\B2\E2\CE\DEЧ,\B4\CBʱ\B2\BB\D3ü\EC\B2\E2idpin\B5\C4״̬;
+ * USB_ID_STATE_DEVICE -- \BC\EC\B2idpinΪ\B8\DF,\BD\F8\C8\EBdevice\BC\EC\B2\E2\BD\CE;
+ * USB_ID_STATE_HOST -- \BC\EC\B2idpinΪ\B5\CD,\BD\F8\C8\EBhost\BC\EC\B2\E2\BD\CE;
+ */
+ #define USB_ID_STATE_INVALID 0
+ #define USB_ID_STATE_DEVICE 1
+ #define USB_ID_STATE_HOST 2
+ int (* get_idpin_state)(struct usb_hal_monitor *pdev);
+
+ int (* set_dp_500k_15k)(struct usb_hal_monitor *pdev, int enable_500k_up, int enable_15k_down);
+ int (* set_soft_id)(struct usb_hal_monitor *pdev, int en_softid, int id_state);
+ int (* set_soft_vbus)(struct usb_hal_monitor *pdev, int en_softvbus, int vbus_state);
+
+ int (* aotg_enable)(struct usb_hal_monitor *pdev, int enable);
+
+ /* used for enter certain otg states. */
+ #define USB_IN_DEVICE_MOD 1
+ #define USB_IN_HOST_MOD 0
+ int (* set_mode)(struct usb_hal_monitor *pdev, int mode);
+ void (* dwc_set_mode)(struct usb_hal_monitor *pdev, int mode);
+ void (* set_cmu_usbpll)(struct usb_hal_monitor *pdev, int enable);
+ void (* dp_up)(struct usb_hal_monitor *pdev);
+ void (* dp_down)(struct usb_hal_monitor *pdev);
+ int (* is_sof)(struct usb_hal_monitor *pdev);
+ int (* enable_irq)(struct usb_hal_monitor *pdev, int enable);
+ int (* suspend_or_resume)(struct usb_hal_monitor *pdev, int is_suspend);
+ void (* dwc3_otg_mode_cfg)(struct usb_hal_monitor *pdev);
+ int (* monitor_get_usb_plug_type)(struct usb_hal_monitor *pdev);
+ void (* dwc3_otg_init)(struct usb_hal_monitor *pdev);
+ void (* dwc3_otg_exit)(struct usb_hal_monitor *pdev);
+ void (* debug)(struct usb_hal_monitor *pdev);
+} usb_hal_monitor_t;
+
+int usb_hal_init_monitor_hw_ops(usb_hal_monitor_t * pdev, umon_port_config_t * config, unsigned int base);
+
+/* todo */
+
+#endif /* _UMONITOR_HAL_H_ */
+/*! \endcond*/
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
old mode 100644
new mode 100755
index a599e8a..8f00195
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -82,9 +82,85 @@ static void option_instat_callback(struct urb *urb);
#define HUAWEI_VENDOR_ID 0x12D1
#define HUAWEI_PRODUCT_E173 0x140C
#define HUAWEI_PRODUCT_E1750 0x1406
+#define HUAWEI_PRODUCT_E600 0x1001
+#define HUAWEI_PRODUCT_E220 0x1003
+#define HUAWEI_PRODUCT_E220BIS 0x1004
+#define HUAWEI_PRODUCT_E1401 0x1401
+#define HUAWEI_PRODUCT_E1402 0x1402
+#define HUAWEI_PRODUCT_E1403 0x1403
+#define HUAWEI_PRODUCT_E1404 0x1404
+#define HUAWEI_PRODUCT_E1405 0x1405
+#define HUAWEI_PRODUCT_E1406 0x1406
+#define HUAWEI_PRODUCT_E1407 0x1407
+#define HUAWEI_PRODUCT_E1408 0x1408
+#define HUAWEI_PRODUCT_E1409 0x1409
+#define HUAWEI_PRODUCT_E140A 0x140A
+#define HUAWEI_PRODUCT_E140B 0x140B
+#define HUAWEI_PRODUCT_E140C 0x140C
+#define HUAWEI_PRODUCT_E140D 0x140D
+#define HUAWEI_PRODUCT_E140E 0x140E
+#define HUAWEI_PRODUCT_E140F 0x140F
+#define HUAWEI_PRODUCT_E1410 0x1410
+#define HUAWEI_PRODUCT_E1411 0x1411
+#define HUAWEI_PRODUCT_E1412 0x1412
+#define HUAWEI_PRODUCT_E1413 0x1413
+#define HUAWEI_PRODUCT_E1414 0x1414
+#define HUAWEI_PRODUCT_E1415 0x1415
+#define HUAWEI_PRODUCT_E1416 0x1416
+#define HUAWEI_PRODUCT_E1417 0x1417
+#define HUAWEI_PRODUCT_E1418 0x1418
+#define HUAWEI_PRODUCT_E1419 0x1419
+#define HUAWEI_PRODUCT_E141A 0x141A
+#define HUAWEI_PRODUCT_E141B 0x141B
+#define HUAWEI_PRODUCT_E141C 0x141C
+#define HUAWEI_PRODUCT_E141D 0x141D
+#define HUAWEI_PRODUCT_E141E 0x141E
+#define HUAWEI_PRODUCT_E141F 0x141F
+#define HUAWEI_PRODUCT_E1420 0x1420
+#define HUAWEI_PRODUCT_E1421 0x1421
+#define HUAWEI_PRODUCT_E1422 0x1422
+#define HUAWEI_PRODUCT_E1423 0x1423
+#define HUAWEI_PRODUCT_E1424 0x1424
+#define HUAWEI_PRODUCT_E1425 0x1425
+#define HUAWEI_PRODUCT_E1426 0x1426
+#define HUAWEI_PRODUCT_E1427 0x1427
+#define HUAWEI_PRODUCT_E1428 0x1428
+#define HUAWEI_PRODUCT_E1429 0x1429
+#define HUAWEI_PRODUCT_E142A 0x142A
+#define HUAWEI_PRODUCT_E142B 0x142B
+#define HUAWEI_PRODUCT_E142C 0x142C
+#define HUAWEI_PRODUCT_E142D 0x142D
+#define HUAWEI_PRODUCT_E142E 0x142E
+#define HUAWEI_PRODUCT_E142F 0x142F
+#define HUAWEI_PRODUCT_E1430 0x1430
+#define HUAWEI_PRODUCT_E1431 0x1431
+#define HUAWEI_PRODUCT_E1432 0x1432
+#define HUAWEI_PRODUCT_E1433 0x1433
+#define HUAWEI_PRODUCT_E1434 0x1434
+#define HUAWEI_PRODUCT_E1435 0x1435
+#define HUAWEI_PRODUCT_E1436 0x1436
+#define HUAWEI_PRODUCT_E1437 0x1437
+#define HUAWEI_PRODUCT_E1438 0x1438
+#define HUAWEI_PRODUCT_E1439 0x1439
+#define HUAWEI_PRODUCT_E143A 0x143A
+#define HUAWEI_PRODUCT_E143B 0x143B
+#define HUAWEI_PRODUCT_E143C 0x143C
+#define HUAWEI_PRODUCT_E143D 0x143D
+#define HUAWEI_PRODUCT_E143E 0x143E
+#define HUAWEI_PRODUCT_E143F 0x143F
#define HUAWEI_PRODUCT_K4505 0x1464
#define HUAWEI_PRODUCT_K3765 0x1465
+#define HUAWEI_PRODUCT_E14AC 0x14AC
+#define HUAWEI_PRODUCT_K3806 0x14AE
#define HUAWEI_PRODUCT_K4605 0x14C6
+#define HUAWEI_PRODUCT_K5005 0x14C8
+#define HUAWEI_PRODUCT_K3770 0x14C9
+#define HUAWEI_PRODUCT_K3771 0x14CA
+#define HUAWEI_PRODUCT_K4510 0x14CB
+#define HUAWEI_PRODUCT_K4511 0x14CC
+#define HUAWEI_PRODUCT_ETS1220 0x1803
+#define HUAWEI_PRODUCT_E353 0x1506
+#define HUAWEI_PRODUCT_E173S 0x1C05
#define HUAWEI_PRODUCT_E173S6 0x1C07
#define QUANTA_VENDOR_ID 0x0408
@@ -160,6 +236,8 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
+#define NOVATELWIRELESS_PRODUCT_G1 0xA001
+#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002
#define NOVATELWIRELESS_PRODUCT_E362 0x9010
#define NOVATELWIRELESS_PRODUCT_E371 0x9011
#define NOVATELWIRELESS_PRODUCT_U620L 0x9022
@@ -289,11 +367,15 @@ static void option_instat_callback(struct urb *urb);
#define ZTE_PRODUCT_MF622 0x0001
#define ZTE_PRODUCT_MF628 0x0015
#define ZTE_PRODUCT_MF626 0x0031
+#define ZTE_PRODUCT_CDMA_TECH 0xfffe
+#define ZTE_PRODUCT_AC8710 0xfff1
+#define ZTE_PRODUCT_AC2726 0xfff5
#define ZTE_PRODUCT_ZM8620_X 0x0396
#define ZTE_PRODUCT_ME3620_MBIM 0x0426
#define ZTE_PRODUCT_ME3620_X 0x1432
#define ZTE_PRODUCT_ME3620_L 0x1433
-#define ZTE_PRODUCT_AC2726 0xfff1
+#define ZTE_PRODUCT_AD3812 0xffeb
+#define ZTE_PRODUCT_MC2716 0xffed
#define ZTE_PRODUCT_MG880 0xfffd
#define ZTE_PRODUCT_CDMA_TECH 0xfffe
#define ZTE_PRODUCT_AC8710T 0xffff
@@ -370,6 +452,7 @@ static void option_instat_callback(struct urb *urb);
* It seems to contain a Qualcomm QSC6240/6290 chipset */
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
#define FOUR_G_SYSTEMS_PRODUCT_W100 0x9b01
+#define FOUR_G_SYSTEMS_PRODUCT_MMX350G 0x9800
/* iBall 3.5G connect wireless modem */
#define IBALL_3_5G_CONNECT 0x9605
@@ -377,6 +460,28 @@ static void option_instat_callback(struct urb *urb);
/* Zoom */
#define ZOOM_PRODUCT_4597 0x9607
+#define MICROMAX_VENDOR_ID 0x2020
+#define MICROMAX_1_PID 0x4010
+#define MICROMAX_MT6229 0x2000
+
+/* India */
+#define INDIA_VENDOR_ID 0x1dbc
+#define MMX355G 0x0669
+
+#define CHINA_TELECOM 0x15eb
+#define CHINA_TELECOM_CBP71 0x7152
+
+#define OLICARD_VID 0x0b3c
+#define OLICARD160_PID 0xc00a
+
+/*WM66E*/
+#define SMART_BRO_WM66E 0x9803
+/*MMX 3536*/
+#define MMX_PID_3536 0x9605
+/*MMX310*/
+#define MMX_PID_310 0x9e00
+#define MMX_PID_6003 0x6003
+
/* SpeedUp SU9800 usb 3g modem */
#define SPEEDUP_PRODUCT_SU9800 0x9800
@@ -384,6 +489,7 @@ static void option_instat_callback(struct urb *urb);
#define HAIER_VENDOR_ID 0x201e
#define HAIER_PRODUCT_CE81B 0x10f8
#define HAIER_PRODUCT_CE100 0x2009
+#define SMARTFREN_CE682 0x1022
/* Gemalto's Cinterion products (formerly Siemens) */
#define SIEMENS_VENDOR_ID 0x0681
@@ -417,10 +523,26 @@ static void option_instat_callback(struct urb *urb);
#define CELOT_VENDOR_ID 0x211f
#define CELOT_PRODUCT_CT680M 0x6801
+/* ONDA Communication vendor id */
+#define ONDA_VENDOR_ID 0x1ee8
+
+/* ONDA MT825UP HSDPA 14.2 modem */
+#define ONDA_MT825UP 0x000b
+
/* Samsung products */
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
+/* USI 3G */
+#define USI_VENDOR_ID 0x0e8d
+#define USI_PRODUCT_WCDMA_3COM 0x00a1
+#define USI_PRODUCT_WCDMA_2COM 0x00a2
+
+/* Spreadwin add by liuyalong*/
+#define SPREADWIN_VENDOR_ID 0x1782
+#define SPREADWIN_PRODUCT_G67 0x0002
+#define SPREADWIN_PRODUCT_G67_DEBUG 0x4d00
+
/* YUGA products www.yuga-info.com gavin.kx at qq.com */
#define YUGA_VENDOR_ID 0x257A
#define YUGA_PRODUCT_CEM600 0x1601
@@ -524,6 +646,15 @@ static void option_instat_callback(struct urb *urb);
#define INOVIA_VENDOR_ID 0x20a6
#define INOVIA_SEW858 0x1105
+/* STRONGRISING products */
+#define STRONGRISING_VENDOR_ID_W 0x20a6
+#define STRONGRISING_PRODUCT_ID_W 0x1105
+
+#define STRONGRISING_VENDOR_ID_TD 0x21f5
+#define STRONGRISING_PRODUCT_ID_TD 0x1101
+#define STRONGRISING_PRODUCT_MODEM_EVDO 0x2009
+#define STRONGRISING_PRODUCT_MODEM_WCDMA 0x2012
+
/* VIA Telecom */
#define VIATELECOM_VENDOR_ID 0x15eb
#define VIATELECOM_PRODUCT_CDS7 0x0001
@@ -719,6 +850,104 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) }, /* E398 3G Modem */
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) }, /* E398 3G PC UI Interface */
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) }, /* E398 3G Application Interface */
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) },
@@ -1106,6 +1335,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC547) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED) },
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) },
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) },
/* Novatel Ovation MC551 a.k.a. Verizon USB551L */
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
@@ -1219,6 +1450,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
+ { USB_DEVICE(OLICARD_VID, OLICARD160_PID) },//alic
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
.driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
@@ -1800,6 +2032,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xfffc, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MG880, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
@@ -1808,6 +2041,10 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L),
.driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM),
@@ -1853,6 +2090,7 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
+ { USB_DEVICE(INDIA_VENDOR_ID, MMX355G), 0x0a, 0x00, 0x00 },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
.driver_info = (kernel_ulong_t)&four_g_w14_blacklist
},
@@ -1860,10 +2098,19 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&four_g_w100_blacklist
},
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_MMX350G) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, SMART_BRO_WM66E) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, MMX_PID_3536) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, MMX_PID_310) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, MMX_PID_6003) },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
{ USB_DEVICE_AND_INTERFACE_INFO(HAIER_VENDOR_ID, HAIER_PRODUCT_CE81B, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(HAIER_VENDOR_ID, SMARTFREN_CE682) },
+ { USB_DEVICE(CHINA_TELECOM, CHINA_TELECOM_CBP71) },
+ { USB_DEVICE(MICROMAX_VENDOR_ID, MICROMAX_1_PID) },
+ { USB_DEVICE(MICROMAX_VENDOR_ID, MICROMAX_MT6229) },
/* Pirelli */
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2, 0xff) },
@@ -1917,7 +2164,12 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
+ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
+ { USB_DEVICE(USI_VENDOR_ID, USI_PRODUCT_WCDMA_3COM) }, /* USI WCDMA modem 3COM */
+ { USB_DEVICE(USI_VENDOR_ID, USI_PRODUCT_WCDMA_2COM) }, /* USI WCDMA modem 2COM */
+ { USB_DEVICE(SPREADWIN_VENDOR_ID, SPREADWIN_PRODUCT_G67) },
+ { USB_DEVICE(SPREADWIN_VENDOR_ID, SPREADWIN_PRODUCT_G67_DEBUG) },
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM500) },
@@ -1988,6 +2240,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) },
{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
+ { USB_DEVICE(STRONGRISING_VENDOR_ID_W, STRONGRISING_PRODUCT_ID_W) },
+ { USB_DEVICE(STRONGRISING_VENDOR_ID_TD, STRONGRISING_PRODUCT_ID_TD) },
+ { USB_DEVICE(STRONGRISING_VENDOR_ID_TD, STRONGRISING_PRODUCT_MODEM_EVDO) },
+ { USB_DEVICE(STRONGRISING_VENDOR_ID_TD, STRONGRISING_PRODUCT_MODEM_WCDMA) },
{ USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
{ USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
@@ -2143,6 +2399,7 @@ static void option_release(struct usb_serial *serial)
static void option_instat_callback(struct urb *urb)
{
int err;
+ static int cnt=0;
int status = urb->status;
struct usb_serial_port *port = urb->context;
struct device *dev = &port->dev;
@@ -2187,6 +2444,19 @@ static void option_instat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN && status != -ENOENT) {
+ /* fix the bug when plug-out dongle will always print
+ option_instat_callback: error -71 */
+ if(status == -EPROTO){
+ cnt++;
+ if(cnt > 10){
+ cnt = 0;
+ return;
+ }
+
+ }
+ else{
+ cnt = 0;
+ }
usb_mark_last_busy(port->serial->dev);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
old mode 100644
new mode 100755
index ba8f759..0d95ac9
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -90,6 +90,17 @@ module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
+#define DEBUG_TIME_OF_SCSI_CMDS 1
+#if DEBUG_TIME_OF_SCSI_CMDS
+static unsigned int total_usec_time_of_scsi_cmds = 0;
+module_param(total_usec_time_of_scsi_cmds, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(total_usec_time_of_scsi_cmds, "total_usec_time_of_scsi_cmds");
+
+static unsigned int debug_cmds_time = 0;
+module_param(debug_cmds_time, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug_cmds_time, "debug_cmds_time");
+#endif
+
/*
* The entries in this table correspond, line for line,
* with the entries in usb_storage_usb_ids[], defined in usual-tables.c.
@@ -375,8 +386,30 @@ static int usb_stor_control_thread(void * __us)
/* we've got a command, let's do it! */
else {
+#if DEBUG_TIME_OF_SCSI_CMDS
+ struct timeval tv_start;
+ struct timeval tv_end;
+#endif
+
US_DEBUG(usb_stor_show_command(us, us->srb));
+
+#if DEBUG_TIME_OF_SCSI_CMDS
+ if(debug_cmds_time) {
+ do_gettimeofday(&tv_start);
+ }
+#endif
us->proto_handler(us->srb, us);
+#if DEBUG_TIME_OF_SCSI_CMDS
+ if(debug_cmds_time) {
+ do_gettimeofday(&tv_end);
+ if(tv_end.tv_sec > tv_start.tv_sec) {
+ total_usec_time_of_scsi_cmds += ((tv_end.tv_sec - tv_start.tv_sec)*1000000 + tv_end.tv_usec - tv_start.tv_usec);
+ }
+ else {
+ total_usec_time_of_scsi_cmds += (tv_end.tv_usec - tv_start.tv_usec);
+ }
+ }
+#endif
usb_mark_last_busy(us->pusb_dev);
}
--
2.7.4
More information about the linux-yocto
mailing list