aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/usb/s3c-otg-host.txt83
-rw-r--r--arch/arm/configs/herring_defconfig14
-rwxr-xr-xarch/arm/mach-s5pv210/mach-herring.c45
-rw-r--r--arch/arm/plat-s5p/devs.c31
-rw-r--r--arch/arm/plat-s5p/include/plat/s5p-otghost.h55
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h3
-rwxr-xr-xdrivers/misc/fsa9480.c18
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/core/hcd.c4
-rw-r--r--drivers/usb/gadget/Kconfig4
-rw-r--r--drivers/usb/gadget/s3c_udc_otg.c112
-rw-r--r--drivers/usb/host/Kconfig16
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/s3c-otg/Makefile18
-rw-r--r--drivers/usb/host/s3c-otg/debug-mem.c55
-rw-r--r--drivers/usb/host/s3c-otg/debug-mem.h9
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-common-common.h49
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-common-const.h167
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-common-datastruct.h785
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-common-errorcode.h115
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-common-regdef.h302
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-debug.h88
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.c379
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.h75
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.c706
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.h152
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-kal.h420
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-list.h217
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-hcdi-memory.h191
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-isr.c294
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-isr.h72
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-oci.c798
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-oci.h86
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-roothub.c605
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-roothub.h65
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-scheduler-ischeduler.c369
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-scheduler-readyq.c264
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.c416
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.h98
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transfer-common.c805
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transfer-nonperiodic.c140
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transfer-periodic.c128
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transfer-transfer.h144
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.c720
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.h88
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-checker.h66
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.c238
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.h79
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.c698
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.h99
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.c574
-rw-r--r--drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.h97
-rwxr-xr-xdrivers/usb/notify/Kconfig11
-rwxr-xr-xdrivers/usb/notify/Makefile4
-rwxr-xr-xdrivers/usb/notify/host_notify_class.c262
-rwxr-xr-xinclude/linux/host_notify.h53
-rw-r--r--include/linux/usb/hcd.h9
58 files changed, 11396 insertions, 5 deletions
diff --git a/Documentation/usb/s3c-otg-host.txt b/Documentation/usb/s3c-otg-host.txt
new file mode 100644
index 0000000..97e7f91
--- /dev/null
+++ b/Documentation/usb/s3c-otg-host.txt
@@ -0,0 +1,83 @@
+This file is a collection of notes on using the USB OTG port of the Samsung Galaxy Tab in HOST mode.
+
+1/17/12 - Zsolt Sz. Sztupak, mail@sztupy.hu, http://android.sztupy.hu
+
+Kevin's patch to the kernel was great, but it had some problems, namely:
+* it was based on an old Froyo (or Eclair?) branch of the kernel, which still had a lot of old code, and methods
+ that were deprecated in later kernel versions
+* the actual client/host changing code was put inside the 30pin connector file, which only exists in the Galaxy
+ Tab based Kernels
+
+The changes I've made are the following:
+* port some of the deprecated code to kernel version 3.x
+* change the otg detector/switcher code from the 30 pin connector module to the s3c otg gadget (client mode) module
+
+There is still a lof code not ported from the old kernel branch as it uses a lot of ugly old samsung kernel code,
+which are non existent in later kernel versions. These include interrupt, LDO and clock switchings, which might
+be the case of some of the hangups.
+
+8/24/11 - Kevin Hester, kevin@ridemission.com
+
+I'm writing this document to capture both the software and hardware changes needed for this device in one place.
+If you are a brave Android kernel hacker, please try these changes out and send pull requests to github with any
+fixes you add. I have been unable to find a 'master' github site where hobbyists are maintaining a master Samsung
+kernel and Android OS, if you have such a site feel free to include my fixes (though credit would be appreciated).
+These fixes are provided 'as-is' and you could bust your device or do any number of bad things.
+
+I'm going to post these notes on the xda forums, but for the latest code and documentation please see my github site.
+
+History: The Samsung open source kernel files (from opensource.samsung.com) contained a USB host mode driver for the
+S5PC110 chipset. These drivers were located in drivers/usb/host/s3c-otg. The driver contained a number of bugs which
+I've fixed and it now seems to work reasonably well for USB serial ports, flash drives etc.
+
+Hardware: To use USB host mode on your samsung tablet _external 5V DC seems to be required_. I have not found
+turning any of the samsung LDOs on to make the unit provide USB power (if you find different, please let me know).
+
+To wire up a USB host mode cable you'll need the following pinout (found on a web forum):
+1 Gnd P
+2 Gnd P
+3 USB_DP_CON I/O
+4 USB_DM_CON I/O
+5 IF_CON_SENSE I
+6 V_ACCESSORY_5.0V P
+7 V_BUS_1 P
+8 V_BUS_1 P
+9 VOUT_CHARGER P (gives out 4v when checked with a multimeter)
+10 VOUT_CHARGER P (gives out 4v when checked with a multimeter)
+11 --- --
+12 --- --
+13 ACCESSORY_ID / USB_ID I
+14 ACCESSORY_INT I
+15 Gnd P
+16 Gnd P
+17 MHL_DP I/O
+18 MHL_DM I/O
+19 MHL_ID I
+20 IF_RXD I
+21 IF_TXD O
+22 --- --
+23 AP_TV_OUT O
+24 REMOTE_SENSE I
+25 --- --
+26 --- --
+27 EAR_L_CRADLE O
+28 EAR_R_CRADLE O
+29 3.5_INT_TEST I
+30 Gnd P
+
+Your cable will need to connect the following five pins:
+1 Gnd
+3 USB_DP
+4 USB_DM
+8 5V+ (at least 1A if you want to support high speed charging of the tablet)
+13 Host mode (attach to ground to run tablet as a host, or leave disconnected to run tablet as a USB target)
+
+A summary of my driver changes:
+* Fix a nubmer of cases where TDs would be used after delete_td and the associated storage was freed (caused kernel
+heap corruption)
+* Allow a bit more time for some mystery Samsung LDO to power up before switching to host mode (caused failure in device detect)
+* Wait for channel disabled interrupt when cancelling transactions (prevents a race condition with the ISR)
+* Properly switch into USB host mode when a host mode cable is detected (see 30pin_con.c)
+* Mark transfers as done when cancel_to_transfer_td is called (prevents rescheduling transactions we have freed)
+* do not force is_need_to_insert_scheduler true in cancel_transfer, this caused list corruption in the ed list
+
diff --git a/arch/arm/configs/herring_defconfig b/arch/arm/configs/herring_defconfig
index 13a1c39..141ee8d 100644
--- a/arch/arm/configs/herring_defconfig
+++ b/arch/arm/configs/herring_defconfig
@@ -203,7 +203,9 @@ CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_MPPE=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
CONFIG_KEYPAD_CYPRESS_TOUCH=y
@@ -334,6 +336,16 @@ CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_G_ANDROID=y
CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED=y
+CONFIG_USB=y
+CONFIG_USB_S3C_OTG_HOST=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_ACM=y
CONFIG_MMC=y
CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MMC_SDHCI=y
diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c
index e370212..1631bd6 100755
--- a/arch/arm/mach-s5pv210/mach-herring.c
+++ b/arch/arm/mach-s5pv210/mach-herring.c
@@ -5514,6 +5514,9 @@ static struct platform_device *herring_devices[] __initdata = {
&herring_i2c11_device, /* optical sensor */
&herring_i2c12_device, /* magnetic sensor */
&herring_i2c14_device, /* nfc sensor */
+#ifdef CONFIG_USB_S3C_OTG_HOST
+ &s3c_device_usb_otghcd,
+#endif
#ifdef CONFIG_USB_GADGET
&s3c_device_usbgadget,
#endif
@@ -5988,10 +5991,10 @@ void otg_phy_init(void)
S3C_USBOTG_PHYCLK);
writel((readl(S3C_USBOTG_RSTCON) & ~(0x3<<1)) | (0x1<<0),
S3C_USBOTG_RSTCON);
- msleep(1);
+ mdelay(1);
writel(readl(S3C_USBOTG_RSTCON) & ~(0x7<<0),
S3C_USBOTG_RSTCON);
- msleep(1);
+ mdelay(1);
/* rising/falling time */
writel(readl(S3C_USBOTG_PHYTUNE) | (0x1<<20),
@@ -6049,6 +6052,44 @@ void usb_host_phy_off(void)
EXPORT_SYMBOL(usb_host_phy_off);
#endif
+#ifdef CONFIG_USB_S3C_OTG_HOST
+
+/* Initializes OTG Phy */
+void otg_host_phy_init(void)
+{
+ __raw_writel(__raw_readl(S5P_USB_PHY_CONTROL)
+ |(0x1<<0), S5P_USB_PHY_CONTROL); /*USB PHY0 Enable */
+// from galaxy tab otg host:
+// __raw_writel((__raw_readl(S3C_USBOTG_PHYPWR)
+// &~(0x3<<3)&~(0x1<<0))|(0x1<<5), S3C_USBOTG_PHYPWR);
+// from galaxy s2 otg host:
+ __raw_writel((__raw_readl(S3C_USBOTG_PHYPWR)
+ &~(0x7<<3)&~(0x1<<0)), S3C_USBOTG_PHYPWR);
+ __raw_writel((__raw_readl(S3C_USBOTG_PHYCLK)
+ &~(0x1<<4))|(0x7<<0), S3C_USBOTG_PHYCLK);
+
+ __raw_writel((__raw_readl(S3C_USBOTG_RSTCON)
+ &~(0x3<<1))|(0x1<<0), S3C_USBOTG_RSTCON);
+ mdelay(1);
+ __raw_writel((__raw_readl(S3C_USBOTG_RSTCON)
+ &~(0x7<<0)), S3C_USBOTG_RSTCON);
+ mdelay(1);
+
+ __raw_writel((__raw_readl(S3C_UDC_OTG_GUSBCFG)
+ |(0x3<<8)), S3C_UDC_OTG_GUSBCFG);
+
+// smb136_set_otg_mode(1);
+
+ printk("otg_host_phy_int : USBPHYCTL=0x%x,PHYPWR=0x%x,PHYCLK=0x%x,USBCFG=0x%x\n",
+ readl(S5P_USB_PHY_CONTROL),
+ readl(S3C_USBOTG_PHYPWR),
+ readl(S3C_USBOTG_PHYCLK),
+ readl(S3C_UDC_OTG_GUSBCFG)
+ );
+}
+EXPORT_SYMBOL(otg_host_phy_init);
+#endif
+
MACHINE_START(HERRING, "herring")
.boot_params = S5P_PA_SDRAM + 0x100,
.fixup = herring_fixup,
diff --git a/arch/arm/plat-s5p/devs.c b/arch/arm/plat-s5p/devs.c
index f961d66..f5ff6ed 100644
--- a/arch/arm/plat-s5p/devs.c
+++ b/arch/arm/plat-s5p/devs.c
@@ -41,6 +41,37 @@
#include <mach/media.h>
#include <s3cfb.h>
+#ifdef CONFIG_USB_S3C_OTG_HOST
+/* USB Device (OTG hcd)*/
+static struct resource s3c_usb_otghcd_resource[] = {
+ [0] = {
+ .start = S3C_PA_OTG,
+ .end = S3C_PA_OTG + S3C_SZ_OTG - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_OTG,
+ .end = IRQ_OTG,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 s3c_device_usb_otghcd_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_usb_otghcd = {
+ .name = "s3c_otghcd",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s3c_usb_otghcd_resource),
+ .resource = s3c_usb_otghcd_resource,
+ .dev = {
+ .dma_mask = &s3c_device_usb_otghcd_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+EXPORT_SYMBOL(s3c_device_usb_otghcd);
+#endif
+
/* RTC */
static struct resource s5p_rtc_resource[] = {
[0] = {
diff --git a/arch/arm/plat-s5p/include/plat/s5p-otghost.h b/arch/arm/plat-s5p/include/plat/s5p-otghost.h
new file mode 100644
index 0000000..5e4b6a9
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/s5p-otghost.h
@@ -0,0 +1,55 @@
+/* linux/arch/arm/plat-s5p/include/plat/s5p-otghost.h
+ *
+ * Copyright 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Platform header file for Samsung OTG Host driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#ifndef _PLAT_S5P_OTGHOST_H
+#define _PLAT_S5P_OTGHOST_H __FILE__
+
+#include <linux/wakelock.h>
+
+/*#define CONFIG_USB_S3C_OTG_HOST_HANDLING_CLOCK*/
+#define CONFIG_USB_S3C_OTG_HOST_DTGDRVVBUS
+
+union port_flags_t {
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct {
+ unsigned port_connect_status_change:1;
+ unsigned port_connect_status:1;
+ unsigned port_reset_change:1;
+ unsigned port_enable_change:1;
+ unsigned port_suspend_change:1;
+ unsigned port_over_current_change:1;
+ unsigned reserved:26;
+ } b;
+};
+
+struct sec_otghost_data {
+ bool clk_usage;
+ void (*set_pwr_cb)(int on);
+ int host_notify;
+ int sec_whlist_table_num;
+};
+
+struct sec_otghost {
+ spinlock_t lock;
+
+ bool ch_halt;
+ union port_flags_t port_flag;
+ struct wake_lock wake_lock;
+
+ struct work_struct work;
+ struct workqueue_struct *wq;
+
+ struct sec_otghost_data *otg_data;
+};
+
+#endif /*_PLAT_S5P_OTGHOST_H */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 1170fb9..ed60a6e 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -114,6 +114,9 @@ extern struct platform_device s3c_device_android_usb;
extern struct platform_device s3c_device_usb_mass_storage;
extern struct platform_device s3c_device_rndis;
extern struct platform_device s3c_device_usb_hsotg;
+#ifdef CONFIG_USB_S3C_OTG_HOST
+extern struct platform_device s3c_device_usb_otghcd;
+#endif
extern struct platform_device s5p_device_rotator;
extern struct platform_device s5p_device_tvout;
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
index 8098f82..1d5e08c 100755
--- a/drivers/misc/fsa9480.c
+++ b/drivers/misc/fsa9480.c
@@ -106,6 +106,10 @@
#define INT_DETACH (1 << 1)
#define INT_ATTACH (1 << 0)
+#ifdef CONFIG_USB_S3C_OTG_HOST
+extern void set_otghost_mode(int mode);
+#endif
+
struct fsa9480_usbsw {
struct i2c_client *client;
struct fsa9480_platform_data *pdata;
@@ -266,6 +270,16 @@ static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw)
dev_err(&client->dev,
"%s: err %d\n", __func__, ret);
}
+#ifdef CONFIG_USB_S3C_OTG_HOST
+// sztupy: handle automatic otg switching
+ if (val1 & DEV_USB_OTG) {
+ // otg cable detected
+ set_otghost_mode(2);
+ } else {
+ // client cable detected
+ set_otghost_mode(1);
+ }
+#endif
/* UART */
} else if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) {
if (pdata->uart_cb)
@@ -320,6 +334,10 @@ static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw)
usbsw->dev2 & DEV_T2_USB_MASK) {
if (pdata->usb_cb)
pdata->usb_cb(FSA9480_DETACHED);
+#ifdef CONFIG_USB_S3C_OTG_HOST
+ // sztupy: also switch off otg host mode
+ set_otghost_mode(0);
+#endif
/* UART */
} else if (usbsw->dev1 & DEV_T1_UART_MASK ||
usbsw->dev2 & DEV_T2_UART_MASK) {
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48f1781..8bf0a0b 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -168,4 +168,6 @@ source "drivers/usb/gadget/Kconfig"
source "drivers/usb/otg/Kconfig"
+source "drivers/usb/notify/Kconfig"
+
endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 30ddf8d..707fe92 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_PCI) += host/
+obj-$(CONFIG_USB_S3C_OTG_HOST) += host/
obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
@@ -51,3 +52,5 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_OTG_UTILS) += otg/
obj-$(CONFIG_USB_GADGET) += gadget/
+
+obj-$(CONFIG_USB_HOST_NOTIFY) += notify/
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 45e0908..2fb9a29 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -156,7 +156,11 @@ static const u8 usb2_rh_dev_descriptor [18] = {
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
+#ifdef CONFIG_USB_S3C_OTG_HOST
+ 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ] */
+#else
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
+#endif
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 60e51d4..9f30cf5 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -376,7 +376,7 @@ config USB_S3C_HSUDC
config USB_GADGET_S3C_OTGD
boolean "S3C HS USB OTG Device"
- depends on (ARCH_S5PV210) && !(USB_S3C_OTG_HOST)
+ depends on (ARCH_S5PV210)
help
Samsung's S3C64XX processors include high speed USB OTG2.0
controller. It has 15 configurable endpoints, as well as
@@ -653,7 +653,7 @@ comment "NOTE: S3C OTG device role enables the controller driver below"
config USB_S3C_OTGD
tristate "S3C high speed(2.0, dual-speed) USB OTG device"
- depends on USB_GADGET && USB_GADGET_S3C_OTGD && !(USB_S3C_OTG_HOST)
+ depends on USB_GADGET && USB_GADGET_S3C_OTGD
default y
default USB_GADGET
select USB_GADGET_SELECTED
diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/s3c_udc_otg.c
index 9ebb7b7..96824a4 100644
--- a/drivers/usb/gadget/s3c_udc_otg.c
+++ b/drivers/usb/gadget/s3c_udc_otg.c
@@ -28,6 +28,12 @@
#include <plat/regs-otg.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
#if defined(CONFIG_USB_GADGET_S3C_OTGD_DMA_MODE) /* DMA mode */
#define OTG_DMA_MODE 1
@@ -1179,6 +1185,108 @@ static struct s3c_udc memory = {
},
};
+#ifdef CONFIG_USB_S3C_OTG_HOST
+atomic_t g_OtgHostMode; // actual mode: client (0) or host (1)
+atomic_t g_OtgOperationMode; // operation mode: 'c'lient, 'h'ost, 'o'tg or 'a'uto-host
+atomic_t g_OtgLastCableState; // last cable state: detached (0), client attached (1), otg attached (2)
+extern struct platform_driver s5pc110_otg_driver;
+
+int s3c_is_otgmode(void)
+{
+ printk("otgmode = %d\n", atomic_read(&g_OtgHostMode));
+ return atomic_read(&g_OtgHostMode);
+}
+EXPORT_SYMBOL(s3c_is_otgmode);
+
+void set_otghost_mode(int mode) {
+//sztupy:
+// this function will determine what to do with the new information according to the current mode of operation
+// mode: 0: cable detached, 1: client cable attached, 2: otg cable attached, -1: operation config changed
+// modes of operation: c: always client, h: always host, g: otg mode (host if otg cable), a: automatic mode (host if cable plugged in)
+
+ struct s3c_udc *dev = the_controller;
+ int enable = 0;
+ char opmode = atomic_read(&g_OtgOperationMode);
+ if (mode==-1) mode = atomic_read(&g_OtgLastCableState);
+ atomic_set(&g_OtgLastCableState, mode);
+ switch (opmode) {
+ case 'h': enable = 1; break;
+ case 'o': enable = (mode==2); break;
+ case 'a': enable = (mode>0); break;
+ default: atomic_set(&g_OtgOperationMode,'c'); enable = 0; break;
+ }
+
+ if (enable && !atomic_read(&g_OtgHostMode)) {
+ printk("Setting OTG host mode\n");
+ free_irq(IRQ_OTG, dev);
+ s3c_vbus_enable(&dev->gadget, 1);
+
+ if (platform_driver_register(&s5pc110_otg_driver) < 0)
+ {
+ printk("platform_driver_register failed...\n");
+ atomic_set(&g_OtgHostMode , 0);
+ } else {
+ printk("platform_driver_register...\n");
+ atomic_set(&g_OtgHostMode , 1);
+ }
+ } else if (!enable && atomic_read(&g_OtgHostMode)) {
+// sztupy: also handle the disabling here
+ printk("Disabling OTG host mode\n");
+ s3c_vbus_enable(&dev->gadget, 0);
+ platform_driver_unregister(&s5pc110_otg_driver);
+ printk("platform_driver_unregistered\n");
+ /* irq setup after old hardware state is cleaned up */
+ if (request_irq(IRQ_OTG, s3c_udc_irq, 0, driver_name, dev)) {
+ printk("Warning: Could not request IRQ for USB gadget!\n");
+ }
+ atomic_set(&g_OtgHostMode , 0);
+ } else {
+ printk("OTG: no changes needed\n");
+ }
+}
+
+EXPORT_SYMBOL(set_otghost_mode);
+
+static ssize_t usbmode_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ const char *msg = "client";
+ const char *msg2 = "disconnected";
+ const char *msg3 = "gadget";
+ switch(atomic_read(&g_OtgOperationMode)) {
+ case 'o': msg = "otg"; break;
+ case 'h': msg = "host"; break;
+ case 'a': msg = "auto-host"; break;
+ }
+ switch(atomic_read(&g_OtgLastCableState)) {
+ case 1: msg2 = "usb connected"; break;
+ case 2: msg2 = "otg connected"; break;
+ }
+ switch(atomic_read(&g_OtgHostMode)) {
+ case 1: msg3 = "host"; break;
+ }
+
+ return sprintf(buf,"%s (cable: %s; state: %s)\n", msg, msg2, msg3);
+}
+
+static ssize_t usbmode_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ char c;
+ printk("input data --> %s\n", buf);
+ c = buf[0];
+ switch(c) {
+ case 'a': atomic_set(&g_OtgOperationMode, 'a'); set_otghost_mode(-1);break;
+ case 'h': atomic_set(&g_OtgOperationMode, 'h'); set_otghost_mode(-1);break;
+ case 'c': atomic_set(&g_OtgOperationMode, 'c'); set_otghost_mode(-1);break;
+ case 'o': atomic_set(&g_OtgOperationMode, 'o'); set_otghost_mode(-1);break;
+ default: printk("Invalid input data\n");
+ }
+ return size;
+}
+
+// kevinh - Allow changing USB host/target modes on S3C android devices without a special cable
+static DEVICE_ATTR(opmode, S_IRUGO | S_IWUSR, usbmode_read, usbmode_write);
+#endif
+
/*
* probe - binds to the platform device
*/
@@ -1232,6 +1340,10 @@ static int s3c_udc_probe(struct platform_device *pdev)
disable_irq(IRQ_OTG);
create_proc_files();
+#ifdef CONFIG_USB_S3C_OTG_HOST
+ if (device_create_file(&pdev->dev, &dev_attr_opmode) < 0)
+ printk("Failed to create device file(%s)!\n", dev_attr_opmode.attr.name);
+#endif
return retval;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ab085f1..67c452d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -578,3 +578,19 @@ config USB_OCTEON_OHCI
config USB_OCTEON2_COMMON
bool
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_S3C_OTG_HOST
+ tristate "S3C USB OTG Host support"
+ depends on USB && (PLAT_S3C64XX || PLAT_S5P)
+ help
+ Samsung's S3C64XX processors include high speed USB OTG2.0
+ controller. It has 15 configurable endpoints, as well as
+ endpoint zero (for control transfers).
+
+ This driver support only OTG Host role. If you want to use
+ OTG Device role, select USB Gadget support and S3C OTG Device.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "s3c_otg_hcd" and force all
+ drivers to also be dynamically linked.
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 624a362..de59025 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,6 +15,7 @@ xhci-hcd-y := xhci.o xhci-mem.o xhci-pci.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
obj-$(CONFIG_USB_WHCI_HCD) += whci/
+obj-$(CONFIG_USB_S3C_OTG_HOST) += s3c-otg/
obj-$(CONFIG_PCI) += pci-quirks.o
diff --git a/drivers/usb/host/s3c-otg/Makefile b/drivers/usb/host/s3c-otg/Makefile
new file mode 100644
index 0000000..37674c8
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for USB OTG Host Controller Drivers
+#
+
+obj-$(CONFIG_USB_S3C_OTG_HOST) += s3c_otg_hcd.o
+
+s3c_otg_hcd-objs += s3c-otg-hcdi-driver.o s3c-otg-hcdi-hcd.o
+s3c_otg_hcd-objs += s3c-otg-transfer-common.o s3c-otg-transfer-nonperiodic.o \
+ s3c-otg-transfer-periodic.o
+s3c_otg_hcd-objs += s3c-otg-scheduler-ischeduler.o s3c-otg-scheduler-scheduler.o \
+ s3c-otg-scheduler-readyq.o
+s3c_otg_hcd-objs += s3c-otg-oci.o
+s3c_otg_hcd-objs += s3c-otg-transferchecker-common.o \
+ s3c-otg-transferchecker-control.o \
+ s3c-otg-transferchecker-bulk.o \
+ s3c-otg-transferchecker-interrupt.o
+s3c_otg_hcd-objs += s3c-otg-isr.o
+s3c_otg_hcd-objs += s3c-otg-roothub.o
diff --git a/drivers/usb/host/s3c-otg/debug-mem.c b/drivers/usb/host/s3c-otg/debug-mem.c
new file mode 100644
index 0000000..de85853
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/debug-mem.c
@@ -0,0 +1,55 @@
+#include "s3c-otg-hcdi-hcd.h"
+#include "debug-mem.h"
+
+#define MAX_ALLOCS 1024
+
+typedef void *ElemType;
+
+static ElemType alloced[MAX_ALLOCS];
+static int numalloced = 0;
+
+#define fail(args...) ( printk(args), dump_stack() )
+
+void debug_alloc(void *addr) {
+ ElemType *freeloc = NULL;
+ ElemType *c = alloced;
+ int i;
+
+ if(!addr)
+ fail("MEMD alloc of NULL");
+
+ for(i = 0; i < numalloced; i++, c++) {
+ if(*c == NULL && freeloc == NULL)
+ freeloc = c;
+ else if(*c == addr)
+ fail("MEMD multiple allocs of %p", addr);
+ }
+
+ if(freeloc)
+ *freeloc = addr;
+ else {
+ if(numalloced >= MAX_ALLOCS)
+ fail("MEMD too many allocs");
+ else {
+ alloced[numalloced++] = addr;
+ }
+ }
+}
+
+void debug_free(void *addr) {
+ ElemType *c = alloced;
+ int i;
+
+ if(!addr)
+ fail("free of NULL");
+
+ for(i = 0; i < numalloced; i++, c++) {
+ if(*c == addr) {
+ *c = NULL;
+ return;
+ }
+ }
+
+ fail("MEMD freed addr %p was never alloced\n", addr);
+}
+
diff --git a/drivers/usb/host/s3c-otg/debug-mem.h b/drivers/usb/host/s3c-otg/debug-mem.h
new file mode 100644
index 0000000..4164793
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/debug-mem.h
@@ -0,0 +1,9 @@
+#ifndef __DEBUGMEM_H
+#define __DEBUGMEM_H
+
+// kevinh quick hack to see if the s3c stuff is doing memory properly
+
+void debug_alloc(void *addr);
+void debug_free(void *addr);
+
+#endif
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-common-common.h b/drivers/usb/host/s3c-otg/s3c-otg-common-common.h
new file mode 100644
index 0000000..720154e
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-common-common.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-common-common.h
+ * @brief it includes common header files for all modules \n
+ * @version
+ * ex)-# Jun 11,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_COMMON_COMMON_H_
+#define _S3C_OTG_COMMON_COMMON_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-errorcode.h"
+#include <linux/errno.h>
+#include <linux/usb.h>
+
+//Define OS
+#define LINUX 1
+
+//Kernel Version
+#define KERNEL_2_6_21
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _S3C_OTG_COMMON_COMMON_H_ */
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-common-const.h b/drivers/usb/host/s3c-otg/s3c-otg-common-const.h
new file mode 100644
index 0000000..f0f5cb9
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-common-const.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : s3c-otg-common-const.h
+ * [Description] : The Header file defines constants to be used at sub-modules of S3C6400HCD.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/03
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created s3c-otg-common-const.h file and defines some constants.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _CONST_TYPE_DEF_H_
+#define _CONST_TYPE_DEF_H_
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+#include "s3c-otg-common-common.h"
+
+//#include "s3c-otg-common-regdef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @def OTG_PORT_NUMBER
+ *
+ * @brief write~ description
+ *
+ * describe in detail
+ */
+#define OTG_PORT_NUMBER 0
+
+
+
+//Defines Stages of Control Transfer
+#define SETUP_STAGE 1
+#define DATA_STAGE 2
+#define STATUS_STAGE 3
+#define COMPLETE_STAGE 4
+
+
+//Defines Direction of Endpoint
+#define EP_IN 1
+#define EP_OUT 0
+
+//Define speed of USB Device
+#define LOW_SPEED_OTG 2
+#define FULL_SPEED_OTG 1
+#define HIGH_SPEED_OTG 0
+#define SUPER_SPEED_OTG 3
+
+//Define multiple count of packet in periodic transfer.
+#define MULTI_COUNT_ZERO 0
+#define MULTI_COUNT_ONE 1
+#define MULTI_COUNT_TWO 2
+
+//Define USB Transfer Types.
+#define CONTROL_TRANSFER 0
+#define ISOCH_TRANSFER 1
+#define BULK_TRANSFER 2
+#define INT_TRANSFER 3
+
+#define BULK_TIMEOUT 300
+
+//Defines PID
+#define DATA0 0
+#define DATA1 2
+#define DATA2 1
+#define MDATA 3
+#define SETUP 3
+
+//Defines USB Transfer Request Size on USB2.0
+#define USB_20_STAND_DEV_REQUEST_SIZE 8
+//Define Max Channel Number
+#define MAX_CH_NUMBER 16
+//Define Channel Number
+#define CH_0 0
+#define CH_1 1
+#define CH_2 2
+#define CH_3 3
+#define CH_4 4
+#define CH_5 5
+#define CH_6 6
+#define CH_7 7
+#define CH_8 8
+#define CH_9 9
+#define CH_10 10
+#define CH_11 11
+#define CH_12 12
+#define CH_13 13
+#define CH_14 14
+#define CH_15 15
+#define CH_NONE 20
+
+
+// define the Constant for result of processing the USB Transfer.
+#define RE_TRANSMIT 1
+#define RE_SCHEDULE 2
+#define DE_ALLOCATE 3
+#define NO_ACTION 4
+
+//define the threshold value to retransmit USB Transfer
+#define RETRANSMIT_THRESHOLD 2
+
+//define the maximum size of data to be tranferred through channel.
+#define MAX_CH_TRANSFER_SIZE 65536//65535
+
+//define Max Frame Number which Synopsys OTG suppports.
+#define MAX_FRAME_NUMBER 0x3FFF
+// Channel Interrupt Status
+#define CH_STATUS_DataTglErr (0x1<<10)
+#define CH_STATUS_FrmOvrun (0x1<<9)
+#define CH_STATUS_BblErr (0x1<<8)
+#define CH_STATUS_XactErr (0x1<<7)
+#define CH_STATUS_NYET (0x1<<6)
+#define CH_STATUS_ACK (0x1<<5)
+#define CH_STATUS_NAK (0x1<<4)
+#define CH_STATUS_STALL (0x1<<3)
+#define CH_STATUS_AHBErr (0x1<<2)
+#define CH_STATUS_ChHltd (0x1<<1)
+#define CH_STATUS_XferCompl (0x1<<0)
+#define CH_STATUS_ALL 0x7FF
+
+
+//Define USB Transfer Flag..
+//typedef URB_SHORT_NOT_OK USB_TRANS_FLAG_NOT_SHORT;
+//typedef URB_ISO_ASAP USB_TRANS_FLAG_ISO_ASYNCH;
+
+#define USB_TRANS_FLAG_NOT_SHORT URB_SHORT_NOT_OK
+#define USB_TRANS_FLAG_ISO_ASYNCH URB_ISO_ASAP
+
+
+#define HFNUM_MAX_FRNUM 0x3FFF
+#define SCHEDULE_SLOT 10
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-common-datastruct.h b/drivers/usb/host/s3c-otg/s3c-otg-common-datastruct.h
new file mode 100644
index 0000000..8165981
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-common-datastruct.h
@@ -0,0 +1,785 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : s3c-otg-common-datastruct.h
+ * [Description] : The Header file defines Data Structures to be used at sub-modules of S3C6400HCD.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/03
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines Data Structure to be managed by Transfer.
+ * (2) 2008/08/18 by SeungSoo Yang ( ss1.yang@samsung.com )
+ * - modifying ED structure
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _DATA_STRUCT_DEF_H
+#define _DATA_STRUCT_DEF_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+#include <linux/wakelock.h>
+#include <plat/s5p-otghost.h>
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-hcdi-list.h"
+
+//#include "s3c-otg-common-regdef.h"
+//#include "s3c-otg-common-errorcode.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef union _hcintmsk_t
+{
+ // raw register data
+ u32 d32;
+
+ // register bits
+ struct
+ {
+ unsigned xfercompl : 1;
+ unsigned chhltd : 1;
+ unsigned ahberr : 1;
+ unsigned stall : 1;
+ unsigned nak : 1;
+ unsigned ack : 1;
+ unsigned nyet : 1;
+ unsigned xacterr : 1;
+ unsigned bblerr : 1;
+ unsigned frmovrun : 1;
+ unsigned datatglerr : 1;
+ unsigned reserved : 21;
+ } b;
+} hcintmsk_t;
+
+typedef union _hcintn_t
+{
+ u32 d32;
+ struct
+ {
+ u32 xfercompl :1;
+ u32 chhltd :1;
+ u32 abherr :1;
+ u32 stall :1;
+ u32 nak :1;
+ u32 ack :1;
+ u32 nyet :1;
+ u32 xacterr :1;
+ u32 bblerr :1;
+ u32 frmovrun :1;
+ u32 datatglerr :1;
+ u32 reserved :21;
+ }b;
+}hcintn_t;
+
+
+typedef union _pcgcctl_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned stoppclk :1;
+ unsigned gatehclk :1;
+ unsigned pwrclmp :1;
+ unsigned rstpdwnmodule :1;
+ unsigned physuspended :1;
+ unsigned Reserved5_31 :27;
+ }b;
+}pcgcctl_t;
+
+
+typedef struct isoch_packet_desc
+{
+ u32 isoch_packiet_start_addr;// start address of buffer is buffer address + uiOffsert.
+ u32 buf_size;
+ u32 transferred_szie;
+ u32 isoch_status;
+}isoch_packet_desc_t;//, *isoch_packet_desc_t *,**isoch_packet_desc_t **;
+
+
+typedef struct standard_dev_req_info
+{
+ bool is_data_stage;
+ u8 conrol_transfer_stage;
+ u32 vir_standard_dev_req_addr;
+ u32 phy_standard_dev_req_addr;
+}standard_dev_req_info_t;
+
+
+typedef struct control_data_tgl_t
+{
+ u8 setup_tgl;
+ u8 data_tgl;
+ u8 status_tgl;
+}control_data_tgl_t;
+
+
+
+typedef struct ed_status
+{
+ u8 data_tgl;
+ control_data_tgl_t control_data_tgl;
+ bool is_ping_enable;
+ bool is_in_transfer_ready_q;
+ bool is_in_transferring;
+ u32 in_transferring_td;
+ bool is_alloc_resource_for_ed;
+}ed_status_t;//, *ed_status_t *,**ed_status_t **;
+
+
+typedef struct ed_desc
+{
+ u8 device_addr;
+ u8 endpoint_num;
+ bool is_ep_in;
+ u8 dev_speed;
+ u8 endpoint_type;
+ u16 max_packet_size;
+ u8 mc;
+ u8 interval;
+ u32 sched_frame;
+ u32 used_bus_time;
+ u8 hub_addr;
+ u8 hub_port;
+ bool is_do_split;
+}ed_dest_t;//, *ed_dest_t *,**ed_dest_t **;
+
+
+//Defines the Data Structures of Transfer.
+typedef struct hc_reg
+{
+
+ hcintmsk_t hc_int_msk;
+ hcintn_t hc_int;
+ u32 dma_addr;
+
+}hc_reg_t;//, *hc_reg_t *, **hc_reg_t **;
+
+
+typedef struct stransfer
+{
+ u32 stransfer_id;
+ u32 parent_td;
+ ed_dest_t *ed_desc_p;
+ ed_status_t *ed_status_p;
+ u32 start_vir_buf_addr;
+ u32 start_phy_buf_addr;
+ u32 buf_size;
+ u32 packet_cnt;
+ u8 alloc_chnum;
+ hc_reg_t hc_reg;
+}stransfer_t;//, *stransfer_t *,**stransfer_t **;
+
+
+typedef struct ed
+{
+ u32 ed_id;
+ bool is_halted;
+ bool is_need_to_insert_scheduler;
+ ed_dest_t ed_desc;
+ ed_status_t ed_status;
+ otg_list_head ed_list_entry;
+ otg_list_head td_list_entry;
+ otg_list_head trans_ready_q_list_entry;
+ u32 num_td;
+ void *ed_private;
+}ed_t;//, *ed_t *, **ed_t **;
+
+
+
+typedef struct td
+{
+ u32 td_id;
+ ed_t *parent_ed_p;
+ void *call_back_func_p;
+ void *call_back_func_param_p;
+ bool is_transferring;
+ bool is_transfer_done;
+ u32 transferred_szie;
+ bool is_standard_dev_req;
+ standard_dev_req_info_t standard_dev_req_info;
+ u32 vir_buf_addr;
+ u32 phy_buf_addr;
+ u32 buf_size;
+ u32 transfer_flag;
+ stransfer_t cur_stransfer;
+ USB_ERROR_CODE error_code;
+ u32 err_cnt;
+ otg_list_head td_list_entry;
+
+ //Isochronous Transfer Specific
+ u32 isoch_packet_num;
+ isoch_packet_desc_t *isoch_packet_desc_p;
+ u32 isoch_packet_index;
+ u32 isoch_packet_position;
+ u32 sched_frame;
+ u32 interval;
+ u32 used_total_bus_time;
+
+ // the private data can be used by S3C6400Interface.
+ void *td_private;
+}td_t;//, *td_t *,**td_t **;
+
+
+//Define Data Structures of Scheduler.
+typedef struct trans_ready_q
+{
+ bool is_periodic_transfer;
+ otg_list_head trans_ready_q_list_head;
+ u32 trans_ready_entry_num;
+
+ //In case of Periodic Transfer
+ u32 total_perio_bus_bandwidth;
+ u8 total_alloc_chnum;
+}trans_ready_q_t;//, *trans_ready_q_t *,**trans_ready_q_t **;
+
+
+//Define USB OTG Reg Data Structure by Kyuhyeok.
+
+#define MAX_COUNT 10000
+#define INT_ALL 0xffffffff
+
+typedef union _haint_t
+{
+ u32 d32;
+ struct
+ {
+ u32 channel_intr_0 :1;
+ u32 channel_intr_1 :1;
+ u32 channel_intr_2 :1;
+ u32 channel_intr_3 :1;
+ u32 channel_intr_4 :1;
+ u32 channel_intr_5 :1;
+ u32 channel_intr_6 :1;
+ u32 channel_intr_7 :1;
+ u32 channel_intr_8 :1;
+ u32 channel_intr_9 :1;
+ u32 channel_intr_10 :1;
+ u32 channel_intr_11 :1;
+ u32 channel_intr_12 :1;
+ u32 channel_intr_13 :1;
+ u32 channel_intr_14 :1;
+ u32 channel_intr_15 :1;
+ u32 reserved1 :16;
+ }b;
+}haint_t;
+
+typedef union _gresetctl_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned csftrst : 1;
+ unsigned hsftrst : 1;
+ unsigned hstfrm : 1;
+ unsigned intknqflsh : 1;
+ unsigned rxfflsh : 1;
+ unsigned txfflsh : 1;
+ unsigned txfnum : 5;
+ unsigned reserved11_29 : 19;
+ unsigned dmareq : 1;
+ unsigned ahbidle : 1;
+ } b;
+} gresetctl_t;
+
+
+typedef union _gahbcfg_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned glblintrmsk : 1;
+#define GAHBCFG_GLBINT_ENABLE 1
+ unsigned hburstlen : 4;
+#define INT_DMA_MODE_SINGLE 00
+#define INT_DMA_MODE_INCR 01
+#define INT_DMA_MODE_INCR4 03
+#define INT_DMA_MODE_INCR8 05
+#define INT_DMA_MODE_INCR16 07
+ unsigned dmaenable : 1;
+#define GAHBCFG_DMAENABLE 1
+ unsigned reserved : 1;
+ unsigned nptxfemplvl : 1;
+ unsigned ptxfemplvl : 1;
+#define GAHBCFG_TXFEMPTYLVL_EMPTY 1
+#define GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
+ unsigned reserved9_31 : 22;
+ } b;
+} gahbcfg_t;
+
+typedef union _gusbcfg_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned toutcal : 3;
+ unsigned phyif : 1;
+ unsigned ulpi_utmi_sel : 1;
+ unsigned fsintf : 1;
+ unsigned physel : 1;
+ unsigned ddrsel : 1;
+ unsigned srpcap : 1;
+ unsigned hnpcap : 1;
+ unsigned usbtrdtim : 4;
+ unsigned nptxfrwnden : 1;
+ unsigned phylpwrclksel : 1;
+ unsigned reserved : 13;
+ unsigned forcehstmode : 1;
+ unsigned reserved2 : 2;
+ } b;
+} gusbcfg_t;
+
+
+typedef union _ghwcfg2_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct {
+ /* GHWCFG2 */
+ unsigned op_mode : 3;
+#define MODE_HNP_SRP_CAPABLE 0
+#define MODE_SRP_ONLY_CAPABLE 1
+#define MODE_NO_HNP_SRP_CAPABLE 2
+#define MODE_SRP_CAPABLE_DEVICE 3
+#define MODE_NO_SRP_CAPABLE_DEVICE 4
+#define MODE_SRP_CAPABLE_HOST 5
+#define MODE_NO_SRP_CAPABLE_HOST 6
+
+ unsigned architecture : 2;
+#define HWCFG2_ARCH_SLAVE_ONLY 0x00
+#define HWCFG2_ARCH_EXT_DMA 0x01
+#define HWCFG2_ARCH_INT_DMA 0x02
+
+ unsigned point2point : 1;
+ unsigned hs_phy_type : 2;
+ unsigned fs_phy_type : 2;
+ unsigned num_dev_ep : 4;
+ unsigned num_host_chan : 4;
+ unsigned perio_ep_supported : 1;
+ unsigned dynamic_fifo : 1;
+ unsigned rx_status_q_depth : 2;
+ unsigned nonperio_tx_q_depth : 2;
+ unsigned host_perio_tx_q_depth : 2;
+ unsigned dev_token_q_depth : 5;
+ unsigned reserved31 : 1;
+ } b;
+} ghwcfg2_t;
+
+typedef union _gintsts_t
+{
+ /** raw register data */
+ u32 d32;
+#define SOF_INTR_MASK 0x0008
+ /** register bits */
+ struct
+ {
+#define HOST_MODE 1
+#define DEVICE_MODE 0
+ unsigned curmode : 1;
+#define OTG_HOST_MODE 1
+#define OTG_DEVICE_MODE 0
+
+ unsigned modemismatch : 1;
+ unsigned otgintr : 1;
+ unsigned sofintr : 1;
+ unsigned rxstsqlvl : 1;
+ unsigned nptxfempty : 1;
+ unsigned ginnakeff : 1;
+ unsigned goutnakeff : 1;
+ unsigned reserved8 : 1;
+ unsigned i2cintr : 1;
+ unsigned erlysuspend : 1;
+ unsigned usbsuspend : 1;
+ unsigned usbreset : 1;
+ unsigned enumdone : 1;
+ unsigned isooutdrop : 1;
+ unsigned eopframe : 1;
+ unsigned intokenrx : 1;
+ unsigned epmismatch : 1;
+ unsigned inepint : 1;
+ unsigned outepintr : 1;
+ unsigned incompisoin : 1;
+ unsigned incompisoout : 1;
+ unsigned reserved22_23 : 2;
+ unsigned portintr : 1;
+ unsigned hcintr : 1;
+ unsigned ptxfempty : 1;
+ unsigned reserved27 : 1;
+ unsigned conidstschng : 1;
+ unsigned disconnect : 1;
+ unsigned sessreqintr : 1;
+ unsigned wkupintr : 1;
+ } b;
+} gintsts_t;
+
+
+typedef union _hcfg_t
+{
+ /** raw register data */
+ u32 d32;
+
+ /** register bits */
+ struct
+ {
+ /** FS/LS Phy Clock Select */
+ unsigned fslspclksel : 2;
+#define HCFG_30_60_MHZ 0
+#define HCFG_48_MHZ 1
+#define HCFG_6_MHZ 2
+
+ /** FS/LS Only Support */
+ unsigned fslssupp : 1;
+ unsigned reserved3_31 : 29;
+ } b;
+} hcfg_t;
+
+typedef union _hprt_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned prtconnsts : 1;
+ unsigned prtconndet : 1;
+ unsigned prtena : 1;
+ unsigned prtenchng : 1;
+ unsigned prtovrcurract : 1;
+ unsigned prtovrcurrchng : 1;
+ unsigned prtres : 1;
+ unsigned prtsusp : 1;
+ unsigned prtrst : 1;
+ unsigned reserved9 : 1;
+ unsigned prtlnsts : 2;
+ unsigned prtpwr : 1;
+ unsigned prttstctl : 4;
+ unsigned prtspd : 2;
+#define HPRT0_PRTSPD_HIGH_SPEED 0
+#define HPRT0_PRTSPD_FULL_SPEED 1
+#define HPRT0_PRTSPD_LOW_SPEED 2
+ unsigned reserved19_31 : 13;
+ } b;
+} hprt_t;
+
+
+typedef union _gintmsk_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned reserved0 : 1;
+ unsigned modemismatch : 1;
+ unsigned otgintr : 1;
+ unsigned sofintr : 1;
+ unsigned rxstsqlvl : 1;
+ unsigned nptxfempty : 1;
+ unsigned ginnakeff : 1;
+ unsigned goutnakeff : 1;
+ unsigned reserved8 : 1;
+ unsigned i2cintr : 1;
+ unsigned erlysuspend : 1;
+ unsigned usbsuspend : 1;
+ unsigned usbreset : 1;
+ unsigned enumdone : 1;
+ unsigned isooutdrop : 1;
+ unsigned eopframe : 1;
+ unsigned reserved16 : 1;
+ unsigned epmismatch : 1;
+ unsigned inepintr : 1;
+ unsigned outepintr : 1;
+ unsigned incompisoin : 1;
+ unsigned incompisoout : 1;
+ unsigned reserved22_23 : 2;
+ unsigned portintr : 1;
+ unsigned hcintr : 1;
+ unsigned ptxfempty : 1;
+ unsigned reserved27 : 1;
+ unsigned conidstschng : 1;
+ unsigned disconnect : 1;
+ unsigned sessreqintr : 1;
+ unsigned wkupintr : 1;
+ } b;
+} gintmsk_t;
+
+
+typedef struct _hc_t
+{
+
+ u8 hc_num; // Host channel number used for register address lookup
+
+ unsigned dev_addr : 7; // Device to access
+ unsigned ep_is_in : 1; // EP direction; 0: OUT, 1: IN
+
+ unsigned ep_num : 4; // EP to access
+ unsigned low_speed : 1; // 1: Low speed, 0: Not low speed
+ unsigned ep_type : 2; // Endpoint type.
+ // One of the following values:
+ // - OTG_EP_TYPE_CONTROL: 0
+ // - OTG_EP_TYPE_ISOC: 1
+ // - OTG_EP_TYPE_BULK: 2
+ // - OTG_EP_TYPE_INTR: 3
+
+ unsigned rsvdb1 : 1; // 8 bit padding
+
+ u8 rsvd2; // 4 byte boundary
+
+ unsigned max_packet : 12; // Max packet size in bytes
+
+ unsigned data_pid_start : 2;
+#define OTG_HC_PID_DATA0 0
+#define OTG_HC_PID_DATA2 1
+#define OTG_HC_PID_DATA1 2
+#define OTG_HC_PID_MDATA 3
+#define OTG_HC_PID_SETUP 3
+
+ unsigned multi_count : 2; // Number of periodic transactions per (micro)frame
+
+
+ // Flag to indicate whether the transfer has been started. Set to 1 if
+ // it has been started, 0 otherwise.
+ u8 xfer_started;
+
+
+ // Set to 1 to indicate that a PING request should be issued on this
+ // channel. If 0, process normally.
+ u8 do_ping;
+
+ // Set to 1 to indicate that the error count for this transaction is
+ // non-zero. Set to 0 if the error count is 0.
+ u8 error_state;
+ u32 *xfer_buff; // Pointer to the current transfer buffer position.
+ u16 start_pkt_count; // Packet count at start of transfer.
+
+ u32 xfer_len; // Total number of bytes to transfer.
+ u32 xfer_count; // Number of bytes transferred so far.
+
+
+ // Set to 1 if the host channel has been halted, but the core is not
+ // finished flushing queued requests. Otherwise 0.
+ u8 halt_pending;
+ u8 halt_status; // Reason for halting the host channel
+ u8 short_read; // Set when the host channel does a short read.
+ u8 rsvd3; // 4 byte boundary
+
+} hc_t;
+
+
+// Port status for the HC
+#define HCD_DRIVE_RESET 0x0001
+#define HCD_SEND_SETUP 0x0002
+
+#define HC_MAX_PKT_COUNT 511
+#define HC_MAX_TRANSFER_SIZE 65535
+#define MAXP_SIZE_64BYTE 64
+#define MAXP_SIZE_512BYTE 512
+#define MAXP_SIZE_1024BYTE 1024
+
+typedef union _hcchar_t
+{
+ // raw register data
+ u32 d32;
+
+ // register bits
+ struct
+ {
+ // Maximum packet size in bytes
+ unsigned mps : 11;
+
+ // Endpoint number
+ unsigned epnum : 4;
+
+ // 0: OUT, 1: IN
+ unsigned epdir : 1;
+#define HCDIR_OUT 0
+#define HCDIR_IN 1
+
+ unsigned reserved : 1;
+
+ // 0: Full/high speed device, 1: Low speed device
+ unsigned lspddev : 1;
+
+ // 0: Control, 1: Isoc, 2: Bulk, 3: Intr
+ unsigned eptype : 2;
+#define OTG_EP_TYPE_CONTROL 0
+#define OTG_EP_TYPE_ISOC 1
+#define OTG_EP_TYPE_BULK 2
+#define OTG_EP_TYPE_INTR 3
+
+ // Packets per frame for periodic transfers. 0 is reserved.
+ unsigned multicnt : 2;
+
+ // Device address
+ unsigned devaddr : 7;
+
+ // Frame to transmit periodic transaction.
+ // 0: even, 1: odd
+ unsigned oddfrm : 1;
+
+ // Channel disable
+ unsigned chdis : 1;
+
+ // Channel enable
+ unsigned chen : 1;
+ } b;
+} hcchar_t;
+
+typedef union _hctsiz_t
+{
+ // raw register data
+ u32 d32;
+
+ // register bits
+ struct
+ {
+ // Total transfer size in bytes
+ unsigned xfersize : 19;
+
+ // Data packets to transfer
+ unsigned pktcnt : 10;
+
+ // Packet ID for next data packet
+ // 0: DATA0
+ // 1: DATA2
+ // 2: DATA1
+ // 3: MDATA (non-Control), SETUP (Control)
+ unsigned pid : 2;
+#define HCTSIZ_DATA0 0
+#define HCTSIZ_DATA1 2
+#define HCTSIZ_DATA2 1
+#define HCTSIZ_MDATA 3
+#define HCTSIZ_SETUP 3
+
+ // Do PING protocol when 1
+ unsigned dopng : 1;
+ } b;
+} hctsiz_t;
+
+
+
+typedef union _grxstsr_t
+{
+ // raw register data
+ u32 d32;
+
+ // register bits
+ struct
+ {
+ unsigned chnum : 4;
+ unsigned bcnt : 11;
+ unsigned dpid : 2;
+ unsigned pktsts : 4;
+ unsigned Reserved : 11;
+ } b;
+} grxstsr_t;
+
+typedef union _hfir_t
+{
+ // raw register data
+ u32 d32;
+
+ // register bits
+ struct
+ {
+ unsigned frint : 16;
+ unsigned Reserved : 16;
+ } b;
+} hfir_t;
+
+typedef union _hfnum_t
+{
+ // raw register data
+ u32 d32;
+
+ // register bits
+ struct
+ {
+ unsigned frnum : 16;
+#define HFNUM_MAX_FRNUM 0x3FFF
+ unsigned frrem : 16;
+ } b;
+} hfnum_t;
+
+typedef union grstctl_t
+{
+ /** raw register data */
+ u32 d32;
+ /** register bits */
+ struct
+ {
+ unsigned csftrst : 1;
+ unsigned hsftrst : 1;
+ unsigned hstfrm : 1;
+ unsigned intknqflsh : 1;
+ unsigned rxfflsh : 1;
+ unsigned txfflsh : 1;
+ unsigned txfnum : 5;
+ unsigned reserved11_29 : 19;
+ unsigned dmareq : 1;
+ unsigned ahbidle : 1;
+ } b;
+} grstctl_t;
+
+typedef struct hc_info
+{
+ hcintmsk_t hc_int_msk;
+ hcintn_t hc_int;
+ u32 dma_addr;
+ hcchar_t hc_char;
+ hctsiz_t hc_size;
+}hc_info_t;//, *hc_info_t *, **hc_info_t **;
+
+#ifndef USB_MAXCHILDREN
+ #define USB_MAXCHILDREN (31)
+#endif
+
+typedef struct _usb_hub_descriptor_t
+{
+ u8 desc_length;
+ u8 desc_type;
+ u8 port_number;
+ u16 hub_characteristics;
+ u8 power_on_to_power_good;
+ u8 hub_control_current;
+ /* add 1 bit for hub status change; round to bytes */
+ u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
+ u8 port_pwr_ctrl_mask[(USB_MAXCHILDREN + 1 + 7) / 8];
+}usb_hub_descriptor_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-common-errorcode.h b/drivers/usb/host/s3c-otg/s3c-otg-common-errorcode.h
new file mode 100644
index 0000000..b2b3bee
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-common-errorcode.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : s3c-otg-common-errorcode.h
+ * [Description] : The Header file defines Error Codes to be used at sub-modules of S3C6400HCD.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/03
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file.
+ * (2) 2008/08/18 by SeungSoo Yang ( ss1.yang@samsung.com )
+ * - add HCD error code
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _ERROR_CODE_DEF_H
+#define _ERROR_CODE_DEF_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-common.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+typedef int USB_ERROR_CODE;
+
+//General USB Error Code.
+#define USB_ERR_SUCCESS 0
+#define USB_ERR_FAIL -1
+
+#define USB_ERR_NO 1
+
+#define USB_ERR_NO_ENTITY -2
+
+//S3CTransfer Error Code
+#define USB_ERR_NODEV -ENODEV
+#define USB_ERR_NOMEM -ENOMEM
+#define USB_ERR_NOSPACE -ENOSPC
+#define USB_ERR_NOIO -EIO
+
+//OTG-HCD error code
+#define USB_ERR_NOELEMENT -ENOENT
+#define USB_ERR_ESHUTDOWN -ESHUTDOWN /* unplug */
+#define USB_ERR_DEQUEUED -ECONNRESET /* unlink */
+
+
+//S3CScheduler Error Code
+#define USB_ERR_ALREADY_EXIST -1
+#define USB_ERR_NO_RESOURCE -2
+#define USB_ERR_NO_CHANNEL -3
+#define USB_ERR_NO_BANDWIDTH -4
+#define USB_ERR_ALL_RESROUCE -5
+
+
+
+
+/************************************************
+ *Defines the USB Error Status Code of USB Transfer.
+ ************************************************/
+
+//#ifdef LINUX
+
+#define USB_ERR_STATUS_COMPLETE 0
+#define USB_ERR_STATUS_INPROGRESS -EINPROGRESS
+#define USB_ERR_STATUS_CRC -EILSEQ
+#define USB_ERR_STATUS_XACTERR -EPROTO
+#define USB_ERR_STATUS_STALL -EPIPE
+#define USB_ERR_STATUS_BBLERR -EOVERFLOW
+#define USB_ERR_STATUS_AHBERR -EIO
+#define USB_ERR_STATUS_FRMOVRUN_OUT -ENOSR
+#define USB_ERR_STATUS_FRMOVRUN_IN -ECOMM
+#define USB_ERR_STATUS_SHORTREAD -EREMOTEIO
+
+//#else
+
+//#endif
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-common-regdef.h b/drivers/usb/host/s3c-otg/s3c-otg-common-regdef.h
new file mode 100644
index 0000000..ed119d7
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-common-regdef.h
@@ -0,0 +1,302 @@
+/****************************************************************************
+* (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+*
+* [File Name] : s3c-otg-common-regdef.h
+* [Description] :
+*
+* [Author] : Kyu Hyeok Jang { kyuhyeok.jang@samsung.com }
+* [Department] : System LSI Division/Embedded Software Center
+* [Created Date]: 2007/12/15
+* [Revision History]
+* (1) 2007/12/15 by Kyu Hyeok Jang { kyuhyeok.jang@samsung.com }
+* - Created
+*
+****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _OTG_REG_DEF_H
+#define _OTG_REG_DEF_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct {
+ u32 OPHYPWR;
+ u32 OPHYCLK;
+ u32 ORSTCON;
+}OTG_PHY_REG, *PS_OTG_PHY_REG;
+
+#define GOTGCTL 0x000 // OTG Control & Status
+#define GOTGINT 0x004 // OTG Interrupt
+#define GAHBCFG 0x008 // Core AHB Configuration
+#define GUSBCFG 0x00C // Core USB Configuration
+#define GRSTCTL 0x010 // Core Reset
+#define GINTSTS 0x014 // Core Interrupt
+#define GINTMSK 0x018 // Core Interrupt Mask
+#define GRXSTSR 0x01C // Receive Status Debug Read/Status Read
+#define GRXSTSP 0x020 // Receive Status Debug Pop/Status Pop
+#define GRXFSIZ 0x024 // Receive FIFO Size
+#define GNPTXFSIZ 0x028 // Non-Periodic Transmit FIFO Size
+#define GNPTXSTS 0x02C // Non-Periodic Transmit FIFO/Queue Status
+#define GPVNDCTL 0x034 // PHY Vendor Control
+#define GGPIO 0x038 // General Purpose I/O
+#define GUID 0x03C // User ID
+#define GSNPSID 0x040 // Synopsys ID
+#define GHWCFG1 0x044 // User HW Config1
+#define GHWCFG2 0x048 // User HW Config2
+#define GHWCFG3 0x04C // User HW Config3
+#define GHWCFG4 0x050 // User HW Config4
+
+#define HPTXFSIZ 0x100 // Host Periodic Transmit FIFO Size
+#define DPTXFSIZ1 0x104 // Device Periodic Transmit FIFO-1 Size
+#define DPTXFSIZ2 0x108 // Device Periodic Transmit FIFO-2 Size
+#define DPTXFSIZ3 0x10C // Device Periodic Transmit FIFO-3 Size
+#define DPTXFSIZ4 0x110 // Device Periodic Transmit FIFO-4 Size
+#define DPTXFSIZ5 0x114 // Device Periodic Transmit FIFO-5 Size
+#define DPTXFSIZ6 0x118 // Device Periodic Transmit FIFO-6 Size
+#define DPTXFSIZ7 0x11C // Device Periodic Transmit FIFO-7 Size
+#define DPTXFSIZ8 0x120 // Device Periodic Transmit FIFO-8 Size
+#define DPTXFSIZ9 0x124 // Device Periodic Transmit FIFO-9 Size
+#define DPTXFSIZ10 0x128 // Device Periodic Transmit FIFO-10 Size
+#define DPTXFSIZ11 0x12C // Device Periodic Transmit FIFO-11 Size
+#define DPTXFSIZ12 0x130 // Device Periodic Transmit FIFO-12 Size
+#define DPTXFSIZ13 0x134 // Device Periodic Transmit FIFO-13 Size
+#define DPTXFSIZ14 0x138 // Device Periodic Transmit FIFO-14 Size
+#define DPTXFSIZ15 0x13C // Device Periodic Transmit FIFO-15 Size
+
+//*********************************************************************
+// Host Mode Registers
+//*********************************************************************
+// Host Global Registers
+
+// Channel specific registers
+#define HCCHAR_ADDR 0x500
+#define HCCHAR(n) 0x500 + ((n)*0x20)
+#define HCSPLT(n) 0x504 + ((n)*0x20)
+#define HCINT(n) 0x508 + ((n)*0x20)
+#define HCINTMSK(n) 0x50C + ((n)*0x20)
+#define HCTSIZ(n) 0x510 + ((n)*0x20)
+#define HCDMA(n) 0x514 + ((n)*0x20)
+
+#define HCFG 0x400 // Host Configuration
+#define HFIR 0x404 // Host Frame Interval
+#define HFNUM 0x408 // Host Frame Number/Frame Time Remaining
+#define HPTXSTS 0x410 // Host Periodic Transmit FIFO/Queue Status
+#define HAINT 0x414 // Host All Channels Interrupt
+#define HAINTMSK 0x418 // Host All Channels Interrupt Mask
+
+// Host Port Control & Status Registers
+
+#define HPRT 0x440 // Host Port Control & Status
+
+// Device Logical Endpoints-Specific Registers
+
+#define DIEPCTL 0x900 // Device IN Endpoint 0 Control
+#define DOEPCTL(n) 0xB00 + ((n)*0x20)) // Device OUT Endpoint 0 Control
+#define DIEPINT(n) 0x908 + ((n)*0x20)) // Device IN Endpoint 0 Interrupt
+#define DOEPINT(n) 0xB08 + ((n)*0x20)) // Device OUT Endpoint 0 Interrupt
+#define DIEPTSIZ(n) 0x910 + ((n)*0x20)) // Device IN Endpoint 0 Transfer Size
+#define DOEPTSIZ(n) 0xB10 + ((n)*0x20)) // Device OUT Endpoint 0 Transfer Size
+#define DIEPDMA(n) 0x914 + ((n)*0x20)) // Device IN Endpoint 0 DMA Address
+#define DOEPDMA(n) 0xB14 + ((n)*0x20)) // Device OUT Endpoint 0 DMA Address
+
+#define EP_FIFO(n) 0x1000 + ((n)*0x1000))
+
+#define PCGCCTL 0x0E00
+
+//
+#define BASE_REGISTER_OFFSET 0x0
+#define REGISTER_SET_SIZE 0x200
+
+// Power Reg Bits
+#define USB_RESET 0x8
+#define MCU_RESUME 0x4
+#define SUSPEND_MODE 0x2
+#define SUSPEND_MODE_ENABLE_CTRL 0x1
+
+// EP0 CSR
+#define EP0_OUT_PACKET_RDY 0x1
+#define EP0_IN_PACKET_RDY 0x2
+#define EP0_SENT_STALL 0x4
+#define DATA_END 0x8
+#define SETUP_END 0x10
+#define EP0_SEND_STALL 0x20
+#define SERVICED_OUT_PKY_RDY 0x40
+#define SERVICED_SETUP_END 0x80
+
+// IN_CSR1_REG Bit definitions
+#define IN_PACKET_READY 0x1
+#define UNDER_RUN 0x4 // Iso Mode Only
+#define FLUSH_IN_FIFO 0x8
+#define IN_SEND_STALL 0x10
+#define IN_SENT_STALL 0x20
+#define IN_CLR_DATA_TOGGLE 0x40
+
+// OUT_CSR1_REG Bit definitions
+#define OUT_PACKET_READY 0x1
+#define FLUSH_OUT_FIFO 0x10
+#define OUT_SEND_STALL 0x20
+#define OUT_SENT_STALL 0x40
+#define OUT_CLR_DATA_TOGGLE 0x80
+
+// IN_CSR2_REG Bit definitions
+#define IN_DMA_INT_DISABLE 0x10
+#define SET_MODE_IN 0x20
+
+#define EPTYPE (0x3<<18)
+#define SET_TYPE_CONTROL (0x0<<18)
+#define SET_TYPE_ISO (0x1<<18)
+#define SET_TYPE_BULK (0x2<<18)
+#define SET_TYPE_INTERRUPT (0x3<<18)
+
+#define AUTO_MODE 0x80
+
+// OUT_CSR2_REG Bit definitions
+#define AUTO_CLR 0x40
+#define OUT_DMA_INT_DISABLE 0x20
+
+// Can be used for Interrupt and Interrupt Enable Reg - common bit def
+#define EP0_IN_INT (0x1<<0)
+#define EP1_IN_INT (0x1<<1)
+#define EP2_IN_INT (0x1<<2)
+#define EP3_IN_INT (0x1<<3)
+#define EP4_IN_INT (0x1<<4)
+#define EP5_IN_INT (0x1<<5)
+#define EP6_IN_INT (0x1<<6)
+#define EP7_IN_INT (0x1<<7)
+#define EP8_IN_INT (0x1<<8)
+#define EP9_IN_INT (0x1<<9)
+#define EP10_IN_INT (0x1<<10)
+#define EP11_IN_INT (0x1<<11)
+#define EP12_IN_INT (0x1<<12)
+#define EP13_IN_INT (0x1<<13)
+#define EP14_IN_INT (0x1<<14)
+#define EP15_IN_INT (0x1<<15)
+#define EP0_OUT_INT (0x1<<16)
+#define EP1_OUT_INT (0x1<<17)
+#define EP2_OUT_INT (0x1<<18)
+#define EP3_OUT_INT (0x1<<19)
+#define EP4_OUT_INT (0x1<<20)
+#define EP5_OUT_INT (0x1<<21)
+#define EP6_OUT_INT (0x1<<22)
+#define EP7_OUT_INT (0x1<<23)
+#define EP8_OUT_INT (0x1<<24)
+#define EP9_OUT_INT (0x1<<25)
+#define EP10_OUT_INT (0x1<<26)
+#define EP11_OUT_INT (0x1<<27)
+#define EP12_OUT_INT (0x1<<28)
+#define EP13_OUT_INT (0x1<<29)
+#define EP14_OUT_INT (0x1<<30)
+#define EP15_OUT_INT (0x1<<31)
+
+// GOTGINT
+#define SesEndDet (0x1<<2)
+
+// GRSTCTL
+#define TxFFlsh (0x1<<5)
+#define RxFFlsh (0x1<<4)
+#define INTknQFlsh (0x1<<3)
+#define FrmCntrRst (0x1<<2)
+#define HSftRst (0x1<<1)
+#define CSftRst (0x1<<0)
+
+#define CLEAR_ALL_EP_INTRS 0xffffffff
+
+#define EP_INTERRUPT_DISABLE_ALL 0x0 // Bits to write to EP_INT_EN_REG - Use CLEAR
+
+// DMA control register bit definitions
+#define RUN_OB 0x80
+#define STATE 0x70
+#define DEMAND_MODE 0x8
+#define OUT_DMA_RUN 0x4
+#define IN_DMA_RUN 0x2
+#define DMA_MODE_EN 0x1
+
+
+#define REAL_PHYSICAL_ADDR_EP0_FIFO (0x520001c0) //Endpoint 0 FIFO
+#define REAL_PHYSICAL_ADDR_EP1_FIFO (0x520001c4) //Endpoint 1 FIFO
+#define REAL_PHYSICAL_ADDR_EP2_FIFO (0x520001c8) //Endpoint 2 FIFO
+#define REAL_PHYSICAL_ADDR_EP3_FIFO (0x520001cc) //Endpoint 3 FIFO
+#define REAL_PHYSICAL_ADDR_EP4_FIFO (0x520001d0) //Endpoint 4 FIFO
+
+// GAHBCFG
+#define MODE_DMA (1<<5)
+#define MODE_SLAVE (0<<5)
+#define BURST_SINGLE (0<<1)
+#define BURST_INCR (1<<1)
+#define BURST_INCR4 (3<<1)
+#define BURST_INCR8 (5<<1)
+#define BURST_INCR16 (7<<1)
+#define GBL_INT_MASK (0<<0)
+#define GBL_INT_UNMASK (1<<0)
+
+// For USB DMA
+//BOOL InitUsbdDriverGlobals(void); //:-)
+//void UsbdDeallocateVm(void); //:-)
+//BOOL UsbdAllocateVm(void); //:-)
+//void UsbdInitDma(int epnum, int bufIndex,int bufOffset); //:-)
+
+
+//by Kevin
+
+//////////////////////////////////////////////////////////////////////////
+
+/*
+inline u32 ReadReg(
+ u32 uiOffset
+ )
+{
+ volatile u32 *pbReg = ctrlr_base_reg_addr(uiOffset);
+ u32 uiValue = (u32) *pbReg;
+ return uiValue;
+}
+
+inline void WriteReg(
+ u32 uiOffset,
+ u32 bValue
+ )
+{
+ volatile ULONG *pbReg = ctrlr_base_reg_addr(uiOffset);
+ *pbReg = (ULONG) bValue;
+}
+
+inline void UpdateReg(
+ u32 uiOffset,
+ u32 bValue
+ )
+{
+ WriteReg(uiOffset, (ReadReg(uiOffset) | bValue));
+};
+
+inline void ClearReg(
+ u32 uiOffeset,
+ u32 bValue
+ )
+{
+ WriteReg(uiOffeset, (ReadReg(uiOffeset) & ~bValue));
+};
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-debug.h b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-debug.h
new file mode 100644
index 0000000..20416b1
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-debug.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-debug.c
+ * @brief It provides debug functions for display message \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_HCDI_DEBUG_H_
+#define _S3C_OTG_HCDI_DEBUG_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define OTG_DEBUG
+
+#ifdef OTG_DEBUG
+#if 0
+#include <linux/stddef.h>
+#endif
+
+#define OTG_DBG_OTGHCDI_DRIVER true
+#define OTG_DBG_OTGHCDI_HCD false
+#define OTG_DBG_OTGHCDI_KAL false
+#define OTG_DBG_OTGHCDI_LIST false
+#define OTG_DBG_OTGHCDI_MEM false
+
+#define OTG_DBG_TRANSFER false
+#define OTG_DBG_SCHEDULE false
+#define OTG_DBG_OCI false
+#define OTG_DBG_DONETRASF false
+#define OTG_DBG_ISR false
+#define OTG_DBG_ROOTHUB false
+
+
+#include <linux/kernel.h> //for printk
+
+#define otg_err(is_active, msg...) \
+ do{ if (/*(is_active) == */true)\
+ {\
+ pr_err("otg_err: in %s()::%05d ", __func__ , __LINE__); \
+ pr_err("=> " msg); \
+ }\
+ }while(0)
+
+#define otg_dbg(is_active, msg...) \
+ do{ if ((is_active) == true)\
+ {\
+ pr_info("otg_dbg: in %s()::%05d ", __func__, __LINE__); \
+ pr_info("=> " msg); \
+ }\
+ }while(0)
+
+#else //OTG_DEBUG
+
+# define otg_err(is_active, msg...) do{}while(0)
+# define otg_dbg(is_active, msg...) do{}while(0)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _S3C_OTG_HCDI_DEBUG_H_ */
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.c b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.c
new file mode 100644
index 0000000..09ee1a3
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.c
@@ -0,0 +1,379 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-driver.c
+ * @brief It provides functions related with module for OTGHCD driver. \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Modifying for successful rmmod & disconnecting \n
+ * @see None
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-hcdi-driver.h"
+extern void otg_phy_off(void);
+
+/**
+ * static int s5pc110_otg_drv_probe (struct platform_device *pdev)
+ *
+ * @brief probe function of OTG hcd platform_driver
+ *
+ * @param [in] pdev : pointer of platform_device of otg hcd platform_driver
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If fail \n
+ * @remark
+ * it allocates resources of it and call other modules' init function.
+ * then call usb_create_hcd, usb_add_hcd, s5pc110_otghcd_start functions
+ */
+
+struct usb_hcd* g_pUsbHcd = NULL;
+
+static void otg_power_work(struct work_struct *work)
+{
+ struct sec_otghost *otghost = container_of(work,
+ struct sec_otghost, work);
+ struct sec_otghost_data *hdata = otghost->otg_data;
+
+ if (hdata && hdata->set_pwr_cb) {
+ hdata->set_pwr_cb(0);
+#ifdef CONFIG_USB_HOST_NOTIFY
+ if (g_pUsbHcd)
+ host_state_notify(&g_pUsbHcd->ndev, NOTIFY_HOST_OVERCURRENT);
+#endif
+ } else {
+ otg_err(true, "invalid otghost data\n");
+ }
+}
+
+static int s5pc110_otg_drv_probe (struct platform_device *pdev)
+{
+ int ret_val = 0;
+ u32 reg_val = 0;
+ struct sec_otghost *otghost = NULL;
+ struct sec_otghost_data *otg_data = dev_get_platdata(&pdev->dev);
+
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER, "s3c_otg_drv_probe\n");
+
+
+ /*init for host mode*/
+ /**
+ Allocate memory for the base HCD & Initialize the base HCD.
+ */
+ g_pUsbHcd = usb_create_hcd(&s5pc110_otg_hc_driver, &pdev->dev,
+ "s3cotg");/*pdev->dev.bus_id*/
+ if (g_pUsbHcd == NULL) {
+ ret_val = -ENOMEM;
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "failed to usb_create_hcd\n");
+ goto err_out_clk;
+ }
+
+ /* mapping hcd resource & device resource*/
+
+ g_pUsbHcd->rsrc_start = pdev->resource[0].start;
+ g_pUsbHcd->rsrc_len = pdev->resource[0].end -
+ pdev->resource[0].start + 1;
+
+ if (!request_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len,
+ gHcdName)) {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "failed to request_mem_region\n");
+ ret_val = -EBUSY;
+ goto err_out_create_hcd;
+ }
+
+
+ /* Physical address => Virtual address */
+ g_pUsbHcd->regs = S3C_VA_OTG;
+ g_pUsbHcd->self.otg_port = 1;
+
+ g_pUDCBase = (u8 *)g_pUsbHcd->regs;
+
+ otghost = hcd_to_sec_otghost(g_pUsbHcd);
+
+ if (otghost == NULL) {
+ otg_err(true, "failed to get otghost hcd\n");
+ ret_val = USB_ERR_FAIL;
+ goto err_out_create_hcd;
+ }
+ otghost->otg_data = otg_data;
+
+ INIT_WORK(&otghost->work, otg_power_work);
+ otghost->wq = create_singlethread_workqueue("sec_otghostd");
+
+ /* call others' init() */
+ ret_val = otg_hcd_init_modules(otghost);
+ if (ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "failed to otg_hcd_init_modules\n");
+ ret_val = USB_ERR_FAIL;
+ goto err_out_create_hcd;
+ }
+
+ /**
+ * Attempt to ensure this device is really a s5pc110 USB-OTG Controller.
+ * Read and verify the SNPSID register contents. The value should be
+ * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX".
+ */
+ reg_val = read_reg_32(0x40);
+ if ((reg_val & 0xFFFFF000) != 0x4F542000) {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "Bad value for SNPSID: 0x%x\n", reg_val);
+ ret_val = -EINVAL;
+ goto err_out_create_hcd_init;
+ }
+#ifdef CONFIG_USB_HOST_NOTIFY
+ if (otg_data->host_notify) {
+ g_pUsbHcd->host_notify = otg_data->host_notify;
+ g_pUsbHcd->ndev.name = dev_name(&pdev->dev);
+ ret_val = host_notify_dev_register(&g_pUsbHcd->ndev);
+ if (ret_val) {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "Failed to host_notify_dev_register\n");
+ goto err_out_create_hcd_init;
+ }
+ }
+#endif
+#ifdef CONFIG_USB_SEC_WHITELIST
+ if (otg_data->sec_whlist_table_num)
+ g_pUsbHcd->sec_whlist_table_num = otg_data->sec_whlist_table_num;
+#endif
+
+ /*
+ * Finish generic HCD initialization and start the HCD. This function
+ * allocates the DMA buffer pool, registers the USB bus, requests the
+ * IRQ line, and calls s5pc110_otghcd_start method.
+ */
+ ret_val = usb_add_hcd(g_pUsbHcd,
+ pdev->resource[1].start, IRQF_DISABLED);
+ if (ret_val < 0) {
+ goto err_out_host_notify_register;
+ }
+
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "OTG HCD Initialized HCD, bus=%s, usbbus=%d\n",
+ "C110 OTG Controller", g_pUsbHcd->self.busnum);
+
+ /* otg_print_registers(); */
+
+ wake_lock_init(&otghost->wake_lock, WAKE_LOCK_SUSPEND, "usb_otg");
+ wake_lock(&otghost->wake_lock);
+
+ return USB_ERR_SUCCESS;
+err_out_host_notify_register:
+#ifdef CONFIG_USB_HOST_NOTIFY
+ host_notify_dev_unregister(&g_pUsbHcd->ndev);
+#endif
+
+err_out_create_hcd_init:
+ otg_hcd_deinit_modules(otghost);
+ release_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len);
+
+err_out_create_hcd:
+ usb_put_hcd(g_pUsbHcd);
+
+err_out_clk:
+
+ return ret_val;
+}
+
+/**
+ * static int s5pc110_otg_drv_remove (struct platform_device *dev)
+ *
+ * @brief remove function of OTG hcd platform_driver
+ *
+ * @param [in] pdev : pointer of platform_device of otg hcd platform_driver
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If fail \n
+ * @remark
+ * This function is called when the otg device unregistered with the
+ * s5pc110_otg_driver. This happens, for example, when the rmmod command is
+ * executed. The device may or may not be electrically present. If it is
+ * present, the driver stops device processing. Any resources used on behalf
+ * of this device are freed.
+ */
+static int s5pc110_otg_drv_remove (struct platform_device *dev)
+{
+ struct sec_otghost *otghost = NULL;
+
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER, "s5pc110_otg_drv_remove\n");
+
+ otghost = hcd_to_sec_otghost(g_pUsbHcd);
+
+#ifdef CONFIG_USB_HOST_NOTIFY
+ host_notify_dev_unregister(&g_pUsbHcd->ndev);
+#endif
+
+ otg_hcd_deinit_modules(otghost);
+
+ destroy_workqueue(otghost->wq);
+
+ wake_unlock(&otghost->wake_lock);
+ wake_lock_destroy(&otghost->wake_lock);
+
+ usb_remove_hcd(g_pUsbHcd);
+
+ release_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len);
+
+ usb_put_hcd(g_pUsbHcd);
+
+ otg_phy_off();
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * @struct s5pc110_otg_driver
+ *
+ * @brief
+ * This structure defines the methods to be called by a bus driver
+ * during the lifecycle of a device on that bus. Both drivers and
+ * devices are registered with a bus driver. The bus driver matches
+ * devices to drivers based on information in the device and driver
+ * structures.
+ *
+ * The probe function is called when the bus driver matches a device
+ * to this driver. The remove function is called when a device is
+ * unregistered with the bus driver.
+ */
+struct platform_driver s5pc110_otg_driver = {
+ .probe = s5pc110_otg_drv_probe,
+ .remove = s5pc110_otg_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "s3c_otghcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+/**
+ * static int __init s5pc110_otg_module_init(void)
+ *
+ * @brief module_init function
+ *
+ * @return it returns result of platform_driver_register
+ * @remark
+ * This function is called when the s5pc110_otg_driver is installed with the
+ * insmod command. It registers the s5pc110_otg_driver structure with the
+ * appropriate bus driver. This will cause the s5pc110_otg_driver_probe function
+ * to be called. In addition, the bus driver will automatically expose
+ * attributes defined for the device and driver in the special sysfs file
+ * system.
+ */
+ /*
+static int __init s5pc110_otg_module_init(void)
+{
+ int ret_val = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "s3c_otg_module_init \n");
+
+ ret_val = platform_driver_register(&s5pc110_otg_driver);
+ if (ret_val < 0)
+ {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "platform_driver_register \n");
+ }
+ return ret_val;
+} */
+
+/**
+ * static void __exit s5pc110_otg_module_exit(void)
+ *
+ * @brief module_exit function
+ *
+ * @remark
+ * This function is called when the driver is removed from the kernel
+ * with the rmmod command. The driver unregisters itself with its bus
+ * driver.
+ */
+static void __exit s5pc110_otg_module_exit(void)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "s3c_otg_module_exit \n");
+ platform_driver_unregister(&s5pc110_otg_driver);
+}
+
+/* for debug */
+void otg_print_registers(void)
+{
+ /* USB PHY Control Registers */
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "USB_CONTROL = 0x%x.\n", readl(0xfb10e80c));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "UPHYPWR = 0x%x.\n", readl(S3C_USBOTG_PHYPWR));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "UPHYCLK = 0x%x.\n", readl(S3C_USBOTG_PHYCLK));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "URSTCON = 0x%x.\n", readl(S3C_USBOTG_RSTCON));
+
+ /* OTG LINK Core registers (Core Global Registers) */
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GOTGCTL = 0x%x.\n", read_reg_32(GOTGCTL));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GOTGINT = 0x%x.\n", read_reg_32(GOTGINT));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GAHBCFG = 0x%x.\n", read_reg_32(GAHBCFG));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GUSBCFG = 0x%x.\n", read_reg_32(GUSBCFG));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GINTSTS = 0x%x.\n", read_reg_32(GINTSTS));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GINTMSK = 0x%x.\n", read_reg_32(GINTMSK));
+
+ /* Host Mode Registers */
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "HCFG = 0x%x.\n", read_reg_32(HCFG));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "HPRT = 0x%x.\n", read_reg_32(HPRT));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "HFIR = 0x%x.\n", read_reg_32(HFIR));
+
+ /* Synopsys ID */
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GSNPSID = 0x%x.\n", read_reg_32(GSNPSID));
+
+ /* HWCFG */
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GHWCFG1 = 0x%x.\n", read_reg_32(GHWCFG1));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GHWCFG2 = 0x%x.\n", read_reg_32(GHWCFG2));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GHWCFG3 = 0x%x.\n", read_reg_32(GHWCFG3));
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "GHWCFG4 = 0x%x.\n", read_reg_32(GHWCFG4));
+
+ /* PCGCCTL */
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER,
+ "PCGCCTL = 0x%x.\n", read_reg_32(PCGCCTL));
+}
+
+/*
+module_init(s5pc110_otg_module_init);
+module_exit(s5pc110_otg_module_exit);
+*/
+
+MODULE_DESCRIPTION("OTG USB HOST controller driver");
+MODULE_AUTHOR("SAMSUNG / System LSI / EMSP");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.h b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.h
new file mode 100644
index 0000000..4488df2
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-driver.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-driver.h
+ * @brief header of s3c-otg-hcdi-driver \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Modifying for successful rmmod & disconnecting \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_HCDI_DRIVER_H_
+#define _S3C_OTG_HCDI_DRIVER_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+//#include <linux/clk.h> //for clk_get, clk_enable etc.
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h> //for SA_SHIRQ
+#include <mach/map.h> //address for smdk
+#include <linux/dma-mapping.h> //dma_alloc_coherent
+#include <linux/ioport.h> //request_mem_request ...
+#include <asm/irq.h> //for IRQ_OTG
+#include <linux/clk.h>
+
+
+#include "s3c-otg-common-common.h"
+#include "s3c-otg-common-regdef.h"
+
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-hcdi-hcd.h"
+#include "s3c-otg-hcdi-kal.h"
+
+
+volatile u8 * g_pUDCBase;
+
+static const char gHcdName[] = "EMSP_OTG_HCD";
+
+//extern int otg_hcd_init_modules(struct sec_otghost *otghost);
+//extern void otg_hcd_deinit_modules(struct sec_otghost *otghost);
+
+//void otg_print_registers();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _S3C_OTG_HCDI_DRIVER_H_ */
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.c b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.c
new file mode 100644
index 0000000..fe1050d
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.c
@@ -0,0 +1,706 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-hcd.c
+ * @brief implementation of structure hc_drive \n
+ * @version
+ * -# Jun 11,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Modifying for successful rmmod & disconnecting \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-hcdi-hcd.h"
+
+/**
+ * otg_hcd_init_modules(struct sec_otghost *otghost)
+ *
+ * @brief call other modules' init functions
+ *
+ * @return PASS : If success \n
+ * FAIL : If fail \n
+ */
+int otg_hcd_init_modules(struct sec_otghost *otghost)
+{
+ unsigned long spin_lock_flag = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "otg_hcd_init_modules\n");
+
+ spin_lock_init(&otghost->lock);
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ init_transfer();
+ init_scheduler();
+ oci_init(otghost);
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ return USB_ERR_SUCCESS;
+};
+
+/**
+ * void otg_hcd_deinit_modules(struct sec_otghost *otghost)
+ *
+ * @brief call other modules' de-init functions
+ *
+ * @return PASS : If success \n
+ * FAIL : If fail \n
+ */
+void otg_hcd_deinit_modules(struct sec_otghost *otghost)
+{
+ unsigned long spin_lock_flag = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "otg_hcd_deinit_modules \n");
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ deinit_transfer(otghost);
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+}
+
+/**
+ * irqreturn_t (*s5pc110_otghcd_irq) (struct usb_hcd *hcd)
+ *
+ * @brief interrupt handler of otg irq
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ *
+ * @return IRQ_HANDLED \n
+ */
+irqreturn_t s5pc110_otghcd_irq(struct usb_hcd *hcd)
+{
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_irq \n");
+
+ spin_lock_otg(&otghost->lock);
+ otg_handle_interrupt(hcd);
+ spin_unlock_otg(&otghost->lock);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * int s5pc110_otghcd_start(struct usb_hcd *hcd)
+ *
+ * @brief initialize and start otg hcd
+ *
+ * @param [in] usb_hcd_p : pointer of usb_hcd
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+int s5pc110_otghcd_start(struct usb_hcd *usb_hcd_p)
+{
+ struct usb_bus *usb_bus_p;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_start \n");
+
+ usb_bus_p = hcd_to_bus(usb_hcd_p);
+
+ /* Initialize and connect root hub if one is not already attached */
+ if (usb_bus_p->root_hub) {
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "OTG HCD Has Root Hub\n");
+
+ /* Inform the HUB driver to resume. */
+ otg_usbcore_resume_roothub();
+ } else {
+ otg_err(OTG_DBG_OTGHCDI_HCD,
+ "OTG HCD Does Not Have Root Hub\n");
+ return USB_ERR_FAIL;
+ }
+
+ set_bit(HCD_FLAG_POLL_RH,&usb_hcd_p->flags);
+ usb_hcd_p->uses_new_polling = 1;
+
+ /* init bus state before enable irq */
+ usb_hcd_p->state = HC_STATE_RUNNING;
+
+ oci_start(); /* enable irq */
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * void s5pc110_otghcd_stop(struct usb_hcd *hcd)
+ *
+ * @brief deinitialize and stop otg hcd
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ *
+ */
+void s5pc110_otghcd_stop(struct usb_hcd *hcd)
+{
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_stop \n");
+
+ otg_hcd_deinit_modules(otghost);
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ oci_stop();
+ root_hub_feature(hcd, 0, ClearPortFeature, USB_PORT_FEAT_POWER, NULL);
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+}
+
+/**
+ * void s5pc110_otghcd_shutdown(struct usb_hcd *hcd)
+ *
+ * @brief shutdown otg hcd
+ *
+ * @param [in] usb_hcd_p : pointer of usb_hcd
+ *
+ */
+void s5pc110_otghcd_shutdown(struct usb_hcd *usb_hcd_p)
+{
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(usb_hcd_p);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_shutdown \n");
+ otg_hcd_deinit_modules(otghost);
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ oci_stop();
+ root_hub_feature(usb_hcd_p, 0, ClearPortFeature, USB_PORT_FEAT_POWER, NULL);
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ free_irq(IRQ_OTG, usb_hcd_p);
+ usb_hcd_p->state = HC_STATE_HALT;
+ otg_usbcore_hc_died();
+}
+
+
+/**
+ * int s5pc110_otghcd_get_frame_number(struct usb_hcd *hcd)
+ *
+ * @brief get currnet frame number
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ *
+ * @return ret : frame number \n
+ */
+int s5pc110_otghcd_get_frame_number(struct usb_hcd *hcd)
+{
+ int ret = 0;
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_get_frame_number \n");
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ ret = oci_get_frame_num();
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ return ret;
+}
+
+
+/**
+ * int s5pc110_otghcd_urb_enqueue()
+ *
+ * @brief enqueue a urb to otg hcd
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ * [in] ep : pointer of usb_host_endpoint
+ * [in] urb : pointer of urb
+ * [in] mem_flags : type of gfp_t
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+int s5pc110_otghcd_urb_enqueue (struct usb_hcd *hcd,
+ struct urb *urb,
+ gfp_t mem_flags)
+{
+ int ret_val = 0;
+ u32 trans_flag = 0;
+ u32 return_td_addr = 0;
+ u8 dev_speed, ed_type = 0, additional_multi_count;
+ u16 max_packet_size;
+
+ u8 dev_addr = 0;
+ u8 ep_num = 0;
+ bool f_is_ep_in = true;
+ u8 interval = 0;
+ u32 sched_frame = 0;
+ u8 hub_addr = 0;
+ u8 hub_port = 0;
+ bool f_is_do_split = false;
+ ed_t *target_ed = NULL;
+ isoch_packet_desc_t *new_isoch_packet_desc = NULL;
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ if (!otghost->port_flag.b.port_connect_status) {
+ printk(KERN_ERR"%s %d\n", __func__, __LINE__);
+ return USB_ERR_NOIO;
+ }
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_urb_enqueue \n");
+
+ /* check ep has ed_t or not */
+ if(!(urb->ep->hcpriv)) {
+ /* for getting dev_speed */
+ switch (urb->dev->speed) {
+ case USB_SPEED_HIGH :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "HS_OTG \n");
+ dev_speed = HIGH_SPEED_OTG;
+ break;
+
+ case USB_SPEED_FULL :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "FS_OTG \n");
+ dev_speed = FULL_SPEED_OTG;
+ break;
+
+ case USB_SPEED_LOW :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "LS_OTG \n");
+ dev_speed = LOW_SPEED_OTG;
+ break;
+
+ default:
+ otg_err(OTG_DBG_OTGHCDI_HCD,
+ "unKnown Device Speed \n");
+ spin_unlock_irq_save_otg(&otghost->lock,
+ spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ /* for getting ed_type */
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_BULK :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "bulk transfer \n");
+ ed_type = BULK_TRANSFER;
+ break;
+
+ case PIPE_INTERRUPT :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "interrupt transfer \n");
+ ed_type = INT_TRANSFER;
+ break;
+
+ case PIPE_CONTROL :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "control transfer \n");
+ ed_type = CONTROL_TRANSFER;
+ break;
+
+ case PIPE_ISOCHRONOUS :
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "isochronous transfer \n");
+ ed_type = ISOCH_TRANSFER;
+ break;
+ default:
+ otg_err(OTG_DBG_OTGHCDI_HCD, "unKnown ep type \n");
+ spin_unlock_irq_save_otg(&otghost->lock,
+ spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ max_packet_size = usb_maxpacket(urb->dev, urb->pipe,
+ !(usb_pipein(urb->pipe)));
+ additional_multi_count = ((max_packet_size) >> 11) & 0x03;
+ dev_addr = usb_pipedevice(urb->pipe);
+ ep_num = usb_pipeendpoint(urb->pipe);
+ f_is_ep_in = usb_pipein(urb->pipe) ? true : false;
+ interval = (u8)(urb->interval);
+ sched_frame = (u8)(urb->start_frame);
+
+ /* check */
+ if(urb->dev->tt == NULL) {
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "urb->dev->tt == NULL\n");
+ hub_port = 0; /* u8 hub_port */
+ hub_addr = 0; /* u8 hub_addr */
+ }
+ else {
+ hub_port = (u8)(urb->dev->ttport);
+ if (urb->dev->tt->hub) {
+ if (((dev_speed == FULL_SPEED_OTG) ||
+ (dev_speed == LOW_SPEED_OTG)) &&
+ (urb->dev->tt) && (urb->dev->tt->hub->devnum != 1)) {
+ f_is_do_split = true;
+ }
+ hub_addr = (u8)(urb->dev->tt->hub->devnum);
+ }
+ if (urb->dev->tt->multi) {
+ hub_addr = 0x80;
+ }
+ }
+ otg_dbg(OTG_DBG_OTGHCDI_HCD,
+ "dev_spped =%d, hub_port=%d, hub_addr=%d\n",
+ dev_speed, hub_port, hub_addr);
+
+ ret_val = create_ed(&target_ed);
+ if(ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD,
+ "fail to create_ed() \n");
+ spin_unlock_irq_save_otg(&otghost->lock,
+ spin_lock_flag);
+ return ret_val;
+ }
+
+ ret_val = init_ed( target_ed,
+ dev_addr,
+ ep_num,
+ f_is_ep_in,
+ dev_speed,
+ ed_type,
+ max_packet_size,
+ additional_multi_count,
+ interval,
+ sched_frame,
+ hub_addr,
+ hub_port,
+ f_is_do_split,
+ (void *)urb->ep);
+
+ if(ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD,
+ "fail to init_ed() :err = %d \n",(int)ret_val);
+ otg_mem_free(target_ed);
+ spin_unlock_irq_save_otg(&otghost->lock,
+ spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ urb->ep->hcpriv = (void *)(target_ed);
+ } /* if(!(ep->hcpriv)) */
+ else {
+ dev_addr = usb_pipedevice(urb->pipe);
+ if(((ed_t *)(urb->ep->hcpriv))->ed_desc.device_addr != dev_addr) {
+ ((ed_t *)urb->ep->hcpriv)->ed_desc.device_addr = dev_addr;
+ }
+ }
+
+ target_ed = (ed_t *)urb->ep->hcpriv;
+
+ if(urb->transfer_flags & URB_SHORT_NOT_OK)
+ trans_flag += USB_TRANS_FLAG_NOT_SHORT;
+ if (urb->transfer_flags & URB_ISO_ASAP)
+ trans_flag += USB_TRANS_FLAG_ISO_ASYNCH;
+
+ if(ed_type == ISOCH_TRANSFER) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "ISO not yet supported \n");
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ if (!HC_IS_RUNNING(hcd->state)) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "!HC_IS_RUNNING(hcd->state) \n");
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return -USB_ERR_NODEV;
+ }
+
+ /* in case of unlink-during-submit */
+ if (urb->status != -EINPROGRESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "urb->status is -EINPROGRESS\n");
+ urb->hcpriv = NULL;
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ usb_hcd_giveback_urb(hcd, urb, urb->status);
+ return USB_ERR_SUCCESS;
+ }
+
+ ret_val = issue_transfer(otghost, target_ed, (void *)NULL, (void *)NULL,
+ trans_flag,
+ (usb_pipetype(urb->pipe) == PIPE_CONTROL)?true:false,
+ (u32)urb->setup_packet, (u32)urb->setup_dma,
+ (u32)urb->transfer_buffer, (u32)urb->transfer_dma,
+ (u32)urb->transfer_buffer_length,
+ (u32)urb->start_frame,(u32)urb->number_of_packets,
+ new_isoch_packet_desc, (void *)urb, &return_td_addr);
+
+ if(ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "fail to issue_transfer() \n");
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+ urb->hcpriv = (void *)return_td_addr;
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * int s5pc110_otghcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb )
+ *
+ * @brief dequeue a urb to otg
+ *
+ * @param [in] _hcd : pointer of usb_hcd
+ * [in] _urb : pointer of urb
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+int s5pc110_otghcd_urb_dequeue(
+ struct usb_hcd *_hcd, struct urb *_urb, int status)
+{
+ int ret_val = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(_hcd);
+
+ unsigned long spin_lock_flag = 0;
+ td_t *cancel_td;
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_urb_dequeue \n");
+
+ /* Dequeue should be performed only if endpoint is enabled */
+ if (_urb->ep->enabled == 0) {
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ usb_hcd_giveback_urb(_hcd, _urb, status);
+ return USB_ERR_SUCCESS;
+ }
+
+ //kevinh read this from inside the spinlock
+ cancel_td = (td_t *)_urb->hcpriv;
+
+ if (cancel_td == NULL) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "cancel_td is NULL\n");
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+ otg_dbg(OTG_DBG_OTGHCDI_HCD,
+ "s5pc110_otghcd_urb_dequeue, status = %d\n", status);
+
+
+ ret_val = usb_hcd_check_unlink_urb(_hcd, _urb, status);
+ if( (ret_val) && (ret_val != -EIDRM) ) {
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "ret_val = %d\n", ret_val);
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ usb_hcd_giveback_urb(_hcd, _urb, status);
+ return ret_val;
+ }
+
+ if (!HC_IS_RUNNING(_hcd->state)) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "!HC_IS_RUNNING(hcd->state) \n");
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ otg_usbcore_giveback(cancel_td);
+ return USB_ERR_SUCCESS;
+ }
+
+ ret_val = cancel_transfer(otghost, cancel_td->parent_ed_p, cancel_td);
+ if(ret_val != USB_ERR_DEQUEUED && ret_val != USB_ERR_NOELEMENT) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "fail to cancel_transfer() \n");
+ otg_usbcore_giveback(cancel_td);
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+ otg_usbcore_giveback(cancel_td);
+ delete_td(otghost, cancel_td);
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * void s5pc110_otghcd_endpoint_disable(
+ * struct usb_hcd *hcd,
+ * struct usb_host_endpoint *ep)
+ *
+ * @brief disable a endpoint
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ * [in] ep : pointer of usb_host_endpoint
+ */
+void s5pc110_otghcd_endpoint_disable(
+ struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ int ret_val = 0;
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_endpoint_disable \n");
+
+ if(!((ed_t *)ep->hcpriv))
+ return;
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ ret_val = delete_ed(otghost, (ed_t *)ep->hcpriv);
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ if(ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "fail to delete_ed() \n");
+ return ;
+ }
+
+ /* ep->hcpriv = NULL; delete_ed coveres it */
+}
+
+/**
+ * int s5pc110_otghcd_hub_status_data(struct usb_hcd *_hcd, char *_buf)
+ *
+ * @brief get status of root hub
+ *
+ * @param [in] _hcd : pointer of usb_hcd
+ * [inout] _buf : pointer of buffer for write a status data
+ *
+ * @return ret_val : return port status \n
+ */
+int s5pc110_otghcd_hub_status_data(struct usb_hcd *_hcd, char *_buf)
+{
+ int ret_val = 0;
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(_hcd);
+
+ /* otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_hub_status_data \n"); */
+
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(_hcd->state)) {
+ otg_dbg(OTG_DBG_OTGHCDI_HCD,
+ "_hcd->state is NOT HC_IS_RUNNING \n");
+ return 0;
+ }
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ ret_val = get_otg_port_status(_hcd, OTG_PORT_NUMBER, _buf);
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ return (int)ret_val;
+}
+
+/**
+ * int s5pc110_otghcd_hub_control()
+ *
+ * @brief control root hub
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ * [in] typeReq : type of control request
+ * [in] value : value
+ * [in] index : index
+ * [in] buf_p : pointer of urb
+ * [in] length : type of gfp_t
+ *
+ * @return ret_val : return root_hub_feature \n
+ */
+int
+s5pc110_otghcd_hub_control (
+ struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 value,
+ u16 index,
+ char* buf_p,
+ u16 length
+)
+{
+ int ret_val = 0;
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_hub_control \n");
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ ret_val = root_hub_feature(hcd, OTG_PORT_NUMBER,
+ typeReq, value, (void *)buf_p);
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ if(ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "fail to root_hub_feature() \n");
+ return ret_val;
+ }
+ return (int)ret_val;
+}
+
+/**
+ * int s5pc110_otghcd_bus_suspend(struct usb_hcd *hcd)
+ *
+ * @brief suspend otg hcd
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ *
+ * @return USB_ERR_SUCCESS \n
+ */
+int s5pc110_otghcd_bus_suspend(struct usb_hcd *hcd)
+{
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_bus_suspend \n");
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ bus_suspend();
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * int s5pc110_otghcd_bus_resume(struct usb_hcd *hcd)
+ *
+ * @brief resume otg hcd
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ *
+ * @return USB_ERR_SUCCESS \n
+ */
+int s5pc110_otghcd_bus_resume(struct usb_hcd *hcd)
+{
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_bus_resume \n");
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ if(bus_resume(otghost) != USB_ERR_SUCCESS) {
+ return USB_ERR_FAIL;
+ }
+
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * int s5pc110_otghcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
+ *
+ * @brief reset otg port
+ *
+ * @param [in] hcd : pointer of usb_hcd
+ * [in] port : number of port
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * ret_val : If call fail \n
+ */
+int s5pc110_otghcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
+{
+ int ret_val = 0;
+
+ unsigned long spin_lock_flag = 0;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_start_port_reset \n");
+
+ spin_lock_irq_save_otg(&otghost->lock, spin_lock_flag);
+ ret_val = reset_and_enable_port(hcd, OTG_PORT_NUMBER);
+ spin_unlock_irq_save_otg(&otghost->lock, spin_lock_flag);
+
+ if(ret_val != USB_ERR_SUCCESS) {
+ otg_err(OTG_DBG_OTGHCDI_HCD,
+ "fail to reset_and_enable_port() \n");
+ return ret_val;
+ }
+ return USB_ERR_SUCCESS;
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.h b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.h
new file mode 100644
index 0000000..95764d8
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-hcd.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-hcd.h
+ * @brief header of s3c-otg-hcdi-hcd \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Modifying for successful rmmod & disconnecting \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_HCDI_HCD_H_
+#define _S3C_OTG_HCDI_HCD_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//for IRQ_NONE (0) IRQ_HANDLED (1) IRQ_RETVAL(x) ((x) != 0)
+#include <linux/interrupt.h>
+
+#include <linux/usb.h>
+
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-hcdi-kal.h"
+
+#include "s3c-otg-common-common.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-common-const.h"
+
+#include "s3c-otg-transfer-transfer.h"
+#include "s3c-otg-oci.h"
+#include "s3c-otg-roothub.h"
+
+//placed in ISR
+//void otg_handle_interrupt(struct usb_hcd *hcd);
+
+irqreturn_t s5pc110_otghcd_irq(struct usb_hcd *hcd);
+
+int s5pc110_otghcd_start(struct usb_hcd *hcd);
+void s5pc110_otghcd_stop(struct usb_hcd *hcd);
+void s5pc110_otghcd_shutdown(struct usb_hcd *hcd);
+
+int s5pc110_otghcd_get_frame_number(struct usb_hcd *hcd);
+
+int s5pc110_otghcd_urb_enqueue(
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ gfp_t mem_flags);
+
+int s5pc110_otghcd_urb_dequeue(
+ struct usb_hcd *_hcd,
+ struct urb *_urb,
+ int status);
+
+void s5pc110_otghcd_endpoint_disable(
+ struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep);
+
+int s5pc110_otghcd_hub_status_data(
+ struct usb_hcd *_hcd,
+ char *_buf);
+
+int s5pc110_otghcd_hub_control(
+ struct usb_hcd *hcd,
+ u16 type_req,
+ u16 value,
+ u16 index,
+ char * buf,
+ u16 length);
+
+int s5pc110_otghcd_bus_suspend(struct usb_hcd *hcd);
+int s5pc110_otghcd_bus_resume(struct usb_hcd *hcd);
+int s5pc110_otghcd_start_port_reset(struct usb_hcd *hcd, unsigned port);
+
+/**
+ * @struct hc_driver s5pc110_otg_hc_driver
+ *
+ * @brief implementation of hc_driver for OTG HCD
+ *
+ * describe in detail
+ */
+static const struct hc_driver s5pc110_otg_hc_driver = {
+ .description = "EMSP_OTGHCD",
+ .product_desc = "S3C OTGHCD",
+ .hcd_priv_size = sizeof(struct sec_otghost),
+
+ .irq = s5pc110_otghcd_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /** basic lifecycle operations */
+ //.reset =
+ .start = s5pc110_otghcd_start,
+ //.suspend = ,
+ //.resume = ,
+ .stop = s5pc110_otghcd_stop,
+ .shutdown = s5pc110_otghcd_shutdown,
+
+ /** managing i/o requests and associated device resources */
+ .urb_enqueue = s5pc110_otghcd_urb_enqueue,
+ .urb_dequeue = s5pc110_otghcd_urb_dequeue,
+ .endpoint_disable = s5pc110_otghcd_endpoint_disable,
+
+ /** scheduling support */
+ .get_frame_number = s5pc110_otghcd_get_frame_number,
+
+ /** root hub support */
+ .hub_status_data = s5pc110_otghcd_hub_status_data,
+ .hub_control = s5pc110_otghcd_hub_control,
+ //.hub_irq_enable =
+ .bus_suspend = s5pc110_otghcd_bus_suspend,
+ .bus_resume = s5pc110_otghcd_bus_resume,
+ .start_port_reset = s5pc110_otghcd_start_port_reset,
+};
+
+static inline struct sec_otghost *hcd_to_sec_otghost (struct usb_hcd *hcd)
+{
+ return (struct sec_otghost *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *sec_otghost_to_hcd (struct sec_otghost *otghost)
+{
+ return container_of ((void *) otghost, struct usb_hcd, hcd_priv);
+}
+
+int otg_hcd_init_modules(struct sec_otghost *otghost);
+void otg_hcd_deinit_modules(struct sec_otghost *otghost);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _S3C_OTG_HCDI_HCD_H_ */
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-kal.h b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-kal.h
new file mode 100644
index 0000000..23bded6
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-kal.h
@@ -0,0 +1,420 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-kal.h
+ * @brief header of s3c-otg-hcdi-kal \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Modifying for successful rmmod & disconnecting \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_HCDI_KAL_H_
+#define _S3C_OTG_HCDI_KAL_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-common-common.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-common-const.h"
+
+#include <asm/io.h> //for readl, writel
+#include <linux/usb/ch9.h> //for usb_device_driver, enum usb_device_speed
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <mach/map.h>
+#include <plat/regs-otg.h>
+
+extern volatile u8 * g_pUDCBase;
+extern struct usb_hcd* g_pUsbHcd;
+
+#include <linux/spinlock.h>
+#define SPINLOCK_t spinlock_t
+#define SPIN_LOCK_INIT SPIN_LOCK_UNLOCKED
+
+#define spin_lock_otg(lock) spin_lock(lock)
+#define spin_lock_irg_otg(lock) spin_lock_irq(lock)
+#define spin_lock_irq_save_otg(lock, flags) spin_lock_irqsave(lock, flags)
+
+#define spin_unlock_otg(lock) spin_unlock(lock)
+#define spin_unlock_irq_otg(lock) spin_unlock_irq(lock)
+#define spin_unlock_irq_save_otg(lock, flags) spin_unlock_irqrestore(lock, flags)
+
+#define ctrlr_base_reg_addr(offset) \
+ ((volatile unsigned int *)((g_pUDCBase) + (offset)))
+/**
+ * otg_kal_make_ep_null
+ *
+ * @brief make ep->hcpriv NULL
+ *
+ * @param [in] pdelete_ed : pointer of ed
+ *
+ * @return void \n
+ */
+static inline void
+otg_kal_make_ep_null
+(
+ ed_t *pdelete_ed
+)
+{
+ ((struct usb_host_endpoint *)(pdelete_ed->ed_private))->hcpriv = NULL;
+}
+//---------------------------------------------------------------------------------------
+
+/**
+ * otg_kal_is_ep_null
+ *
+ * @brief check ep->hcpriv is NULL or not
+ *
+ * @param [in] pdelete_ed : pointer of ed
+ *
+ * @return bool \n
+ */
+static inline bool
+otg_kal_is_ep_null
+(
+ ed_t *pdelete_ed
+)
+{
+ if (((struct usb_host_endpoint *)(pdelete_ed->ed_private))->hcpriv == NULL)
+ return true;
+ else
+ return false;
+}
+//---------------------------------------------------------------------------------------
+
+
+/**
+ * int otg_usbcore_get_calc_bustime()
+ *
+ * @brief get bus time of usbcore
+ *
+ * @param [in] speed : usb speed
+ * [in] is_input : input or not
+ * [in] is_isoch : isochronous or not
+ * [in] byte_count : bytes
+ *
+ * @return bus time of usbcore \n
+ */
+static inline int
+otg_usbcore_get_calc_bustime
+(
+ u8 speed,
+ bool is_input,
+ bool is_isoch,
+ unsigned int byte_count
+)
+{
+ unsigned int convert_speed = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_KAL, "otg_usbcore_get_calc_bustime \n");
+/* enum usb_device_speed {
+ USB_SPEED_UNKNOWN = 0,
+ USB_SPEED_LOW, USB_SPEED_FULL,
+ USB_SPEED_HIGH,
+ USB_SPEED_VARIABLE, };*/
+ switch(speed) {
+ case HIGH_SPEED_OTG :
+ convert_speed = USB_SPEED_HIGH;
+ break;
+
+ case FULL_SPEED_OTG :
+ convert_speed = USB_SPEED_FULL;
+ break;
+
+ case LOW_SPEED_OTG :
+ convert_speed = USB_SPEED_LOW;
+ break;
+
+ default:
+ convert_speed = USB_SPEED_UNKNOWN;
+ break;
+ }
+ return usb_calc_bus_time(convert_speed, is_input, (unsigned int)is_isoch, byte_count);
+}
+
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_usbcore_giveback(td_t td_p)
+ *
+ * @brief give-back a td as urb
+ *
+ * @param [in] td_p : pointer of td_t to give back
+ *
+ * @return void \n
+ */
+static inline void
+otg_usbcore_giveback(td_t * td_p)
+{
+ struct urb *urb_p = NULL;
+
+ otg_dbg(OTG_DBG_OTGHCDI_KAL, "otg_usbcore_giveback \n");
+
+ if (td_p->td_private == NULL)
+ {
+ otg_err(OTG_DBG_OTGHCDI_KAL,
+ "td_p->td_private == NULL \n");
+ return;
+ }
+
+ urb_p = (struct urb *)td_p->td_private;
+
+ urb_p->actual_length = (int)(td_p->transferred_szie);
+ urb_p->status = (int)(td_p->error_code);
+ urb_p->error_count = (int)(td_p->err_cnt);
+ urb_p->hcpriv = NULL;
+
+ usb_hcd_giveback_urb(g_pUsbHcd, urb_p, urb_p->status);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_usbcore_hc_died(void)
+ *
+ * @brief inform usbcore of hc die
+ *
+ * @return void \n
+ */
+static inline void
+otg_usbcore_hc_died(void)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_KAL, "otg_usbcore_hc_died \n");
+ usb_hc_died(g_pUsbHcd);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_usbcore_poll_rh_status(void)
+ *
+ * @brief invoke usbcore's usb_hcd_poll_rh_status
+ *
+ * @param void
+ *
+ * @return void \n
+ */
+static inline void
+otg_usbcore_poll_rh_status(void)
+{
+ usb_hcd_poll_rh_status(g_pUsbHcd);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_usbcore_resume_roothub(void)
+ *
+ * @brief invoke usbcore's usb_hcd_resume_root_hub
+ *
+ * @param void
+ *
+ * @return void \n
+ */
+static inline void
+otg_usbcore_resume_roothub(void)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_KAL,
+ "otg_usbcore_resume_roothub \n");
+ usb_hcd_resume_root_hub(g_pUsbHcd);
+};
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_usbcore_inc_usb_bandwidth(u32 band_width)
+ *
+ * @brief increase bandwidth of usb bus
+ *
+ * @param [in] band_width : bandwidth to be increased
+ *
+ * @return USB_ERR_SUCCESS \n
+ */
+static inline int
+otg_usbcore_inc_usb_bandwidth(u32 band_width)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_KAL,
+ "otg_usbcore_inc_usb_bandwidth \n");
+ hcd_to_bus(g_pUsbHcd)->bandwidth_allocated += band_width;
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_usbcore_des_usb_bandwidth(u32 uiBandwidth)
+ *
+ * @brief decrease bandwidth of usb bus
+ *
+ * @param [in] band_width : bandwidth to be decreased
+ *
+ * @return USB_ERR_SUCCESS \n
+ */
+static inline int
+otg_usbcore_des_usb_bandwidth(u32 band_width)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_KAL,
+ "otg_usbcore_des_usb_bandwidth \n");
+ hcd_to_bus(g_pUsbHcd)->bandwidth_allocated -= band_width;
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_usbcore_inc_periodic_transfer_cnt(u8 transfer_type)
+ *
+ * @brief increase count of periodic transfer
+ *
+ * @param [in] transfer_type : type of transfer
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+static inline int
+otg_usbcore_inc_periodic_transfer_cnt(u8 transfer_type)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_KAL,
+ "otg_usbcore_inc_periodic_transfer_cnt \n");
+
+ switch(transfer_type) {
+ case INT_TRANSFER :
+ hcd_to_bus(g_pUsbHcd)->bandwidth_int_reqs++;
+ break;
+ case ISOCH_TRANSFER :
+ hcd_to_bus(g_pUsbHcd)->bandwidth_isoc_reqs++;
+ break;
+ default:
+ otg_err(OTG_DBG_OTGHCDI_KAL,
+ "not proper TransferType for otg_usbcore_inc_periodic_transfer_cnt()\n");
+ return USB_ERR_FAIL;
+ }
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_usbcore_des_periodic_transfer_cnt(u8 transfer_type)
+ *
+ * @brief decrease count of periodic transfer
+ *
+ * @param [in] transfer_type : type of transfer
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+static inline int
+otg_usbcore_des_periodic_transfer_cnt(u8 transfer_type)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_KAL,
+ "otg_usbcore_des_periodic_transfer_cnt \n");
+
+ switch(transfer_type) {
+ case INT_TRANSFER :
+ hcd_to_bus(g_pUsbHcd)->bandwidth_int_reqs--;
+ break;
+ case ISOCH_TRANSFER :
+ hcd_to_bus(g_pUsbHcd)->bandwidth_isoc_reqs--;
+ break;
+ default:
+ otg_err(OTG_DBG_OTGHCDI_KAL,
+ "not proper TransferType for otg_usbcore_des_periodic_transfer_cnt()\n");
+ return USB_ERR_FAIL;
+ }
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * u32 read_reg_32(u32 offset)
+ *
+ * @brief Reads the content of a register.
+ *
+ * @param [in] offset : offset of address of register to read.
+ *
+ * @return contents of the register. \n
+ * @remark call readl()
+ */
+static inline u32 read_reg_32(u32 offset)
+{
+ volatile unsigned int * reg_addr_p = ctrlr_base_reg_addr(offset);
+
+ return *reg_addr_p;
+ //return readl(reg_addr_p);
+};
+//-------------------------------------------------------------------------------
+
+/**
+ * void write_reg_32( u32 offset, const u32 value)
+ *
+ * @brief Writes a register with a 32 bit value.
+ *
+ * @param [in] offset : offset of address of register to write.
+ * @param [in] value : value to write
+ *
+ * @remark call writel()
+ */
+static inline void write_reg_32( u32 offset, const u32 value)
+{
+ volatile unsigned int * reg_addr_p = ctrlr_base_reg_addr(offset);
+
+ *reg_addr_p = value;
+ //writel( value, reg_addr_p );
+};
+//-------------------------------------------------------------------------------
+
+/**
+ * void update_reg_32(u32 offset, u32 value)
+ *
+ * @brief logic or operation
+ *
+ * @param [in] offset : offset of address of register to write.
+ * @param [in] value : value to or
+ *
+ */
+static inline void update_reg_32(u32 offset, u32 value)
+{
+ write_reg_32(offset, (read_reg_32(offset) | value));
+}
+//---------------------------------------------------------------------------------------
+
+/**
+ * void clear_reg_32(u32 offset, u32 value)
+ *
+ * @brief logic not operation
+ *
+ * @param [in] offset : offset of address of register to write.
+ * @param [in] value : value to not
+ *
+ */
+static inline void clear_reg_32(u32 offset, u32 value)
+{
+ write_reg_32(offset, (read_reg_32(offset) & ~value));
+}
+//---------------------------------------------------------------------------------------
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _S3C_OTG_HCDI_KAL_H_ */
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-list.h b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-list.h
new file mode 100644
index 0000000..03ae3d8
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-list.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-list.h
+ * @brief list functions for otg \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_HCDI_LIST_H_
+#define _S3C_OTG_HCDI_LIST_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "s3c-otg-common-common.h"
+#include "s3c-otg-hcdi-debug.h"
+
+#include <linux/list.h>
+
+typedef struct list_head otg_list_head;
+
+#define otg_list_get_node(ptr, type, member) container_of(ptr, type, member)
+
+
+#define otg_list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+
+/**
+ * void otg_list_push_next(otg_list_head *new_node_p, otg_list_head *list_head_p)
+ *
+ * @brief push a list node into the next of head
+ *
+ * @param [in] new_node_p : node to be pushed
+ * @param [in] otg_list_head : target list head
+ *
+ * @return void \n
+ */
+
+static inline
+void otg_list_push_next(otg_list_head *new_node_p, otg_list_head *list_head_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_push_next \n");
+ list_add(new_node_p, list_head_p);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_list_push_prev(otg_list_head *new_node_p, otg_list_head *list_head_p)
+ *
+ * @brief push a list node into the previous of head
+ *
+ * @param [in] new_node_p : node to be pushed
+ * @param [in] otg_list_head : target list head
+ *
+ * @return void \n
+ */
+static inline
+void otg_list_push_prev(otg_list_head *new_node_p, otg_list_head *list_head_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_push_prev \n");
+ list_add_tail(new_node_p, list_head_p);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_list_pop(otg_list_head *list_entity_p)
+ *
+ * @brief pop a list node
+ *
+ * @param [in] new_node_p : node to be poped
+ * @param [in] otg_list_head : target list head
+ *
+ * @return void \n
+ */
+static inline
+void otg_list_pop(otg_list_head *list_entity_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_pop \n");
+ list_del(list_entity_p);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_list_move_next(otg_list_head *node_p, otg_list_head *list_head_p)
+ *
+ * @brief move a list to next of head
+ *
+ * @param [in] new_node_p : node to be moved
+ * @param [in] otg_list_head : target list head
+ *
+ * @return void \n
+ */
+static inline
+void otg_list_move_next(otg_list_head *node_p, otg_list_head *list_head_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_move_next \n");
+ list_move(node_p, list_head_p);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_list_move_prev(otg_list_head *node_p, otg_list_head *list_head_p)
+ *
+ * @brief move a list to previous of head
+ *
+ * @param [in] new_node_p : node to be moved
+ * @param [in] otg_list_head : target list head
+ *
+ * @return void \n
+ */
+static inline
+void otg_list_move_prev(otg_list_head *node_p, otg_list_head *list_head_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_move_prev \n");
+ list_move_tail(node_p, list_head_p);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * bool otg_list_empty(otg_list_head *list_head_p)
+ *
+ * @brief check a list empty or not
+ *
+ * @param [in] list_head_p : node to check
+ *
+ * @return true : empty list \n
+ * false : not empty list
+ */
+static inline
+bool otg_list_empty(otg_list_head *list_head_p)
+{
+
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_empty \n");
+ if(list_empty(list_head_p))
+ return true;
+ return false;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_list_merge(otg_list_head *list_p, otg_list_head *head_p)
+ *
+ * @brief merge two list
+ *
+ * @param [in] list_p : a head
+ * @param [in] head_p : target list head
+ *
+ * @return void \n
+ */
+static inline
+void otg_list_merge(otg_list_head *list_p, otg_list_head *head_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_merge \n");
+ list_splice(list_p, head_p);
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * void otg_list_init(otg_list_head *list_p)
+ *
+ * @brief initialize a list
+ *
+ * @param [in] list_p : node to be initialized
+ *
+ * @return void \n
+ */
+static inline
+void otg_list_init(otg_list_head *list_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_init \n");
+ list_p->next = list_p;
+ list_p->prev = list_p;
+}
+//-------------------------------------------------------------------------------
+
+/*
+void otg_list_push_next(otg_list_head *new_node_p, otg_list_head *list_head_p );
+void otg_list_push_prev(otg_list_head *new_node_p, otg_list_head *list_head_p);
+void otg_list_pop(otg_list_head *list_entity_p);
+
+void otg_list_move_next(otg_list_head *node_p, otg_list_head *list_head_p);
+void otg_list_move_prev(otg_list_head *node_p, otg_list_head *list_head_p);
+
+bool otg_list_empty(otg_list_head *list_head_p);
+void otg_list_merge(otg_list_head *list_p, otg_list_head *head_p);
+void otg_list_init(otg_list_head *list_p);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _S3C_OTG_HCDI_LIST_H_ */
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-hcdi-memory.h b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-memory.h
new file mode 100644
index 0000000..c87f15e
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-hcdi-memory.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-memory.h
+ * @brief header of s3c-otg-hcdi-memory \n
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Creating the initial version of this code \n
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ * @see None
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _S3C_OTG_HCDI_MEMORY_H_
+#define _S3C_OTG_HCDI_MEMORY_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "s3c-otg-common-common.h"
+#include "s3c-otg-hcdi-debug.h"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+/**
+ * @enum otg_mem_alloc_flag
+ *
+ * @brief enumeration for flag of memory allocation
+ */
+typedef
+enum otg_mem_alloc_flag
+{
+ USB_MEM_SYNC, USB_MEM_ASYNC, USB_MEM_DMA
+}otg_mem_alloc_flag_t;
+//---------------------------------------------------------------------------------------
+
+/*
+inline int otg_mem_alloc(void ** addr_pp, u16 byte_size, otg_mem_alloc_flag_t type);
+inline int otg_mem_copy(void * to_addr_p, void * from_addr_p, u16 byte_size);
+//inline int otg_mem_free(void * addr_p);
+inline int otg_mem_set(void * addr_p, char value, u16 byte_size);
+*/
+
+/**
+ * int otg_mem_alloc(void ** addr_pp, u16 byte_size, u8 ubType);
+ *
+ * @brief allocating momory specified
+ *
+ * @param [inout] addr_pp : address to be assigned
+ * [in] byte_size : size of memory
+ * [in] type : otg_mem_alloc_flag_t type
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+static inline int
+otg_mem_alloc (
+ void ** addr_pp,
+ u16 byte_size,
+ otg_mem_alloc_flag_t type
+)
+{
+ gfp_t flags;
+ otg_dbg(OTG_DBG_OTGHCDI_MEM, "otg_mem_alloc \n");
+
+ switch(type) {
+ case USB_MEM_SYNC:
+ flags = GFP_KERNEL;
+ break;
+ case USB_MEM_ASYNC:
+ flags = GFP_ATOMIC;
+ break;
+ case USB_MEM_DMA:
+ flags = GFP_DMA;
+ break;
+ default:
+ otg_err(OTG_DBG_OTGHCDI_MEM,
+ "not proper otg_mem_alloc_flag_t in otg_mem_alloc \n");
+ return USB_ERR_FAIL;
+ }
+
+ *addr_pp = kmalloc((size_t)byte_size, flags);
+ if(*addr_pp == 0) {
+ otg_err(OTG_DBG_OTGHCDI_MEM,
+ "kmalloc failed\n");
+ return USB_ERR_FAIL;
+ }
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_mem_copy(void * to_addr_p, void * from_addr_p, u16 byte_size);
+ *
+ * @brief memory copy
+ *
+ * @param [in] to_addr_p : target address
+ * [in] from_addr_p : source address
+ * [in] byte_size : size
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+static inline int
+otg_mem_copy
+(
+ void * to_addr_p,
+ void * from_addr_p,
+ u16 byte_size
+)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_MEM,
+ "otg_mem_copy \n");
+
+ memcpy(to_addr_p, from_addr_p, (size_t)byte_size);
+
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_mem_free(void * addr_p);
+ *
+ * @brief de-allocating memory
+ *
+ * @param [in] addr_p : target address to be de-allocated
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+static inline int
+otg_mem_free(void * addr_p)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_MEM,
+ "otg_mem_free \n");
+ kfree(addr_p);
+ return USB_ERR_SUCCESS;
+}
+
+//-------------------------------------------------------------------------------
+
+/**
+ * int otg_mem_set(void * addr_p, char value, u16 byte_size)
+ *
+ * @brief writing a value to memory
+ *
+ * @param [in] addr_p : target address
+ * [in] value : value to be written
+ * [in] byte_size : size
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ */
+static inline int
+otg_mem_set
+(
+ void * addr_p,
+ char value,
+ u16 byte_size
+)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_MEM,
+ "otg_mem_set \n");
+ memset(addr_p, value, (size_t)byte_size);
+ return USB_ERR_SUCCESS;
+}
+//-------------------------------------------------------------------------------
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _S3C_OTG_HCDI_MEMORY_H_ */
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-isr.c b/drivers/usb/host/s3c-otg/s3c-otg-isr.c
new file mode 100644
index 0000000..b72b386
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-isr.c
@@ -0,0 +1,294 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : Isr.c
+ * [Description] : The file implement the external and internal functions of ISR
+ * [Author] : Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * [Department] : System LSI Division/Embedded S/W Platform
+ * [Created Date]: 2009/02/10
+ * [Revision History]
+ * (1) 2008/06/13 by Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * - Created this file and implements functions of ISR
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-isr.h"
+
+/**
+ * void otg_handle_interrupt(void)
+ *
+ * @brief Main interrupt processing routine
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+
+__inline__ void otg_handle_interrupt(struct usb_hcd *hcd)
+{
+ gintsts_t clearIntr = {.d32 = 0};
+ gintsts_t gintsts = {.d32 = 0};
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ gintsts.d32 = read_reg_32(GINTSTS) & read_reg_32(GINTMSK);
+
+ otg_dbg(OTG_DBG_ISR, "otg_handle_interrupt - GINTSTS=0x%8x\n",
+ gintsts.d32);
+
+ if (gintsts.b.wkupintr) {
+ otg_dbg(true, "Wakeup Interrupt\n");
+ clearIntr.b.wkupintr = 1;
+ }
+
+ if (gintsts.b.disconnect) {
+ otg_dbg(true, "Disconnect Interrupt\n");
+ otghost->port_flag.b.port_connect_status_change = 1;
+ otghost->port_flag.b.port_connect_status = 0;
+ clearIntr.b.disconnect = 1;
+ /*
+ wake_unlock(&otghost->wake_lock);
+ */
+ }
+
+ if (gintsts.b.conidstschng) {
+ otg_dbg(OTG_DBG_ISR, "Connect ID Status Change Interrupt\n");
+ clearIntr.b.conidstschng = 1;
+ oci_init_mode();
+ }
+
+ if (gintsts.b.hcintr) {
+ /* Mask Channel Interrupt to prevent generating interrupt */
+ otg_dbg(OTG_DBG_ISR, "Channel Interrupt\n");
+ if(!otghost->ch_halt) {
+ do_transfer_checker(otghost);
+ }
+ }
+
+ if (gintsts.b.portintr) {
+ /* Read Only */
+ otg_dbg(true, "Port Interrupt\n");
+ process_port_intr(hcd);
+ }
+
+
+ if (gintsts.b.otgintr) {
+ /* Read Only */
+ otg_dbg(OTG_DBG_ISR, "OTG Interrupt\n");
+ }
+
+ if (gintsts.b.sofintr) {
+ /* otg_dbg(OTG_DBG_ISR, "SOF Interrupt\n"); */
+ do_schedule(otghost);
+ clearIntr.b.sofintr = 1;
+ }
+
+ if (gintsts.b.modemismatch) {
+ otg_dbg(OTG_DBG_ISR, "Mode Mismatch Interrupt\n");
+ clearIntr.b.modemismatch = 1;
+ }
+ update_reg_32(GINTSTS, clearIntr.d32);
+}
+
+/**
+ * void mask_channel_interrupt(u32 ch_num, u32 mask_info)
+ *
+ * @brief Mask specific channel interrupt
+ *
+ * @param [IN] chnum : channel number for masking
+ * [IN] mask_info : mask information to write register
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void mask_channel_interrupt(u32 ch_num, u32 mask_info)
+{
+ clear_reg_32(HCINTMSK(ch_num),mask_info);
+}
+
+/**
+ * void unmask_channel_interrupt(u32 ch_num, u32 mask_info)
+ *
+ * @brief Unmask specific channel interrupt
+ *
+ * @param [IN] chnum : channel number for unmasking
+ * [IN] mask_info : mask information to write register
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void unmask_channel_interrupt(u32 ch_num, u32 mask_info)
+{
+ update_reg_32(HCINTMSK(ch_num),mask_info);
+}
+
+/**
+ * int get_ch_info(hc_info_t * hc_reg, u8 ch_num)
+ *
+ * @brief Get current channel information about specific channel
+ *
+ * @param [OUT] hc_reg : structure to write channel inforamtion value
+ * [IN] ch_num : channel number for unmasking
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+int get_ch_info(hc_info_t *hc_reg, u8 ch_num)
+{
+ if(hc_reg !=NULL) {
+ hc_reg->hc_int_msk.d32 = read_reg_32(HCINTMSK(ch_num));
+ hc_reg->hc_int.d32 = read_reg_32(HCINT(ch_num));
+ hc_reg->dma_addr = read_reg_32(HCDMA(ch_num));
+ hc_reg->hc_char.d32 = read_reg_32(HCCHAR(ch_num));
+ hc_reg->hc_size.d32 = read_reg_32(HCTSIZ(ch_num));
+
+ return USB_ERR_SUCCESS;
+ }
+ return USB_ERR_FAIL;
+}
+
+/**
+ * void get_intr_ch(u32* haint, u32* haintmsk)
+ *
+ * @brief Get Channel Interrupt Information in HAINT, HAINTMSK register
+ *
+ * @param [OUT] haint : HAINT register value
+ * [OUT] haintmsk : HAINTMSK register value
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void get_intr_ch(u32 *haint, u32 *haintmsk)
+{
+ *haint = read_reg_32(HAINT);
+ *haintmsk = read_reg_32(HAINTMSK);
+}
+
+/**
+ * void clear_ch_intr(u8 ch_num, u32 clear_bit)
+ *
+ * @brief Get Channel Interrupt Information in HAINT, HAINTMSK register
+ *
+ * @param [IN] haint : HAINT register value
+ * [IN] haintmsk : HAINTMSK register value
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void clear_ch_intr(u8 ch_num, u32 clear_bit)
+{
+ update_reg_32(HCINT(ch_num),clear_bit);
+}
+
+/**
+ * void enable_sof(void)
+ *
+ * @brief Generate SOF Interrupt.
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void enable_sof(void)
+{
+ gintmsk_t gintmsk = {.d32 = 0};
+ gintmsk.b.sofintr = 1;
+ update_reg_32(GINTMSK, gintmsk.d32);
+}
+
+/**
+ * void disable_sof(void)
+ *
+ * @brief Stop to generage SOF interrupt
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void disable_sof(void)
+{
+ gintmsk_t gintmsk = {.d32 = 0};
+ gintmsk.b.sofintr = 1;
+ clear_reg_32(GINTMSK, gintmsk.d32);
+}
+
+/*Internal function of isr */
+void process_port_intr(struct usb_hcd *hcd)
+{
+ hprt_t hprt; /* by ss1, clear_hprt; */
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ hprt.d32 = read_reg_32(HPRT);
+
+ otg_dbg(OTG_DBG_ISR, "Port Interrupt() : HPRT = 0x%x\n",hprt.d32);
+
+ if(hprt.b.prtconndet) {
+ otg_dbg(true, "detect connection");
+
+ otghost->port_flag.b.port_connect_status_change = 1;
+
+ if(hprt.b.prtconnsts)
+ otghost->port_flag.b.port_connect_status = 1;
+
+ /* wake_lock(&otghost->wake_lock); */
+ }
+
+
+ if(hprt.b.prtenchng) {
+ otg_dbg(true, "port enable/disable changed\n");
+ otghost->port_flag.b.port_enable_change = 1;
+ }
+
+ if(hprt.b.prtovrcurrchng) {
+ otg_dbg(true, "over current condition is changed\n");
+ if(hprt.b.prtovrcurract) {
+ otg_dbg(true, "port_over_current_change = 1\n");
+ otghost->port_flag.b.port_over_current_change = 1;
+ }
+ else {
+ otghost->port_flag.b.port_over_current_change = 0;
+ }
+ /* defer otg power control into a kernel thread */
+ queue_work(otghost->wq, &otghost->work);
+ }
+
+ hprt.b.prtena = 0; /* prtena¸¦ writeclear½ÃÅ°¸é ¾ÈµÊ. */
+ /* hprt.b.prtpwr = 0; */
+ hprt.b.prtrst = 0;
+ hprt.b.prtconnsts = 0;
+
+ write_reg_32(HPRT, hprt.d32);
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-isr.h b/drivers/usb/host/s3c-otg/s3c-otg-isr.h
new file mode 100644
index 0000000..cad4cf5
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-isr.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] :s3c-otg-isr.h
+ * [Description] : The Header file defines the external and internal functions of ISR.
+ * [Author] : Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * [Department] : System LSI Division/Embedded S/W Platform
+ * [Created Date]: 2008/06/18
+ * [Revision History]
+ * (1) 2008/06/18 by Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * - Created this file and defines functions of Scheduler
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _ISR_H_
+#define _ISR_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-common-regdef.h"
+#include "s3c-otg-hcdi-kal.h"
+#include "s3c-otg-scheduler-scheduler.h"
+#include "s3c-otg-transferchecker-common.h"
+#include "s3c-otg-roothub.h"
+#include "s3c-otg-oci.h"
+
+__inline__ void otg_handle_interrupt(struct usb_hcd *hcd);
+
+void process_port_intr(struct usb_hcd *hcd);
+
+void mask_channel_interrupt(u32 ch_num, u32 mask_info);
+
+void unmask_channel_interrupt(u32 ch_num, u32 mask_info);
+
+extern int get_ch_info(hc_info_t *hc_reg, u8 ch_num);
+
+extern void get_intr_ch(u32 *haint, u32 *haintmsk);
+
+extern void clear_ch_intr(u8 ch_num, u32 clear_bit);
+
+extern void enable_sof(void);
+
+extern void disable_sof(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _ISR_H_ */
+
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-oci.c b/drivers/usb/host/s3c-otg/s3c-otg-oci.c
new file mode 100644
index 0000000..a79c45c
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-oci.c
@@ -0,0 +1,798 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : OCI.c
+ * [Description] : The file implement the external and internal functions of OCI
+ * [Author] : Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * [Department] : System LSI Division/Embedded S/W Platform
+ * [Created Date]: 2009/02/10
+ * [Revision History]
+ * (1) 2008/06/12 by Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * - Created this file and Implement functions of OCI
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-oci.h"
+
+static bool ch_enable[16];
+
+/**
+ * int oci_init(struct sec_otghost *otghost)
+ *
+ * @brief Initialize oci module.
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_init(struct sec_otghost *otghost)
+{
+ otg_mem_set((void*)ch_enable, true, sizeof(bool)*16);
+ otghost->ch_halt = false;
+
+ if(oci_sys_init() == USB_ERR_SUCCESS) {
+ if(oci_core_reset() == USB_ERR_SUCCESS) {
+ oci_set_global_interrupt(false);
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ otg_dbg(OTG_DBG_OCI, "oci_core_reset() Fail\n");
+ return USB_ERR_FAIL;
+ }
+ }
+
+ return USB_ERR_FAIL;
+}
+
+/**
+ * int oci_core_init(void)
+ *
+ * @brief process core initialize as s5pc110 otg spec
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_core_init(void)
+{
+ gahbcfg_t ahbcfg = {.d32 = 0};
+ gusbcfg_t usbcfg = {.d32 = 0};
+ ghwcfg2_t hwcfg2 = {.d32 = 0};
+ gintmsk_t gintmsk = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_core_init \n");
+
+ usbcfg.d32 = read_reg_32(GUSBCFG);
+ otg_dbg(OTG_DBG_OCI, "before - GUSBCFG=0x%x, GOTGCTL=0x%x\n",
+ usbcfg.d32, read_reg_32(GOTGCTL));
+
+ /* PHY parameters */
+ usbcfg.b.physel = 0;
+ usbcfg.b.phyif = 1; /* 16 bit */
+ usbcfg.b.ulpi_utmi_sel = 0; /* UTMI */
+ /* usbcfg.b.ddrsel = 1; */ /* DDR */
+ usbcfg.b.usbtrdtim = 5; /* 16 bit UTMI */
+ usbcfg.b.toutcal = 7;
+ usbcfg.b.forcehstmode = 1;
+ write_reg_32 (GUSBCFG, usbcfg.d32);
+
+ // per
+ // http://forum.xda-developers.com/showthread.php?t=709135&page=21
+ // we need a 25msec delay after setting this -kevinh
+
+ mdelay(100);
+
+ otg_dbg(OTG_DBG_OCI,
+ "after - GUSBCFG=0x%x, GOTGCTL=0x%x\n",
+ read_reg_32(GUSBCFG),
+ read_reg_32(GOTGCTL));
+
+ /* Reset after setting the PHY parameters */
+ if(oci_core_reset() == USB_ERR_SUCCESS) {
+ /* Program the GAHBCFG Register.*/
+ hwcfg2.d32 = read_reg_32 (GHWCFG2);
+
+ switch (hwcfg2.b.architecture) {
+ case HWCFG2_ARCH_SLAVE_ONLY:
+ otg_dbg(OTG_DBG_OCI, "Slave Only Mode\n");
+ ahbcfg.b.nptxfemplvl = 0;
+ ahbcfg.b.ptxfemplvl = 0;
+ break;
+
+ case HWCFG2_ARCH_EXT_DMA:
+ otg_dbg(OTG_DBG_OCI, "External DMA Mode - TBD!\n");
+ break;
+
+ case HWCFG2_ARCH_INT_DMA:
+ otg_dbg(OTG_DBG_OCI, "Internal DMA Setting \n");
+ ahbcfg.b.dmaenable = true;
+ ahbcfg.b.hburstlen = INT_DMA_MODE_INCR4;
+ break;
+
+ default:
+ otg_dbg(OTG_DBG_OCI, "ERR> hwcfg2\n ");
+ break;
+ }
+ write_reg_32 (GAHBCFG, ahbcfg.d32);
+
+ /* Program the GUSBCFG register.*/
+ switch (hwcfg2.b.op_mode) {
+ case MODE_HNP_SRP_CAPABLE:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_HNP_SRP_CAPABLE \n");
+ usbcfg.b.hnpcap = 1;
+ usbcfg.b.srpcap = 1;
+
+ otg_dbg(OTG_DBG_OCI,
+ "OTG_DBG_OCI : use HNP and SRP \n");
+ break;
+
+ case MODE_SRP_ONLY_CAPABLE:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_SRP_ONLY_CAPABLE \n");
+ usbcfg.b.srpcap = 1;
+ break;
+
+ case MODE_NO_HNP_SRP_CAPABLE:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_NO_HNP_SRP_CAPABLE \n");
+ usbcfg.b.hnpcap = 0;
+ break;
+
+ case MODE_SRP_CAPABLE_DEVICE:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_SRP_CAPABLE_DEVICE \n");
+ usbcfg.b.srpcap = 1;
+ break;
+
+ case MODE_NO_SRP_CAPABLE_DEVICE:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_NO_SRP_CAPABLE_DEVICE \n");
+ usbcfg.b.srpcap = 0;
+ break;
+
+ case MODE_SRP_CAPABLE_HOST:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_SRP_CAPABLE_HOST \n");
+ usbcfg.b.srpcap = 1;
+ break;
+
+ case MODE_NO_SRP_CAPABLE_HOST:
+ otg_dbg(OTG_DBG_OCI,
+ "GHWCFG2 OP Mode : MODE_NO_SRP_CAPABLE_HOST \n");
+ usbcfg.b.srpcap = 0;
+ break;
+ default :
+ otg_err(OTG_DBG_OCI, "ERR> hwcfg2\n ");
+ break;
+ }
+ write_reg_32 (GUSBCFG, usbcfg.d32);
+
+ /* Program the GINTMSK register.*/
+ gintmsk.b.modemismatch = 1;
+ gintmsk.b.sofintr = 1;
+ /*gintmsk.b.otgintr = 1; */
+ gintmsk.b.conidstschng = 1;
+ /*gintmsk.b.wkupintr = 1;*/
+ gintmsk.b.disconnect = 1;
+ /*gintmsk.b.usbsuspend = 1;*/
+ /*gintmsk.b.sessreqintr = 1;*/
+ /*gintmsk.b.portintr = 1;*/
+ /*gintmsk.b.hcintr = 1; */
+ write_reg_32(GINTMSK, gintmsk.d32);
+
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ otg_err(OTG_DBG_OCI, "Core Reset FAIL\n");
+ return USB_ERR_FAIL;
+ }
+}
+
+/**
+ * int oci_host_init(void)
+ *
+ * @brief Process host initialize as s5pc110 spec
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_host_init(void)
+{
+ gintmsk_t gintmsk = {.d32 = 0};
+ hcfg_t hcfg = {.d32 = 0};
+#if 0
+/*#ifdef CONFIG_USB_S3C_OTG_HOST_DTGDRVVBUS*/
+ hprt_t hprt;
+ hprt.d32 = read_reg_32(HPRT);
+#endif
+
+ otg_dbg(OTG_DBG_OCI, "oci_host_init\n");
+
+ gintmsk.b.portintr = 1;
+ update_reg_32(GINTMSK,gintmsk.d32);
+
+ hcfg.b.fslspclksel = HCFG_30_60_MHZ;
+ update_reg_32(HCFG, hcfg.d32);
+
+#if 0
+/*#ifdef CONFIG_USB_S3C_OTG_HOST_DTGDRVVBUS*/
+ /* turn on vbus */
+ if(!hprt.b.prtpwr) {
+ hprt.b.prtpwr = 1;
+ write_reg_32(HPRT, hprt.d32);
+
+ otg_dbg(true, "turn on Vbus\n");
+ }
+#endif
+
+ oci_config_flush_fifo(OTG_HOST_MODE);
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * int oci_start(void)
+ *
+ * @brief start to operate oci module by calling oci_core_init function
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_start(void)
+{
+ otg_dbg(OTG_DBG_OCI, "oci_start \n");
+
+ if(oci_core_init() == USB_ERR_SUCCESS) {
+ mdelay(50);
+ if(oci_init_mode() == USB_ERR_SUCCESS) {
+ oci_set_global_interrupt(true);
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ otg_dbg(OTG_DBG_OCI, "oci_init_mode() Fail\n");
+ return USB_ERR_FAIL;
+ }
+ }
+ else {
+ otg_dbg(OTG_DBG_OCI, "oci_core_init() Fail\n");
+ return USB_ERR_FAIL;
+ }
+}
+
+/**
+ * int oci_stop(void)
+ *
+ * @brief stop to opearte otg core
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_stop()
+{
+ gintmsk_t gintmsk = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_stop\n");
+
+ /* sometimes, port interrupt occured after removed
+ * otg host driver. so, we have to mask port interrupt. */
+ write_reg_32(GINTMSK, gintmsk.d32);
+
+ oci_set_global_interrupt(false);
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * oci_start_transfer(struct sec_otghost *otghost, stransfer_t *st_t)
+ *
+ * @brief start transfer by using transfer information to receive from scheduler
+ *
+ * @param [IN] *st_t - information about transfer to write register by calling oci_channel_init function
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+
+u8 oci_start_transfer(struct sec_otghost *otghost, stransfer_t *st_t)
+{
+ hcchar_t hcchar = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_start_transfer \n");
+
+ if(st_t->alloc_chnum ==CH_NONE) {
+
+ if( oci_channel_alloc(&(st_t->alloc_chnum)) == USB_ERR_SUCCESS) {
+ oci_channel_init(st_t->alloc_chnum, st_t);
+
+ hcchar.b.chen = 1;
+ update_reg_32(HCCHAR(st_t->alloc_chnum), hcchar.d32);
+ return st_t->alloc_chnum;
+ }
+ else {
+ otg_dbg(OTG_DBG_OCI,
+ "oci_start_transfer Fail - Channel Allocation Error\n");
+ return CH_NONE;
+ }
+ }
+ else {
+ oci_channel_init(st_t->alloc_chnum, st_t);
+
+ hcchar.b.chen = 1;
+ update_reg_32(HCCHAR(st_t->alloc_chnum), hcchar.d32);
+
+ return st_t->alloc_chnum;
+ }
+}
+
+/**
+ * int oci_stop_transfer(struct sec_otghost *otghost, u8 ch_num)
+ *
+ * @brief stop to transfer even if transfering
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_stop_transfer(struct sec_otghost *otghost, u8 ch_num)
+{
+ hcchar_t hcchar = {.d32 = 0};
+ hcintmsk_t hcintmsk = {.d32 = 0};
+ int count = 0, max_error_count = 10000;
+
+ otg_dbg(OTG_DBG_OCI,
+ "step1: oci_stop_transfer ch=%d, hcchar=0x%x\n",
+ ch_num, read_reg_32(HCCHAR(ch_num)));
+
+ if(ch_num>16)
+ return USB_ERR_FAIL;
+
+ otghost->ch_halt = true;
+
+ hcintmsk.b.chhltd = 1;
+ update_reg_32(HCINTMSK(ch_num),hcintmsk.d32);
+
+ hcchar.b.chdis = 1;
+ hcchar.b.chen = 1;
+ update_reg_32(HCCHAR(ch_num),hcchar.d32);
+
+ /* wait for Channel Disabled Interrupt */
+ do {
+ hcchar.d32 = read_reg_32(HCCHAR(ch_num));
+
+ if(count > max_error_count) {
+ otg_dbg(OTG_DBG_OCI,
+ "Warning!! oci_stop_transfer()"
+ "ChDis is not cleared! ch=%d, hcchar=0x%x\n",
+ ch_num, hcchar.d32);
+ break;
+ }
+ count++;
+
+ } while(hcchar.b.chdis);
+
+ //kevinh: wait for Channel Disabled Interrupt
+ count = 0;
+ do {
+ hcintmsk.d32 = read_reg_32(HCINT(ch_num));
+ if(count > max_error_count) {
+ printk("chhltd int never occurred! ch=%d, intreg=0x%x\n",
+ ch_num, hcintmsk.d32);
+ break;
+ }
+ count++;
+ } while(!hcintmsk.b.chhltd);
+
+ oci_channel_dealloc(ch_num);
+
+ clear_reg_32(HAINTMSK,ch_num);
+ write_reg_32(HCINT(ch_num),INT_ALL);
+ clear_reg_32(HCINTMSK(ch_num), INT_ALL);
+
+ otghost->ch_halt = false;
+ otg_dbg(OTG_DBG_OCI,
+ "step2 : oci_stop_transfer ch=%d, hcchar=0x%x\n",
+ ch_num, read_reg_32(HCCHAR(ch_num)));
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * int oci_channel_init( u8 ch_num, stransfer_t *st_t)
+ *
+ * @brief Process channel initialize to prepare starting transfer
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+int oci_channel_init( u8 ch_num, stransfer_t *st_t)
+{
+ u32 intr_enable = 0;
+ gintmsk_t gintmsk = {.d32 = 0};
+ hcchar_t hcchar = {.d32 = 0};
+ hctsiz_t hctsiz = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_channel_init \n");
+
+ /* Clear channel information */
+ write_reg_32(HCTSIZ(ch_num), 0);
+ write_reg_32(HCCHAR(ch_num), 0);
+ write_reg_32(HCINTMSK(ch_num), 0);
+ write_reg_32(HCINT(ch_num), INT_ALL);/*write clear*/
+ write_reg_32(HCDMA(ch_num), 0);
+
+ /* enable host channel interrupt in GINTSTS */
+ gintmsk.b.hcintr =1;
+ update_reg_32(GINTMSK, gintmsk.d32);
+ /* Enable the top level host channel interrupt in HAINT */
+ intr_enable = (1 << ch_num);
+ update_reg_32(HAINTMSK, intr_enable);
+ /* unmask the down level host channel interrupt in HCINT */
+ write_reg_32(HCINTMSK(ch_num),st_t->hc_reg.hc_int_msk.d32);
+
+ /* Program the HCSIZn register with the endpoint characteristics for */
+ hctsiz.b.xfersize = st_t->buf_size;
+ hctsiz.b.pktcnt = st_t->packet_cnt;
+
+ /* Program the HCCHARn register with the endpoint characteristics for */
+ hcchar.b.mps = st_t->ed_desc_p->max_packet_size;
+ hcchar.b.epnum = st_t->ed_desc_p->endpoint_num;
+ hcchar.b.epdir = st_t->ed_desc_p->is_ep_in;
+ hcchar.b.lspddev = (st_t->ed_desc_p->dev_speed == LOW_SPEED_OTG);
+ hcchar.b.eptype = st_t->ed_desc_p->endpoint_type;
+ hcchar.b.multicnt = st_t->ed_desc_p->mc;
+ hcchar.b.devaddr = st_t->ed_desc_p->device_addr;
+
+ if(st_t->ed_desc_p->endpoint_type == INT_TRANSFER ||
+ st_t->ed_desc_p->endpoint_type == ISOCH_TRANSFER) {
+ u32 uiFrameNum = 0;
+ uiFrameNum = oci_get_frame_num();
+
+ hcchar.b.oddfrm = uiFrameNum%2?1:0;
+
+ /*
+ * if transfer type is periodic transfer,
+ * must support sof interrupt
+ */
+
+ /*
+ gintmsk.b.sofintr = 1;
+ update_reg_32(GINTMSK, gintmsk.d32);
+ */
+ }
+
+ if(st_t->ed_desc_p->endpoint_type == CONTROL_TRANSFER) {
+ td_t *td_p;
+ td_p = (td_t *)st_t->parent_td;
+
+ switch(td_p->standard_dev_req_info.conrol_transfer_stage) {
+ case SETUP_STAGE:
+ hctsiz.b.pid = st_t->ed_status_p->control_data_tgl.setup_tgl;
+ hcchar.b.epdir = EP_OUT;
+ break;
+ case DATA_STAGE:
+ hctsiz.b.pid = st_t->ed_status_p->control_data_tgl.data_tgl;
+ hcchar.b.epdir = st_t->ed_desc_p->is_ep_in;
+ break;
+ case STATUS_STAGE:
+ hctsiz.b.pid = st_t->ed_status_p->control_data_tgl.status_tgl;
+
+ if(td_p->standard_dev_req_info.is_data_stage) {
+ hcchar.b.epdir = ~(st_t->ed_desc_p->is_ep_in);
+ }
+ else {
+ hcchar.b.epdir = EP_IN;
+ }
+ break;
+ default:break;
+ }
+ }
+ else {
+ hctsiz.b.pid = st_t->ed_status_p->data_tgl;
+ }
+
+ hctsiz.b.dopng = st_t->ed_status_p->is_ping_enable;
+ write_reg_32(HCTSIZ(ch_num),hctsiz.d32);
+ st_t->ed_status_p->is_ping_enable = false;
+
+ /* Write DMA Address */
+ write_reg_32(HCDMA(ch_num),st_t->start_phy_buf_addr);
+
+ /* Wrote HCCHAR Register */
+ write_reg_32(HCCHAR(ch_num),hcchar.d32);
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * u32 oci_get_frame_num(void)
+ *
+ * @brief Get current frame number by reading register.
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+u32 oci_get_frame_num(void)
+{
+ hfnum_t hfnum;
+ hfnum.d32 = read_reg_32(HFNUM);
+
+ otg_dbg(OTG_DBG_OCI, " oci_get_frame_num=%d\n", hfnum.b.frnum);
+
+ return hfnum.b.frnum;
+}
+
+/**
+ * u16 oci_get_frame_interval(void)
+ *
+ * @brief Get current frame interval by reading register.
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ * @remark
+ *
+ */
+u16 oci_get_frame_interval(void)
+{
+ hfir_t hfir;
+ hfir.d32 = read_reg_32(HFIR);
+ return hfir.b.frint;
+}
+
+void oci_set_frame_interval(u16 interval)
+{
+ hfir_t hfir = {.d32 = 0};
+ hfir.b.frint = interval;
+ write_reg_32(HFIR, hfir.d32);
+}
+
+/* OCI Internal Functions */
+
+int oci_channel_alloc(u8 *ch_num)
+{
+ u8 ch;
+
+ hcchar_t hcchar = {.d32 = 0};
+
+ for(ch = 0 ; ch<16 ; ch++) {
+ if(ch_enable[ch] == true) {
+ hcchar.d32 = read_reg_32(HCCHAR(ch));
+
+ if(hcchar.b.chdis == 0) {
+ *ch_num = ch;
+ ch_enable[ch] = false;
+ return USB_ERR_SUCCESS;
+ }
+ }
+ }
+
+ return USB_ERR_FAIL;
+}
+
+int oci_channel_dealloc(u8 ch_num)
+{
+ if(ch_num < 16 && ch_enable[ch_num] == false) {
+ ch_enable[ch_num] = true;
+
+ write_reg_32(HCTSIZ(ch_num), 0);
+ write_reg_32(HCCHAR(ch_num), 0);
+ write_reg_32(HCINTMSK(ch_num), 0);
+ write_reg_32(HCINT(ch_num), INT_ALL);
+ write_reg_32(HCDMA(ch_num), 0);
+ return USB_ERR_SUCCESS;
+ }
+
+ return USB_ERR_FAIL;
+}
+
+int oci_sys_init(void)
+{
+ otg_host_phy_init();
+
+ return USB_ERR_SUCCESS;
+}
+
+void oci_set_global_interrupt(bool set)
+{
+ gahbcfg_t ahbcfg;
+
+ otg_dbg(OTG_DBG_OCI, " oci_set_global_interrupt\n");
+
+ ahbcfg.d32 = 0;
+ ahbcfg.b.glblintrmsk = 1;
+
+ if(set) {
+ update_reg_32(GAHBCFG,ahbcfg.d32);
+ }
+ else {
+ clear_reg_32(GAHBCFG,ahbcfg.d32);
+ }
+}
+
+int oci_init_mode(void)
+{
+ gintsts_t gintsts;
+
+ gintsts.d32 = read_reg_32(GINTSTS);
+
+ otg_dbg(OTG_DBG_OCI,
+ "GINSTS = 0x%x,GINMSK = 0x%x.\n",
+ (unsigned int)gintsts.d32,
+ (unsigned int)read_reg_32(GINTMSK));
+
+ if(gintsts.b.curmode == OTG_HOST_MODE) {
+ otg_dbg(OTG_DBG_OCI, "HOST Mode\n");
+
+ if(oci_host_init() == USB_ERR_SUCCESS) {
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ otg_dbg(OTG_DBG_OCI, "oci_host_init() Fail\n");
+ return USB_ERR_FAIL;
+ }
+ }
+ else { /* Device Mode */
+ otg_dbg(OTG_DBG_OCI, "DEVICE Mode\n");
+ if(oci_dev_init() == USB_ERR_SUCCESS) {
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ otg_err(OTG_DBG_OCI, "oci_dev_init() Fail\n");
+ return USB_ERR_FAIL;
+ }
+ }
+
+ return USB_ERR_SUCCESS;
+}
+
+void oci_config_flush_fifo(u32 mode)
+{
+ ghwcfg2_t hwcfg2 = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_config_flush_fifo\n");
+
+ hwcfg2.d32 = read_reg_32(GHWCFG2);
+
+ /* Configure data FIFO sizes */
+ if (hwcfg2.b.dynamic_fifo) {
+ /* Rx FIFO */
+ write_reg_32(GRXFSIZ, 0x0000010D);
+
+ /* Non-periodic Tx FIFO */
+ write_reg_32(GNPTXFSIZ, 0x0080010D);
+
+ if (mode == OTG_HOST_MODE) {
+ /* For Periodic transactions, */
+ /* program HPTXFSIZ */
+ }
+ }
+
+ /* Flush the FIFOs */
+ oci_flush_tx_fifo(0);
+
+ oci_flush_rx_fifo();
+}
+
+void oci_flush_tx_fifo(u32 num)
+{
+ grstctl_t greset = {.d32 = 0};
+ u32 count = 0;
+
+ otg_dbg(OTG_DBG_OCI, "oci_flush_tx_fifo\n");
+
+ greset.b.txfflsh = 1;
+ greset.b.txfnum = num;
+ write_reg_32(GRSTCTL, greset.d32);
+
+ /* wait for flush to end */
+ while (greset.b.txfflsh == 1) {
+ greset.d32 = read_reg_32(GRSTCTL);
+ if (++count > MAX_COUNT)
+ break;
+ };
+
+ /* Wait for 3 PHY Clocks*/
+ udelay(30);
+}
+
+void oci_flush_rx_fifo(void)
+{
+ grstctl_t greset = {.d32 = 0};
+ u32 count = 0;
+
+ otg_dbg(OTG_DBG_OCI, "oci_flush_rx_fifo\n");
+
+ greset.b.rxfflsh = 1;
+ write_reg_32(GRSTCTL, greset.d32 );
+
+ do {
+ greset.d32 = read_reg_32(GRSTCTL);
+ if (++count > MAX_COUNT)
+ break;
+ } while (greset.b.rxfflsh == 1);
+
+ /* Wait for 3 PHY Clocks*/
+ udelay(30);
+}
+
+int oci_core_reset(void)
+{
+ u32 count = 0;
+ grstctl_t greset = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_core_reset\n");
+
+ /* Wait for AHB master IDLE state. */
+ do {
+ greset.d32 = read_reg_32 (GRSTCTL);
+ mdelay (50);
+
+ if(++count>100) {
+ otg_dbg(OTG_DBG_OCI, "AHB status is not IDLE\n");
+ return USB_ERR_FAIL;
+ }
+ } while (greset.b.ahbidle != 1);
+
+ /* Core Soft Reset */
+ greset.b.csftrst = 1;
+ write_reg_32 (GRSTCTL, greset.d32);
+
+ /* Wait for 3 PHY Clocks*/
+ mdelay (50);
+ return USB_ERR_SUCCESS;
+}
+
+int oci_dev_init(void)
+{
+ otg_dbg(OTG_DBG_OCI, "oci_dev_init - do nothing.\n");
+ /* return USB_ERR_FAIL; */
+ return USB_ERR_SUCCESS;
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-oci.h b/drivers/usb/host/s3c-otg/s3c-otg-oci.h
new file mode 100644
index 0000000..fcc9f07
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-oci.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] :s3c-otg-oci.h
+ * [Description] : The Header file defines the external and internal functions of OCI.
+ * [Author] : Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * [Department] : System LSI Division/Embedded S/W Platform
+ * [Created Date]: 2008/06/18
+ * [Revision History]
+ * (1) 2008/06/25 by Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * - Added some functions and data structure of OCI
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _OCI_H_
+#define _OCI_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-regdef.h"
+#include "s3c-otg-hcdi-kal.h"
+#include "s3c-otg-hcdi-memory.h"
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-roothub.h"
+#include "s3c-otg-hcdi-hcd.h"
+
+#include <mach/map.h> //virtual address for smdk
+
+extern void otg_host_phy_init(void);
+#include <mach/regs-clock.h>
+
+//OCI interace
+int oci_init(struct sec_otghost *otghost);
+
+int oci_start(void);
+int oci_stop(void);
+
+u8 oci_start_transfer(struct sec_otghost *otghost, stransfer_t *st_t);
+int oci_stop_transfer(struct sec_otghost *otghost, u8 ch_num);
+
+int oci_channel_init(u8 ch_num, stransfer_t *st_t);
+u32 oci_get_frame_num(void);
+u16 oci_get_frame_interval(void);
+void oci_set_frame_interval(u16 intervl);
+
+///OCI Internal Functions
+int oci_sys_init(void);
+int oci_core_init(void);
+int oci_init_mode(void);
+int oci_host_init(void);
+int oci_dev_init(void);
+
+int oci_channel_alloc(u8 *ch_num);
+int oci_channel_dealloc(u8 ch_num);
+
+void oci_config_flush_fifo(u32 mode);
+void oci_flush_tx_fifo(u32 num);
+void oci_flush_rx_fifo(void);
+
+int oci_core_reset(void);
+void oci_set_global_interrupt(bool set);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _OCI_H_ */
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-roothub.c b/drivers/usb/host/s3c-otg/s3c-otg-roothub.c
new file mode 100644
index 0000000..56eb195
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-roothub.c
@@ -0,0 +1,605 @@
+/* for* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 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.
+ * ========================================================================== */
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : RootHub.c
+ * [Description] : The file implement the external and internal functions of RootHub
+ * [Author] : Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * [Department] : System LSI Division/Embedded S/W Platform
+ * [Created Date]: 2009/02/10
+ * [Revision History]
+ * (1) 2008/06/13 by Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * - Created this file and implements functions of RootHub
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-roothub.h"
+
+static void setPortPower(bool on)
+{
+#ifdef CONFIG_USB_S3C_OTG_HOST_DTGDRVVBUS
+ hprt_t hprt = {.d32 = 0};
+
+ if(on) {
+ hprt.d32 = read_reg_32(HPRT);
+ if(!hprt.b.prtpwr) {
+ /*hprt.d32 = 0;*/
+ hprt.b.prtpwr = 1;
+ write_reg_32(HPRT, hprt.d32);
+ }
+ }
+ else {
+ hprt.b.prtpwr = 1;
+ clear_reg_32(HPRT, hprt.d32);
+ }
+#else
+ otg_dbg(true, "turn %s Vbus\n", on ? "on" : "off");
+#endif
+}
+
+/**
+ * int get_otg_port_status(const u8 port, char* status)
+ *
+ * @brief Get port change bitmap information
+ *
+ * @param [IN] port : port number
+ * [OUT] status : buffer to store bitmap information
+ *
+ * @returnUSB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ *
+ * @remark
+ *
+ */
+__inline__ int get_otg_port_status(
+ struct usb_hcd *hcd, const u8 port, char *status)
+{
+
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+ /* return root_hub_feature(port, GetPortStatus, NULL, status); */
+#if 0
+ /* for debug */
+ hprt_t hprt;
+
+ hprt.d32 = read_reg_32(HPRT);
+
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "HPRT:spd=%d,pwr=%d,lnsts=%d,rst=%d,susp=%d,res=%d,ovrcurract=%d,ena=%d,connsts=%d\n",
+ hprt.b.prtspd,
+ hprt.b.prtpwr,
+ hprt.b.prtlnsts,
+ hprt.b.prtrst,
+ hprt.b.prtsusp,
+ hprt.b.prtres,
+ hprt.b.prtovrcurract,
+ hprt.b.prtena,
+ hprt.b.prtconnsts);
+
+#endif
+ status[port] = 0;
+ status[port] |= (otghost->port_flag.b.port_connect_status_change ||
+ otghost->port_flag.b.port_reset_change ||
+ otghost->port_flag.b.port_enable_change ||
+ otghost->port_flag.b.port_suspend_change ||
+ otghost->port_flag.b.port_over_current_change) << 1;
+
+#if 0
+ //* for debug */
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "connect:%d,reset:%d,enable:%d,suspend:%d,over_current:%d\n",
+ otghost->port_flag.b.port_connect_status_change,
+ otghost->port_flag.b.port_reset_change,
+ otghost->port_flag.b.port_enable_change,
+ otghost->port_flag.b.port_suspend_change,
+ otghost->port_flag.b.port_over_current_change);
+#endif
+
+ if (status[port]) {
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " Root port status changed\n");
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " port_connect_status_change: %d\n",
+ otghost->port_flag.b.port_connect_status_change);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " port_reset_change: %d\n",
+ otghost->port_flag.b.port_reset_change);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " port_enable_change: %d\n",
+ otghost->port_flag.b.port_enable_change);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " port_suspend_change: %d\n",
+ otghost->port_flag.b.port_suspend_change);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " port_over_current_change: %d\n",
+ otghost->port_flag.b.port_over_current_change);
+ }
+
+ return (status[port] !=0);
+}
+
+/**
+ * int reset_and_enable_port(struct usb_hcd *hcd, const u8 port)
+ *
+ * @brief Reset port and make enable status the specific port
+ *
+ * @param [IN] port : port number
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ *
+ * @remark
+ *
+ */
+int reset_and_enable_port(struct usb_hcd *hcd, const u8 port)
+{
+ hprt_t hprt;
+ u32 count = 0;
+ u32 max_error_count = 10000;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ hprt.d32 = read_reg_32(HPRT);
+
+ otg_dbg(OTG_DBG_ROOTHUB,
+ " reset_and_enable_port\n");
+
+ if(hprt.b.prtconnsts==0) {
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "No Attached Device, HPRT = 0x%x\n", hprt.d32);
+
+ otghost->port_flag.b.port_connect_status_change = 1;
+ otghost->port_flag.b.port_connect_status = 0;
+
+ return USB_ERR_FAIL;
+ }
+
+ if(!hprt.b.prtena) {
+ hprt.b.prtrst = 1; /* drive reset */
+ write_reg_32(HPRT, hprt.d32);
+
+ mdelay(60);
+ hprt.b.prtrst = 0;
+ write_reg_32(HPRT, hprt.d32);
+
+ do {
+ hprt.d32 = read_reg_32(HPRT);
+
+ if(count > max_error_count) {
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "Port Reset Fail : HPRT : 0x%x\n", hprt.d32);
+ return USB_ERR_FAIL;
+ }
+ count++;
+
+ } while(!hprt.b.prtena);
+
+ }
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * int root_hub_feature(
+ * struct usb_hcd *hcd,
+ * const u8 port,
+ * const u16 type_req,
+ * const u16 feature,
+ * void* buf)
+ *
+ * @brief Get port change bitmap information
+ *
+ * @param [IN] port : port number
+ * [IN] type_req : request type of hub feature as usb 2.0 spec
+ * [IN] feature : hub feature as usb 2.0 spec
+ * [OUT] status : buffer to store results
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ *
+ * @remark
+ *
+ */
+__inline__ int root_hub_feature(
+ struct usb_hcd *hcd,
+ const u8 port,
+ const u16 type_req,
+ const u16 feature,
+ void *buf)
+{
+ int retval = USB_ERR_SUCCESS;
+ usb_hub_descriptor_t *desc = NULL;
+ u32 port_status = 0;
+ hprt_t hprt = {.d32 = 0};
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_ROOTHUB, " root_hub_feature\n");
+
+ switch (type_req) {
+ case ClearHubFeature:
+ otg_dbg(OTG_DBG_ROOTHUB, "case ClearHubFeature\n");
+ switch (feature) {
+ case C_HUB_LOCAL_POWER:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearHubFeature -C_HUB_LOCAL_POWER\n");
+ break;
+ case C_HUB_OVER_CURRENT:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearHubFeature -C_HUB_OVER_CURRENT\n");
+ /* Nothing required here */
+ break;
+ default:
+ retval = USB_ERR_FAIL;
+ }
+ break;
+
+ case ClearPortFeature:
+ otg_dbg(OTG_DBG_ROOTHUB, "case ClearPortFeature\n");
+ switch (feature) {
+ case USB_PORT_FEAT_ENABLE:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_ENABLE\n");
+ hprt.b.prtena = 1;
+ update_reg_32(HPRT, hprt.d32);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_SUSPEND\n");
+ bus_resume(otghost);
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_POWER\n");
+ setPortPower(false);
+ break;
+
+ case USB_PORT_FEAT_INDICATOR:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_INDICATOR\n");
+ /* Port inidicator not supported */
+ break;
+
+ case USB_PORT_FEAT_C_CONNECTION:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_C_CONNECTION\n");
+ /* Clears drivers internal connect status change flag */
+ otghost->port_flag.b.port_connect_status_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_RESET:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_C_RESET\n");
+ /* Clears the driver's internal Port Reset Change flag*/
+ otghost->port_flag.b.port_reset_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_ENABLE:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_C_ENABLE\n");
+ /* Clears the driver's internal Port Enable/Disable Change flag */
+ otghost->port_flag.b.port_enable_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_SUSPEND:
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature -USB_PORT_FEAT_C_SUSPEND\n");
+ /* Clears the driver's internal Port Suspend
+ * Change flag, which is set when resume signaling on
+ * the host port is complete */
+ otghost->port_flag.b.port_suspend_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ otg_dbg(OTG_DBG_ROOTHUB, "case ClearPortFeature - \
+ USB_PORT_FEAT_C_OVER_CURRENT\n");
+ otghost->port_flag.b.port_over_current_change = 0;
+ break;
+
+ default:
+ retval = USB_ERR_FAIL;
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case ClearPortFeature - FAIL\n");
+ }
+ break;
+
+ case GetHubDescriptor:
+ otg_dbg(OTG_DBG_ROOTHUB, "case GetHubDescriptor\n");
+ desc = (usb_hub_descriptor_t *)buf;
+ desc->desc_length = 9;
+ desc->desc_type = 0x29;
+ desc->port_number = 1;
+ desc->hub_characteristics = 0x08;
+ desc->power_on_to_power_good = 1;
+ desc->hub_control_current = 0;
+ desc->DeviceRemovable[0] = 0;
+ desc->DeviceRemovable[1] = 0xff;
+ break;
+
+ case GetHubStatus:
+ otg_dbg(OTG_DBG_ROOTHUB, "case GetHubStatus\n");
+ otg_mem_set(buf, 0, 4);
+ break;
+
+ case GetPortStatus:
+ otg_dbg(OTG_DBG_ROOTHUB, "case GetPortStatus\n");
+
+ if (otghost->port_flag.b.port_connect_status_change) {
+ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case GetPortStatus - USB_PORT_FEAT_C_CONNECTION\n");
+ }
+
+ if (otghost->port_flag.b.port_enable_change) {
+ port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case GetPortStatus - USB_PORT_FEAT_C_ENABLE\n");
+ }
+
+ if (otghost->port_flag.b.port_suspend_change) {
+ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case GetPortStatus - USB_PORT_FEAT_C_SUSPEND\n");
+ }
+
+ if (otghost->port_flag.b.port_reset_change) {
+ port_status|= (1 << USB_PORT_FEAT_C_RESET);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case GetPortStatus - USB_PORT_FEAT_C_RESET\n");
+ }
+
+ if (otghost->port_flag.b.port_over_current_change) {
+ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case GetPortStatus - USB_PORT_FEAT_C_OVER_CURRENT\n");
+ }
+
+ if (!otghost->port_flag.b.port_connect_status) {
+ /*
+ * The port is disconnected, which means the core is
+ * either in device mode or it soon will be. Just
+ * return 0's for the remainder of the port status
+ * since the port register can't be read if the core
+ * is in device mode.
+ */
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case GetPortStatus - disconnected\n");
+
+ *((__le32*)buf) = cpu_to_le32(port_status);
+ /*break;*/
+ }
+
+ hprt.d32 = read_reg_32(HPRT);
+
+ if (hprt.b.prtconnsts)
+ port_status|= (1 << USB_PORT_FEAT_CONNECTION);
+
+ if (hprt.b.prtena)
+ port_status |= (1 << USB_PORT_FEAT_ENABLE);
+
+ if (hprt.b.prtsusp)
+ port_status |= (1 << USB_PORT_FEAT_SUSPEND);
+
+ if (hprt.b.prtovrcurract)
+ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
+
+ if (hprt.b.prtrst)
+ port_status |= (1 << USB_PORT_FEAT_RESET);
+
+ if (hprt.b.prtpwr)
+ port_status |= (1 << USB_PORT_FEAT_POWER);
+
+ if (hprt.b.prtspd == 0) {
+ port_status |= USB_PORT_STAT_HIGH_SPEED;
+ }
+ else {
+ if (hprt.b.prtspd == 2)
+ port_status |= USB_PORT_STAT_LOW_SPEED;
+ }
+
+ if (hprt.b.prttstctl)
+ port_status |= (1 << USB_PORT_FEAT_TEST);
+
+ *((__le32*)buf) = cpu_to_le32(port_status);
+
+ otg_dbg(OTG_DBG_ROOTHUB, "port_status=0x%x.\n", port_status);
+ break;
+
+ case SetHubFeature:
+ otg_dbg(OTG_DBG_ROOTHUB, "case SetHubFeature\n");
+ /* No HUB features supported */
+ break;
+
+ case SetPortFeature:
+ otg_dbg(OTG_DBG_ROOTHUB, "case SetPortFeature\n");
+ if (!otghost->port_flag.b.port_connect_status) {
+ /*
+ * The port is disconnected, which means the core is
+ * either in device mode or it soon will be. Just
+ * return without doing anything since the port
+ * register can't be written if the core is in device
+ * mode.
+ */
+ otg_dbg(OTG_DBG_ROOTHUB,
+ "case SetPortFeature - disconnected\n");
+
+ /*break;*/
+ }
+
+ switch (feature) {
+ case USB_PORT_FEAT_SUSPEND:
+ otg_dbg(true,
+ "case SetPortFeature -USB_PORT_FEAT_SUSPEND\n");
+ bus_suspend();
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ otg_dbg(true,
+ "case SetPortFeature -USB_PORT_FEAT_POWER\n");
+ setPortPower(true);
+ break;
+
+ case USB_PORT_FEAT_RESET:
+ otg_dbg(true,
+ "case SetPortFeature -USB_PORT_FEAT_RESET\n");
+ retval = reset_and_enable_port(hcd, port);
+ /*
+ if(retval == USB_ERR_SUCCESS)
+ wake_lock(&otghost->wake_lock);
+ */
+ break;
+
+ case USB_PORT_FEAT_INDICATOR:
+ otg_dbg(true,
+ "case SetPortFeature -USB_PORT_FEAT_INDICATOR\n");
+ break;
+
+ default :
+ otg_dbg(true, "case SetPortFeature -USB_ERR_FAIL\n");
+ retval = USB_ERR_FAIL;
+ break;
+ }
+ break;
+
+ default:
+ retval = USB_ERR_FAIL;
+ otg_err(true, "root_hub_feature() Function Error\n");
+ break;
+ }
+
+ if(retval != USB_ERR_SUCCESS)
+ retval = USB_ERR_FAIL;
+
+ return retval;
+}
+
+/**
+ * void bus_suspend(void)
+ *
+ * @brief Make suspend status when this platform support PM Mode
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+void bus_suspend(void)
+{
+ hprt_t hprt;
+ pcgcctl_t pcgcctl;
+
+ otg_dbg(OTG_DBG_ROOTHUB, " bus_suspend\n");
+
+ hprt.d32 = 0;
+ pcgcctl.d32 = 0;
+
+ hprt.b.prtsusp = 1;
+ update_reg_32(HPRT, hprt.d32);
+
+ pcgcctl.b.pwrclmp = 1;
+ update_reg_32(PCGCCTL,pcgcctl.d32);
+ udelay(1);
+
+ pcgcctl.b.rstpdwnmodule = 1;
+ update_reg_32(PCGCCTL,pcgcctl.d32);
+ udelay(1);
+
+ pcgcctl.b.stoppclk = 1;
+ update_reg_32(PCGCCTL,pcgcctl.d32);
+ udelay(1);
+}
+
+/**
+ * int bus_resume(struct sec_otghost *otghost)
+ *
+ * @brief Make resume status when this platform support PM Mode
+ *
+ * @param None
+ *
+ * @return USB_ERR_SUCCESS : If success \n
+ * USB_ERR_FAIL : If call fail \n
+ *
+ * @remark
+ *
+ */
+int bus_resume(struct sec_otghost *otghost)
+{
+ /*
+ hprt_t hprt;
+ pcgcctl_t pcgcctl;
+ hprt.d32 = 0;
+ pcgcctl.d32 = 0;
+
+ pcgcctl.b.stoppclk = 1;
+ clear_reg_32(PCGCCTL,pcgcctl.d32);
+ udelay(1);
+
+ pcgcctl.b.pwrclmp = 1;
+ clear_reg_32(PCGCCTL,pcgcctl.d32);
+ udelay(1);
+
+ pcgcctl.b.rstpdwnmodule = 1;
+ clear_reg_32(PCGCCTL,pcgcctl.d32);
+ udelay(1);
+
+ hprt.b.prtres = 1;
+ update_reg_32(HPRT, hprt.d32);
+ mdelay(20);
+
+ clear_reg_32(HPRT, hprt.d32);
+ */
+ otg_dbg(OTG_DBG_ROOTHUB, "bus_resume()......\n");
+
+ otg_dbg(OTG_DBG_ROOTHUB, "wait for 50 ms...\n");
+
+ mdelay(50);
+ if(oci_init(otghost) == USB_ERR_SUCCESS) {
+ if(oci_start() == USB_ERR_SUCCESS) {
+ otg_dbg(OTG_DBG_ROOTHUB, "OTG Init Success\n");
+ return USB_ERR_SUCCESS;
+ }
+ }
+
+ return USB_ERR_FAIL;
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-roothub.h b/drivers/usb/host/s3c-otg/s3c-otg-roothub.h
new file mode 100644
index 0000000..03883d1
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-roothub.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] :s3c-otg-roothub.h
+ * [Description] : The Header file defines the external and internal functions of RootHub.
+ * [Author] : Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * [Department] : System LSI Division/Embedded S/W Platform
+ * [Created Date]: 2008/06/13
+ * [Revision History]
+ * (1) 2008/06/13 by Jang Kyu Hyeok { kyuhyeok.jang@samsung.com }
+ * - Created this file and defines functions of RootHub
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _ROOTHUB_H_
+#define _ROOTHUB_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-regdef.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-hcdi-kal.h"
+#include "s3c-otg-hcdi-memory.h"
+#include "s3c-otg-oci.h"
+
+__inline__ int root_hub_feature(
+ struct usb_hcd *hcd,
+ const u8 port,
+ const u16 type_req,
+ const u16 feature,
+ void *buf);
+
+__inline__ int get_otg_port_status(
+ struct usb_hcd *hcd, const u8 port, char *status);
+
+int reset_and_enable_port(struct usb_hcd *hcd, const u8 port);
+void bus_suspend(void);
+
+int bus_resume(struct sec_otghost *otghost);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _ROOTHUB_H_ */
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-scheduler-ischeduler.c b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-ischeduler.c
new file mode 100644
index 0000000..d94fb1a
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-ischeduler.c
@@ -0,0 +1,369 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : Scheduler.c
+ * [Description] : The source file implements the internal functions of Scheduler.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2009/2/10
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of Scheduler
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-scheduler-scheduler.h"
+
+void init_scheduler(void)
+{
+ /*init_scheduling();*/
+ init_transfer_ready_q();
+}
+
+/******************************************************************************/
+/*!
+ * @name int reserve_used_resource_for_periodic(u32 usb_time)
+ *
+ * @brief this function reserves the necessary resource of USB Transfer for Periodic Transfer.
+ * So, this function firstly checks there ares some available USB Time
+ * and Channel resource for USB Transfer.
+ * if there exists necessary resources for Periodic Transfer, then reserves the resource.
+ *
+ * @param [IN] usb_time = indicates the USB Time for the USB Transfer.
+ *
+ * @return USB_ERR_SUCCESS - if success to insert pInsertED to S3CScheduler.
+ * USB_ERR_NO_BANDWIDTH - if fail to reserve the USB Bandwidth.
+ * USB_ERR_NO_CHANNEL - if fail to reserve the Channel.
+ */
+/******************************************************************************/
+
+int reserve_used_resource_for_periodic(u32 usb_time, u8 dev_speed, u8 trans_type)
+{
+ if(inc_perio_bus_time(usb_time,dev_speed)==USB_ERR_SUCCESS) {
+ if(inc_perio_chnum()==USB_ERR_SUCCESS) {
+ otg_usbcore_inc_usb_bandwidth(usb_time);
+ otg_usbcore_inc_periodic_transfer_cnt(trans_type);
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ dec_perio_bus_time(usb_time);
+ return USB_ERR_NO_CHANNEL;
+ }
+ }
+ else {
+ return USB_ERR_NO_BANDWIDTH;
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int free_usb_resource_for_periodic(ed_t * pFreeED)
+ *
+ * @brief this function frees the resources to be allocated to pFreeED at S3CScheduler.
+ * that is, this functions only releases the resources to be allocated by S3C6400Scheduler.
+ *
+ * @param [IN] pFreeED = indicates ed_t to have the information of the resource to be released.
+ *
+ * @return USB_ERR_SUCCESS - if success to free the USB Resource.
+ * USB_ERR_FAIL - if fail to free the USB Resrouce.
+ */
+/******************************************************************************/
+int free_usb_resource_for_periodic(
+ u32 free_usb_time, u8 free_chnum, u8 trans_type)
+{
+ if(dec_perio_bus_time(free_usb_time)==USB_ERR_SUCCESS) {
+ if(dec_perio_chnum()==USB_ERR_SUCCESS) {
+ if(free_chnum!=CH_NONE) {
+ oci_channel_dealloc(free_chnum);
+ set_transferring_td_array(free_chnum, 0);
+ }
+ otg_usbcore_des_usb_bandwidth(free_usb_time);
+ otg_usbcore_des_periodic_transfer_cnt(trans_type);
+ return USB_ERR_SUCCESS;
+ }
+ }
+ return USB_ERR_FAIL;
+}
+
+/******************************************************************************/
+/*!
+ * @name int remove_ed_from_scheduler(ed_t * remove_ed)
+ *
+ * @brief this function just remove the remove_ed from TransferReadyQ. So if you want to
+ * stop the USB Tranfer of remove_ed or release the releated resources.
+ * you should call another functions of S3CScheduler.
+ *
+ * @param [IN] remove_ed = indicates ed_t to be removed from TransferReadyQ.
+ *
+ * @return USB_ERR_SUCCESS - if success to remove the remove_ed from TransferReadyQ.
+ * USB_ERR_FAIL - if fail to remove the remove_ed from TransferReadyQ.
+ */
+ /******************************************************************************/
+int remove_ed_from_scheduler(ed_t *remove_ed)
+{
+ if(remove_ed->ed_status.is_in_transfer_ready_q) {
+ remove_ed_from_ready_q(remove_ed);
+ remove_ed->ed_status.is_in_transfer_ready_q = false;
+
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td)
+ *
+ * @brief this function stop to execute the USB Transfer of cancel_td and
+ * release the Channel Resources to be allocated the cancel_td ,if the Transfer Type of
+ * cancel_td is NonPeriodic Transfer.
+ * this function don't release any usb resources(Channel, USB Bandwidth) for Periodic Transfer.
+ * if you want to release some usb resources for a periodic Transfer, you should call
+ * the free_usb_resource_for_periodic()
+ *
+ * @param [IN] cancel_td = indicates the td_t to be canceled.
+ *
+ * @return USB_ERR_SUCCESS - if success to cancel the USB Transfer of cancel_td.
+ * USB_ERR_FAIL - if fail to cancel the USB Transfer of cancel_td.
+ */
+ /******************************************************************************/
+int cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td)
+{
+ if(cancel_td->is_transfer_done) {
+ return USB_ERR_FAIL;
+ }
+
+ if(cancel_td->is_transferring) {
+ int err;
+
+ err = oci_stop_transfer(otghost, cancel_td->cur_stransfer.alloc_chnum);
+
+ if(err == USB_ERR_SUCCESS) {
+ set_transferring_td_array(cancel_td->cur_stransfer.alloc_chnum,0);
+
+ cancel_td->cur_stransfer.alloc_chnum = CH_NONE;
+ cancel_td->is_transferring = false;
+ cancel_td->parent_ed_p->ed_status.is_in_transferring = false;
+ cancel_td->parent_ed_p->ed_status.in_transferring_td = 0;
+ cancel_td->parent_ed_p->is_need_to_insert_scheduler = true;
+
+ if(cancel_td->cur_stransfer.ed_desc_p->endpoint_type == BULK_TRANSFER ||
+ cancel_td->cur_stransfer.ed_desc_p->endpoint_type == CONTROL_TRANSFER ) {
+ dec_nonperio_chnum();
+ }
+ return err;
+ }
+ else {
+ return err;
+ }
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+ return USB_ERR_SUCCESS;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int retransmit(struct sec_otghost *otghost, td_t *retrasmit_td)
+ *
+ * @brief this function retransmits the retrasmit_td immediately.
+ * So, the Channel of pRetransmitted is reused for retransmittion.
+ *
+ * @param [IN] retrasmit_td = indicates the pointer ot the td_t to be retransmitted.
+ *
+ * @return USB_ERR_SUCCESS - if success to retransmit the retrasmit_td.
+ * USB_ERR_FAIL - if fail to retransmit the retrasmit_td.
+ */
+ /******************************************************************************/
+int retransmit(struct sec_otghost *otghost, td_t *retrasmit_td)
+{
+ u32 td_addr=0;
+
+ if(get_transferring_td_array(retrasmit_td->cur_stransfer.alloc_chnum,&td_addr)==USB_ERR_SUCCESS) {
+ if(td_addr == (u32)retrasmit_td) {
+ if(oci_start_transfer(otghost, &retrasmit_td->cur_stransfer)
+ == retrasmit_td->cur_stransfer.alloc_chnum) {
+ retrasmit_td->is_transferring = true;
+ retrasmit_td->parent_ed_p->ed_status.in_transferring_td = (u32)retrasmit_td;
+ retrasmit_td->parent_ed_p->ed_status.is_in_transfer_ready_q = false;
+ retrasmit_td->parent_ed_p->ed_status.is_in_transferring = true;
+ }
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+
+ return USB_ERR_SUCCESS;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name int reschedule(td_t *reschedule_td)
+ *
+ * @brief this function re-schedules the reschedule_td.
+ * So, the Channel of pRescheuleTD is released and reschedule_td is inserted to TransferReadyQ.
+ *
+ * @param [IN] reschedule_td = indicates the pointer ot the td_t to be rescheduled.
+ *
+ * @return USB_ERR_SUCCESS - if success to re-schedule the reschedule_td.
+ * USB_ERR_FAIL - if fail to re-schedule the reschedule_td.
+ */
+ /******************************************************************************/
+int reschedule(td_t *reschedule_td)
+{
+ u32 td_addr;
+
+ if(get_transferring_td_array(reschedule_td->cur_stransfer.alloc_chnum, &td_addr)==USB_ERR_SUCCESS)
+ {
+ if((u32)reschedule_td == td_addr)
+ {
+ set_transferring_td_array(reschedule_td->cur_stransfer.alloc_chnum, 0);
+ oci_channel_dealloc(reschedule_td->cur_stransfer.alloc_chnum);
+
+ reschedule_td->cur_stransfer.alloc_chnum = CH_NONE;
+ reschedule_td->parent_ed_p->is_need_to_insert_scheduler = true;
+ reschedule_td->parent_ed_p->ed_status.in_transferring_td = 0;
+
+ if(reschedule_td->parent_ed_p->ed_desc.endpoint_type == BULK_TRANSFER||
+ reschedule_td->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER )
+ {
+ /* Increase the available Channel */
+ dec_nonperio_chnum();
+
+ }
+
+ insert_ed_to_ready_q(reschedule_td->parent_ed_p, false);
+ reschedule_td->parent_ed_p->ed_status.is_in_transfer_ready_q =true;
+
+ }
+ else
+ {
+ /* this case is not support.... */
+ }
+ }
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name int deallocate(td_t *deallocate_td)
+ *
+ * @brief this function frees resources to be allocated deallocate_td by S3CScheduler.
+ * this function just free the resource by S3CScheduler. that is, Channel Resource.
+ * if there are another td_t at ed_t, deallocate() insert the ed_t to TransferReadyQ.
+ *
+ * @param [IN] deallocate_td = indicates the pointer ot the td_t to be deallocated.
+ *
+ * @return USB_ERR_SUCCESS - if success to dealloate the resources for the deallocate_td.
+ * USB_ERR_FAIL - if fail to dealloate the resources for the deallocate_td.
+ */
+ /******************************************************************************/
+int deallocate(td_t *deallocate_td)
+{
+ u32 td_addr;
+
+ if(get_transferring_td_array(deallocate_td->cur_stransfer.alloc_chnum , &td_addr)==USB_ERR_SUCCESS)
+ {
+ if((u32)deallocate_td == td_addr)
+ {
+ set_transferring_td_array(deallocate_td->cur_stransfer.alloc_chnum, 0);
+ oci_channel_dealloc(deallocate_td->cur_stransfer.alloc_chnum);
+
+ deallocate_td->cur_stransfer.alloc_chnum = CH_NONE;
+
+ if(deallocate_td->parent_ed_p->ed_desc.endpoint_type == BULK_TRANSFER||
+ deallocate_td->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER )
+ {
+ /* Increase the available Channel */
+ dec_nonperio_chnum();
+ }
+
+ deallocate_td->parent_ed_p->is_need_to_insert_scheduler = true;
+
+ if(deallocate_td->parent_ed_p->num_td)
+ {
+ /* insert ed_t to TransferReadyQ. */
+ insert_ed_to_ready_q(deallocate_td->parent_ed_p , false);
+ deallocate_td->parent_ed_p->ed_status.is_in_transfer_ready_q = true;
+ deallocate_td->parent_ed_p->is_need_to_insert_scheduler = false;
+ }
+ return USB_ERR_SUCCESS;
+ }
+ else
+ {
+ return USB_ERR_FAIL;
+ }
+ }
+ else
+ {
+ return USB_ERR_FAIL;
+ }
+
+}
+
+/* TBD.... */
+void do_schedule(struct sec_otghost *otghost)
+{
+ if(get_avail_chnum()) {
+ do_periodic_schedule(otghost);
+ do_nonperiodic_schedule(otghost);
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int get_td_info(u8 chnum,
+ * unsigned int *td_addr_p)
+ *
+ * @brief this function returns the pointer of td_t at TransferringTDArray[chnum]
+ *
+ * @param [IN] chnum = indicates the index of TransferringTDArray
+ * to include the address of td_t which we gets
+ * [OUT] td_addr_p= indicate pointer to store the address of td_t.
+ *
+ * @return USB_ERR_SUCCESS -if success to get the address of td_t.
+ * USB_ERR_FAIL -if fail to get the address of td_t.
+ */
+ /******************************************************************************/
+int get_td_info( u8 chnum,
+ unsigned int *td_addr_p)
+{
+ u32 td_addr;
+
+ if(get_transferring_td_array(chnum, &td_addr)==USB_ERR_SUCCESS)
+ {
+ *td_addr_p = td_addr;
+ return USB_ERR_SUCCESS;
+ }
+
+ return USB_ERR_FAIL;
+}
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-scheduler-readyq.c b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-readyq.c
new file mode 100644
index 0000000..7b41f0c
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-readyq.c
@@ -0,0 +1,264 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : TransferReadyQ.c
+ * [Description] : The source file implements the internal functions of TransferReadyQ.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/04
+ * [Revision History]
+ * (1) 2008/06/04 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of TransferReadyQ.
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-scheduler-scheduler.h"
+
+static trans_ready_q_t periodic_trans_ready_q;
+static trans_ready_q_t nonperiodic_trans_ready_q;
+
+/******************************************************************************/
+/*!
+ * @name void init_transfer_ready_q(void)
+ *
+ * @brief this function initiates PeriodicTransferReadyQ and NonPeriodicTransferReadyQ.
+ *
+ *
+ * @param void
+ *
+ * @return void.
+ */
+/******************************************************************************/
+void init_transfer_ready_q(void)
+{
+ otg_dbg(OTG_DBG_SCHEDULE,"start init_transfer_ready_q\n");
+
+ otg_list_init(&periodic_trans_ready_q.trans_ready_q_list_head);
+ periodic_trans_ready_q.is_periodic_transfer = true;
+ periodic_trans_ready_q.trans_ready_entry_num = 0;
+ periodic_trans_ready_q.total_alloc_chnum = 0;
+ periodic_trans_ready_q.total_perio_bus_bandwidth = 0;
+
+ otg_list_init(&nonperiodic_trans_ready_q.trans_ready_q_list_head);
+ nonperiodic_trans_ready_q.is_periodic_transfer = false;
+ nonperiodic_trans_ready_q.trans_ready_entry_num = 0;
+ nonperiodic_trans_ready_q.total_alloc_chnum = 0;
+ nonperiodic_trans_ready_q.total_perio_bus_bandwidth = 0;
+
+
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int insert_ed_to_ready_q(ed_t *insert_ed,
+ * bool f_isfirst)
+ *
+ * @brief this function inserts ed_t * to TransferReadyQ.
+ *
+ *
+ * @param [IN] insert_ed = indicates the ed_t to be inserted to TransferReadyQ.
+ * [IN] f_isfirst = indicates whether the insert_ed is inserted as first entry of TransferReadyQ.
+ *
+ * @return USB_ERR_SUCCESS -if successes to insert the insert_ed to TransferReadyQ.
+ * USB_ERR_FAILl -if fails to insert the insert_ed to TransferReadyQ.
+ */
+/******************************************************************************/
+int insert_ed_to_ready_q(ed_t *insert_ed,
+ bool f_isfirst)
+{
+
+ if(insert_ed->ed_desc.endpoint_type == BULK_TRANSFER||
+ insert_ed->ed_desc.endpoint_type == CONTROL_TRANSFER)
+ {
+ if(f_isfirst)
+ {
+ otg_list_push_next(&insert_ed->trans_ready_q_list_entry,&nonperiodic_trans_ready_q.trans_ready_q_list_head);
+ }
+ else
+ {
+ otg_list_push_prev(&insert_ed->trans_ready_q_list_entry,&nonperiodic_trans_ready_q.trans_ready_q_list_head);
+ }
+ nonperiodic_trans_ready_q.trans_ready_entry_num++;
+ }
+ else
+ {
+ if(f_isfirst)
+ {
+ otg_list_push_next(&insert_ed->trans_ready_q_list_entry,&periodic_trans_ready_q.trans_ready_q_list_head);
+ }
+ else
+ {
+ otg_list_push_prev(&insert_ed->trans_ready_q_list_entry,&periodic_trans_ready_q.trans_ready_q_list_head);
+ }
+ periodic_trans_ready_q.trans_ready_entry_num++;
+ }
+
+ return USB_ERR_SUCCESS;
+
+}
+
+
+u32 get_periodic_ready_q_entity_num(void)
+{
+ return periodic_trans_ready_q.trans_ready_entry_num;
+}
+/******************************************************************************/
+/*!
+ * @name int remove_ed_from_ready_q(ed_t *remove_ed)
+ *
+ * @brief this function removes ed_t * from TransferReadyQ.
+ *
+ *
+ * @param [IN] remove_ed = indicate the ed_t to be removed from TransferReadyQ.
+ *
+ * @return USB_ERR_SUCCESS -if successes to remove the remove_ed from TransferReadyQ.
+ * USB_ERR_FAILl -if fails to remove the remove_ed from TransferReadyQ.
+ */
+/******************************************************************************/
+int remove_ed_from_ready_q(ed_t *remove_ed)
+{
+// SPINLOCK_t SLForRemoveED_t = SPIN_LOCK_INIT;
+// u32 uiSLFlag=0;
+
+ otg_list_pop(&remove_ed->trans_ready_q_list_entry);
+
+ if(remove_ed->ed_desc.endpoint_type == BULK_TRANSFER||
+ remove_ed->ed_desc.endpoint_type == CONTROL_TRANSFER)
+ {
+// spin_lock_irq_save_otg(&SLForRemoveED_t, uiSLFlag);
+// otg_list_pop(&remove_ed->trans_ready_q_list_entry);
+ nonperiodic_trans_ready_q.trans_ready_entry_num--;
+// spin_unlock_irq_save_otg(&SLForRemoveED_t, uiSLFlag);
+ }
+ else
+ {
+// spin_lock_irq_save_otg(&SLForRemoveED_t, uiSLFlag);
+// otg_list_pop(&remove_ed->trans_ready_q_list_entry);
+ periodic_trans_ready_q.trans_ready_entry_num--;
+// spin_unlock_irq_save_otg(&SLForRemoveED_t, uiSLFlag);
+ }
+
+ return USB_ERR_SUCCESS;
+
+}
+
+//by ss1 unused func
+/*
+bool check_ed_on_ready_q(ed_t *check_ed_p)
+{
+
+ if(check_ed_p->ed_status.is_in_transfer_ready_q)
+ return true;
+ else
+ return false;
+}*/
+
+/******************************************************************************/
+/*!
+ * @name int get_ed_from_ready_q(bool f_isperiodic,
+ * td_t **get_ed)
+ *
+ * @brief this function returns the first entity of TransferReadyQ.
+ * if there are some ed_t on TransferReadyQ, this function pops first ed_t from TransferReadyQ.
+ * So, the TransferReadyQ don's has the poped ed_t.
+ *
+ *
+ * @param [IN] f_isperiodic = indicate whether Periodic or not
+ * [OUT] get_ed = indicate the double pointer to store the address of first entity
+ * on TransferReadyQ.
+ *
+ * @return USB_ERR_SUCCESS -if successes to get frist ed_t from TransferReadyQ.
+ * USB_ERR_NO_ENTITY -if fails to get frist ed_t from TransferReadyQ
+ * because there is no entity on TransferReadyQ.
+ */
+/******************************************************************************/
+
+int get_ed_from_ready_q(bool f_isperiodic,
+ ed_t **get_ed)
+{
+ if(f_isperiodic)
+ {
+ otg_list_head *transreadyq_list_entity=NULL;
+
+ if(periodic_trans_ready_q.trans_ready_entry_num==0)
+ {
+ return USB_ERR_NO_ENTITY;
+ }
+
+ transreadyq_list_entity = periodic_trans_ready_q.trans_ready_q_list_head.next;
+
+ //if(transreadyq_list_entity!= &periodic_trans_ready_q.trans_ready_q_list_head)
+ if(!otg_list_empty(&periodic_trans_ready_q.trans_ready_q_list_head))
+ {
+ *get_ed = otg_list_get_node(transreadyq_list_entity,ed_t,trans_ready_q_list_entry);
+ if (transreadyq_list_entity->prev == LIST_POISON2 ||
+ transreadyq_list_entity->next == LIST_POISON1) {
+ printk(KERN_ERR "s3c-otg-scheduler get_ed_from_ready_q error\n");
+ periodic_trans_ready_q.trans_ready_entry_num =0;
+ }
+ else {
+ otg_list_pop(transreadyq_list_entity);
+ periodic_trans_ready_q.trans_ready_entry_num--;
+ }
+
+ return USB_ERR_SUCCESS;
+ }
+ else
+ {
+ return USB_ERR_NO_ENTITY;
+ }
+ }
+ else
+ {
+ otg_list_head *transreadyq_list_entity=NULL;
+
+ if(nonperiodic_trans_ready_q.trans_ready_entry_num==0)
+ {
+ return USB_ERR_NO_ENTITY;
+ }
+
+ transreadyq_list_entity = nonperiodic_trans_ready_q.trans_ready_q_list_head.next;
+
+ //if(transreadyq_list_entity!= &nonperiodic_trans_ready_q.trans_ready_q_list_head)
+ if(!otg_list_empty(&nonperiodic_trans_ready_q.trans_ready_q_list_head))
+ {
+ *get_ed = otg_list_get_node(transreadyq_list_entity,ed_t, trans_ready_q_list_entry);
+ if (transreadyq_list_entity->prev == LIST_POISON2 ||
+ transreadyq_list_entity->next == LIST_POISON1) {
+ printk(KERN_ERR "s3c-otg-scheduler get_ed_from_ready_q error\n");
+ nonperiodic_trans_ready_q.trans_ready_entry_num =0;
+ }
+ else {
+ otg_list_pop(transreadyq_list_entity);
+ nonperiodic_trans_ready_q.trans_ready_entry_num--;
+ }
+
+ return USB_ERR_SUCCESS;
+ }
+ else
+ {
+ return USB_ERR_NO_ENTITY;
+ }
+ }
+}
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.c b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.c
new file mode 100644
index 0000000..81777a9
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.c
@@ -0,0 +1,416 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : Scheduler.c
+ * [Description] : The source file implements the internal functions of Scheduler.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/04
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of Scheduler
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-scheduler-scheduler.h"
+
+//Define constant variables
+
+//the max periodic bus time is 80%*125us on High Speed Mode
+static const u32 perio_highbustime_threshold = 100;
+
+//the max periodic bus time is 90%*1000us(1ms) on Full/Low Speed Mode .
+static const u32 perio_fullbustime_threshold = 900;
+
+static const u8 perio_chnum_threshold = 14;
+//static const u8 total_chnum_threshold = 16;
+static u8 total_chnum_threshold = 16;
+
+ //Define global variables
+// kevinh: add volatile
+static volatile u32 perio_used_bustime = 0;
+static volatile u8 perio_used_chnum = 0;
+static volatile u8 nonperio_used_chnum = 0;
+static volatile u8 total_used_chnum = 0;
+static volatile u32 transferring_td_array[16]={0};
+
+
+int inc_perio_bus_time(u32 bus_time, u8 dev_speed)
+{
+ switch(dev_speed) {
+ case HIGH_SPEED_OTG:
+ if((bus_time+perio_used_bustime)<=perio_highbustime_threshold) {
+ perio_used_bustime=+bus_time;
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+
+ case LOW_SPEED_OTG:
+ case FULL_SPEED_OTG:
+ if((bus_time+perio_used_bustime)<=perio_fullbustime_threshold) {
+ perio_used_bustime=+bus_time;
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+ case SUPER_SPEED_OTG:
+ break;
+ default:
+ break;
+ }
+ return USB_ERR_FAIL;
+}
+
+int dec_perio_bus_time(u32 bus_time)
+{
+ if(perio_used_bustime >= bus_time ) {
+ perio_used_bustime =- bus_time;
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ return USB_ERR_FAIL;
+ }
+}
+
+int inc_perio_chnum(void)
+{
+ if(perio_used_chnum<perio_chnum_threshold)
+ {
+ if(total_used_chnum<total_chnum_threshold)
+ {
+ perio_used_chnum++;
+ total_used_chnum++;
+ return USB_ERR_SUCCESS;
+ }
+ }
+ return USB_ERR_FAIL;
+}
+
+u8 get_avail_chnum(void)
+{
+ return total_chnum_threshold - total_used_chnum;
+}
+
+int dec_perio_chnum(void)
+{
+ if(perio_used_chnum>0)
+ {
+ if(total_used_chnum>0)
+ {
+ perio_used_chnum--;
+ total_used_chnum--;
+ return USB_ERR_SUCCESS;
+ }
+ }
+ return USB_ERR_FAIL;
+}
+
+int inc_non_perio_chnum(void)
+{
+ if(nonperio_used_chnum<total_chnum_threshold)
+ {
+ if(total_used_chnum<total_chnum_threshold)
+ {
+ nonperio_used_chnum++;
+ total_used_chnum++;
+ return USB_ERR_SUCCESS;
+ }
+ }
+ return USB_ERR_FAIL;
+}
+
+int dec_nonperio_chnum(void)
+{
+ if(nonperio_used_chnum>0)
+ {
+ if(total_used_chnum>0)
+ {
+ nonperio_used_chnum--;
+ total_used_chnum--;
+ return USB_ERR_SUCCESS;
+ }
+ }
+ return USB_ERR_FAIL;
+}
+
+int get_transferring_td_array(u8 chnum, unsigned int *td_addr)
+{
+ if(transferring_td_array[chnum]!=0)
+ {
+ *td_addr = transferring_td_array[chnum];
+ return USB_ERR_SUCCESS;
+ }
+
+ return USB_ERR_FAIL;
+}
+
+int set_transferring_td_array(u8 chnum, u32 td_addr)
+{
+ if(td_addr ==0)
+ {
+ transferring_td_array[chnum] = td_addr;
+ return USB_ERR_SUCCESS;
+ }
+
+ if(transferring_td_array[chnum] == 0)
+ {
+ transferring_td_array[chnum] = td_addr;
+ return USB_ERR_SUCCESS;
+ }
+ else
+ {
+ return USB_ERR_FAIL;
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int insert_ed_to_scheduler(struct sec_otghost *otghost, ed_t *insert_ed)
+ *
+ * @brief this function transfers the insert_ed to S3C6400Scheduler, and
+ * after that, the insert_ed is inserted to TransferReadyQ and scheduled by Scheduler.
+ *
+ *
+ * @param [IN] insert_ed = indicates pointer of ed_t to be inserted to TransferReadyQ.
+ *
+ * @return USB_ERR_ALREADY_EXIST - if the insert_ed is already existed.
+ * USB_ERR_SUCCESS - if success to insert insert_ed to S3CScheduler.
+ */
+/******************************************************************************/
+int insert_ed_to_scheduler(struct sec_otghost *otghost, ed_t *insert_ed)
+{
+ if(!insert_ed->is_need_to_insert_scheduler)
+ return USB_ERR_ALREADY_EXIST;
+
+ insert_ed_to_ready_q(insert_ed, false);
+ insert_ed->is_need_to_insert_scheduler = false;
+ insert_ed->ed_status.is_in_transfer_ready_q = true;
+
+ do_periodic_schedule(otghost);
+ do_nonperiodic_schedule(otghost);
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name int do_periodic_schedule(struct sec_otghost *otghost)
+ *
+ * @brief this function schedules PeriodicTransferReadyQ.
+ * this function checks whether PeriodicTransferReadyQ has some ed_t.
+ * if there are some ed_t on PeriodicTransferReadyQ
+ * , this function request to start USB Trasnfer to S3C6400OCI.
+ *
+ *
+ * @param void
+ *
+ * @return void
+ */
+/******************************************************************************/
+void do_periodic_schedule(struct sec_otghost *otghost)
+{
+ ed_t *scheduling_ed= NULL;
+ int err_sched = USB_ERR_SUCCESS;
+ u32 sched_cnt = 0;
+
+ otg_dbg(OTG_DBG_SCHEDULE,"*******Start to DoPeriodicSchedul*********\n");
+
+ sched_cnt = get_periodic_ready_q_entity_num();
+
+ while(sched_cnt) {
+ //in periodic transfser, the channel resource was already reserved.
+ //So, we don't need this routine...
+
+start_sched_perio_transfer:
+ if(!sched_cnt)
+ goto end_sched_perio_transfer;
+
+ err_sched = get_ed_from_ready_q(true, &scheduling_ed);
+
+ if(err_sched==USB_ERR_SUCCESS) {
+ otg_list_head *td_list_entry;
+ td_t *td;
+ u32 cur_frame_num = 0;
+
+ otg_dbg(OTG_DBG_SCHEDULE,"the ed_t to be scheduled :%d",(int)scheduling_ed);
+ sched_cnt--;
+ td_list_entry = scheduling_ed->td_list_entry.next;
+
+ if(td_list_entry == &scheduling_ed->td_list_entry) {
+ //scheduling_ed has no td_t. so we schedules another ed_t on PeriodicTransferReadyQ.
+ goto start_sched_perio_transfer;
+ }
+
+ if(scheduling_ed->ed_status.is_in_transferring) {
+ //scheduling_ed is already Scheduled. so we schedules another ed_t on PeriodicTransferReadyQ.
+ goto start_sched_perio_transfer;
+ }
+
+ cur_frame_num = oci_get_frame_num();
+
+ if(((cur_frame_num-scheduling_ed->ed_desc.sched_frame)&HFNUM_MAX_FRNUM)>(HFNUM_MAX_FRNUM>>1)) {
+ insert_ed_to_ready_q(scheduling_ed, false);
+ goto start_sched_perio_transfer;
+ }
+
+ td = otg_list_get_node(td_list_entry, td_t, td_list_entry);
+
+ if((!td->is_transferring) && (!td->is_transfer_done)) {
+ u8 alloc_ch;
+ otg_dbg(OTG_DBG_SCHEDULE,"the td_t to be scheduled :%d",(int)td);
+ alloc_ch = oci_start_transfer(otghost, &td->cur_stransfer);
+ if(alloc_ch<total_chnum_threshold) {
+ td->cur_stransfer.alloc_chnum = alloc_ch;
+ set_transferring_td_array(alloc_ch, (u32)td);
+
+ scheduling_ed->ed_status.is_in_transferring = true;
+ scheduling_ed->ed_status.is_in_transfer_ready_q = false;
+ scheduling_ed->ed_status.in_transferring_td = (u32)td;
+
+ td->is_transferring = true;
+ }
+ else {
+ //we should insert the ed_t to TransferReadyQ, because the USB Transfer of the ed_t is failed.
+ scheduling_ed->ed_status.is_in_transferring = false;
+ scheduling_ed->ed_status.is_in_transfer_ready_q = true;
+ scheduling_ed->ed_status.in_transferring_td = 0;
+
+ insert_ed_to_ready_q(scheduling_ed,true);
+
+ scheduling_ed->is_need_to_insert_scheduler = false;
+ goto end_sched_perio_transfer;
+ }
+
+ }
+ else { // the selected td_t was already transferring or completed to transfer.
+ //we should decide how to control this case.
+ goto end_sched_perio_transfer;
+ }
+ }
+ else {
+ // there is no ED on PeriodicTransferQ. So we finish scheduling.
+ goto end_sched_perio_transfer;
+ }
+ }
+
+end_sched_perio_transfer:
+
+ return;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int do_nonperiodic_schedule(struct sec_otghost *otghost)
+ *
+ * @brief this function start to schedule thie NonPeriodicTransferReadyQ.
+ * this function checks whether NonPeriodicTransferReadyQ has some ed_t.
+ * if there are some ed_t on NonPeriodicTransferReadyQ
+ * , this function request to start USB Trasnfer to S3C6400OCI.
+ *
+ *
+ * @param void
+ *
+ * @return void
+ */
+/******************************************************************************/
+void do_nonperiodic_schedule(struct sec_otghost *otghost)
+{
+ if(total_used_chnum<total_chnum_threshold) {
+ ed_t *scheduling_ed;
+ int err_sched;
+
+ while(1) {
+
+start_sched_nonperio_transfer:
+
+ //check there is available channel resource for Non-Periodic Transfer.
+ if(total_used_chnum==total_chnum_threshold) {
+ goto end_sched_nonperio_transfer;
+ }
+
+ err_sched = get_ed_from_ready_q(false, &scheduling_ed);
+
+ if(err_sched ==USB_ERR_SUCCESS ) {
+ otg_list_head *td_list_entry;
+ td_t *td;
+
+ td_list_entry = scheduling_ed->td_list_entry.next;
+
+ //if(td_list_entry == &scheduling_ed->td_list_entry)
+ if(otg_list_empty(&scheduling_ed->td_list_entry)) {
+ //scheduling_ed has no td_t. so we schedules another ed_t on PeriodicTransferReadyQ.
+ goto start_sched_nonperio_transfer;
+ }
+
+ if(scheduling_ed->ed_status.is_in_transferring) {
+ //scheduling_ed is already Scheduled. so we schedules another ed_t on PeriodicTransferReadyQ.
+ goto start_sched_nonperio_transfer;
+ }
+
+ td = otg_list_get_node(td_list_entry, td_t, td_list_entry);
+
+ if((!td->is_transferring) && (!td->is_transfer_done)) {
+ u8 alloc_ch;
+
+ alloc_ch = oci_start_transfer(otghost, &td->cur_stransfer);
+
+ if(alloc_ch<total_chnum_threshold) {
+ td->cur_stransfer.alloc_chnum = alloc_ch;
+ set_transferring_td_array(alloc_ch, (u32)td);
+
+ inc_non_perio_chnum();
+
+ scheduling_ed->ed_status.is_in_transferring = true;
+ scheduling_ed->ed_status.is_in_transfer_ready_q = false;
+ scheduling_ed->ed_status.in_transferring_td =(u32)td;
+ td->is_transferring = true;
+ }
+ else {
+ //we should insert the ed_t to TransferReadyQ, because the USB Transfer of the ed_t is failed.
+ scheduling_ed->ed_status.is_in_transferring = false;
+ scheduling_ed->ed_status.in_transferring_td =0;
+ insert_ed_to_ready_q(scheduling_ed,true);
+ scheduling_ed->ed_status.is_in_transfer_ready_q = true;
+
+ goto end_sched_nonperio_transfer;
+ }
+ }
+ else {
+ goto end_sched_nonperio_transfer;
+ }
+ }
+ else { //there is no ed_t on NonPeriodicTransferReadyQ.
+ //So, we finish do_nonperiodic_schedule().
+ goto end_sched_nonperio_transfer;
+ }
+ }
+ }
+
+end_sched_nonperio_transfer:
+
+ return;
+}
+
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.h b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.h
new file mode 100644
index 0000000..eb43f41
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-scheduler-scheduler.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : Scheduler.h
+ * [Description] : The Header file defines the external and internal functions of Scheduler.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/03
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of Scheduler
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _SCHEDULER_H
+#define _SCHEDULER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-hcdi-memory.h"
+#include "s3c-otg-hcdi-kal.h"
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-oci.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//Defines external functions of IScheduler.c
+extern void init_scheduler(void);
+extern int reserve_used_resource_for_periodic(u32 usb_time,u8 dev_speed, u8 trans_type);
+extern int free_usb_resource_for_periodic(u32 free_usb_time, u8 free_chnum, u8 trans_type);
+extern int remove_ed_from_scheduler(ed_t *remove_ed);
+extern int cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td);
+extern int retransmit(struct sec_otghost *otghost, td_t *retransmit_td);
+extern int reschedule(td_t *resched_td);
+extern int deallocate(td_t *dealloc_td);
+extern void do_schedule(struct sec_otghost *otghost);
+extern int get_td_info(u8 chnum,unsigned int *td_addr);
+
+// Defines functiions of TranferReadyQ.
+void init_transfer_ready_q(void);
+int insert_ed_to_ready_q(ed_t *insert_ed, bool f_isfirst);
+int remove_ed_from_ready_q(ed_t *remove_ed);
+int get_ed_from_ready_q(bool f_isperiodic, ed_t **get_ed);
+
+//Define functions of Scheduler
+void do_periodic_schedule(struct sec_otghost *otghost);
+void do_nonperiodic_schedule(struct sec_otghost *otghost);
+int set_transferring_td_array(u8 chnum, u32 td_addr);
+int get_transferring_td_array(u8 chnum, unsigned int *td_addr);
+
+
+//Define fuctions to manage some static global variable.
+int inc_perio_bus_time(u32 uiBusTime, u8 dev_speed);
+int dec_perio_bus_time(u32 uiBusTime);
+
+u8 get_avail_chnum(void);
+int inc_perio_chnum(void);
+int dec_perio_chnum(void);
+int inc_non_perio_chnum(void);
+int dec_nonperio_chnum(void);
+u32 get_periodic_ready_q_entity_num(void);
+
+int insert_ed_to_scheduler(struct sec_otghost *otghost, ed_t *insert_ed);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transfer-common.c b/drivers/usb/host/s3c-otg/s3c-otg-transfer-common.c
new file mode 100644
index 0000000..3f5c9a9
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transfer-common.c
@@ -0,0 +1,805 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : Commons3c-otg-transfer-transfer.h
+ * [Description] : This source file implements the functions to be defined at CommonTransfer Module.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/03
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements some functions of CommonTransfer.
+ * (2) 2008/07/15 by SeungSoo Yang ( ss1.yang@samsung.com )n
+ * - Optimizing for performance \n
+ * (3) 2008/08/18 by SeungSoo Yang ( ss1.yang@samsung.com )
+ * - Modifying for successful rmmod & disconnecting \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-transfer-transfer.h"
+
+// the header pointer to indicate the ED_list to manage the ed_t to be created and initiated.
+static otg_list_head ed_list_head;
+static u32 ref_periodic_transfer;
+
+/******************************************************************************/
+/*!
+ * @name void init_transfer(void)
+ *
+ * @brief this function initiates the S3CTranfer module. that is, this functions initiates
+ * the ED_list_head OTG List which manages the all ed_t to be existed.
+ *
+ * @param void
+ *
+ * @return void
+ */
+/******************************************************************************/
+
+void init_transfer(void)
+{
+ otg_dbg(OTG_DBG_TRANSFER,"start to init_transfer\n");
+ otg_list_init(&ed_list_head);
+ ref_periodic_transfer = 0;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name void DeInitTransfer(void)
+ *
+ * @brief this function Deinitiates the S3CTranfer module. this functions check which there are
+ * some ed_t on ED_list_head. if some ed_t exists, deinit_transfer() deletes the ed_t.
+ *
+ *
+ * @param void
+ *
+ * @return void
+ */
+/******************************************************************************/
+void deinit_transfer(struct sec_otghost *otghost)
+{
+ otg_list_head *ed_list_member;
+ ed_t *delete_ed_p;
+
+ while(otg_list_empty(&ed_list_head) != true) {
+ ed_list_member = ed_list_head.next;
+
+ /* otg_list_pop(ed_list_member); */
+
+ delete_ed_p= otg_list_get_node(ed_list_member,ed_t,ed_list_entry);
+
+ delete_ed(otghost, delete_ed_p);
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int delete_ed(ed_t *delete_ed)
+ *
+ * @brief this function delete the delete_ed.
+ * if there is some available TD_ts on delete_ed, then this function also deletes these td_t
+ *
+ *
+ * @param [IN] delete_ed = indicates the address of ed_t to be deleted.
+ *
+ * @return USB_ERR_SUCCESS -if successes to delete the ed_t.
+ * USB_ERR_FAILl -if fails to delete the ed_t.
+ */
+/******************************************************************************/
+int delete_ed(struct sec_otghost *otghost, ed_t *delete_ed)
+{
+ otg_kal_make_ep_null(delete_ed);
+
+ if(delete_ed->num_td) {
+ cancel_all_td(otghost, delete_ed);
+ /**
+ need to giveback of td's urb with considering life-cycle of
+ TD, ED, urb->hcpriv, td->private, ep->hcpriv, td->parentED
+ (commented by ss1.yang)
+ */
+ }
+
+ otg_list_pop(&delete_ed->ed_list_entry);
+
+ if(delete_ed->ed_desc.endpoint_type == INT_TRANSFER ||
+ delete_ed->ed_desc.endpoint_type == ISOCH_TRANSFER) {
+ ref_periodic_transfer--;
+ }
+
+ if(ref_periodic_transfer==0) {
+ disable_sof();
+ }
+ otg_mem_free(delete_ed);
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name int delete_td(struct sec_otghost *otghost, td_t *delete_td)
+ *
+ * @brief this function frees memory resource for the delete_td.
+ * and if delete_td is transferring USB Transfer, then this function request to cancel
+ * the USB Transfer to S3CScheduler.
+ *
+ *
+ * @param [OUT] new_td_p = returns the address of the new td_t .
+ *
+ * @return USB_ERR_SUCCESS -if successes to create the new td_t.
+ * USB_ERR_FAILl -if fails to create to new td_t.
+ */
+/******************************************************************************/
+int delete_td(struct sec_otghost *otghost, td_t *delete_td)
+{
+ if(delete_td->is_transferring) {
+ //at this case, we should cancel the USB Transfer.
+ cancel_to_transfer_td(otghost, delete_td);
+ }
+
+ otg_mem_free(delete_td);
+ return USB_ERR_SUCCESS;
+}
+
+int create_isoch_packet_desc(isoch_packet_desc_t **new_isoch_packet_desc,
+ u32 isoch_packet_num)
+{
+ return otg_mem_alloc((void **)new_isoch_packet_desc,
+ (u16)sizeof(isoch_packet_desc_t)*isoch_packet_num,USB_MEM_SYNC);
+}
+
+int delete_isoch_packet_desc(isoch_packet_desc_t *del_isoch_packet_desc,
+ u32 isoch_packet_num)
+{
+ return otg_mem_free(del_isoch_packet_desc);
+}
+
+/******************************************************************************/
+/*!
+ * @name void init_isoch_packet_desc( isoch_packet_desc_t *init_isoch_packet_desc,
+ * u32 isoch_packet_start_addr,
+ * u32 isoch_packet_size,
+ * u32 index)
+ *
+ * @brief this function initiates the isoch_packet_desc_t[index].
+ *
+ *
+ * @param [OUT] init_isoch_packet_desc = indicates the pointer of IsochPackDesc_t to be initiated.
+ * [IN] isoch_packet_start_addr = indicates the start address of the buffer to be used
+ * at USB Isochronous Transfer.
+ * [IN] isoch_packet_size = indicates the size of Isochronous packet.
+ * [IN] index = indicates the index to be mapped with this init_isoch_packet_desc.
+ *
+ * @return void
+ */
+/******************************************************************************/
+void init_isoch_packet_desc(isoch_packet_desc_t *init_isoch_packet_desc,
+ u32 isoch_packet_start_addr,
+ u32 isoch_packet_size,
+ u32 index)
+{
+ init_isoch_packet_desc[index].buf_size = isoch_packet_size;
+ init_isoch_packet_desc[index].isoch_packiet_start_addr = isoch_packet_start_addr;
+ init_isoch_packet_desc[index].isoch_status = 0;
+ init_isoch_packet_desc[index].transferred_szie = 0;
+}
+
+/******************************************************************************/
+/*!
+ * @name int create_ed(ed_t **new_ed)
+ *
+ * @brief this function creates a new ed_t and returns the ed_t to Caller
+ *
+ *
+ * @param [OUT] new_ed = returns the address of the new ed_t .
+ *
+ * @return USB_ERR_SUCCESS -if successes to create the new ed_t.
+ * USB_ERR_FAILl -if fails to create to new ed_t.
+ */
+/******************************************************************************/
+int create_ed(ed_t **new_ed)
+{
+ int err_code = USB_ERR_SUCCESS;
+
+ err_code = otg_mem_alloc((void **)new_ed,(u16)sizeof(ed_t), USB_MEM_ASYNC);
+ otg_mem_set(*new_ed, 0, sizeof(ed_t));
+ return err_code;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int init_ed( ed_t *init_ed,
+ * u8 dev_addr,
+ * u8 ep_num,
+ * bool f_is_ep_in,
+ * u8 dev_speed,
+ * u8 ep_type,
+ * u32 max_packet_size,
+ * u8 multi_count,
+ * u8 interval,
+ * u32 sched_frame,
+ * u8 hub_addr,
+ * u8 hub_port,
+ * bool f_is_do_split)
+ *
+ * @brief this function initiates the init_ed by using the another parameters.
+ *
+ *
+ * @param [OUT] init_ed = returns the ed_t to be initiated.
+ * [IN] dev_addr = inidcates the address of USB Device.
+ * [IN] ep_num = inidcates the number of the specific endpoint on USB Device.
+ * [IN] f_is_ep_in = inidcates whether the endpoint is IN or not
+ * [IN] dev_speed = inidcates the speed of USB Device.
+ * [IN] max_packet_size = inidcates the maximum packet size of a specific endpoint on USB Device.
+ * [IN] multi_count = if the endpoint supports periodic transfer
+ * , this indicates the multiple packet to be transferred on a uframe
+ * [IN] interval= if the endpoint support periodic transfer, this indicates the polling rate.
+ * [IN] sched_frame= if the endpoint supports periodic transfer, this indicates the start frame number.
+ * [IN] hub_addr= indicate the address of hub which the USB device attachs to.
+ * [IN] hub_port= inidcates the port number of the hub which the USB device attachs to.
+ * [IN] f_is_do_split= inidcates whether this tranfer is split transaction or not.
+ *
+ * @return USB_ERR_SUCCESS -if successes to initiate the ed_t.
+ * USB_ERR_FAILl -if fails to initiate the ed_t.
+ * USB_ERR_NOSPACE -if fails to initiate the ed_t
+ * because there is no USB Resource for this init_ed.
+ */
+/******************************************************************************/
+int init_ed(ed_t *init_ed,
+ u8 dev_addr,
+ u8 ep_num,
+ bool f_is_ep_in,
+ u8 dev_speed,
+ u8 ep_type,
+ u16 max_packet_size,
+ u8 multi_count,
+ u8 interval,
+ u32 sched_frame,
+ u8 hub_addr,
+ u8 hub_port,
+ bool f_is_do_split,
+ void *ep)
+{
+ init_ed->is_halted = false;
+ init_ed->is_need_to_insert_scheduler= true;
+ init_ed->ed_id = (u32)init_ed;
+ init_ed->num_td = 0;
+ init_ed->ed_private = ep;
+
+ otg_list_init(&init_ed->td_list_entry);
+
+ //start to initiate struct ed_desc....
+ init_ed->ed_desc.is_do_split = f_is_do_split;
+ init_ed->ed_desc.is_ep_in = f_is_ep_in;
+ init_ed->ed_desc.dev_speed = dev_speed;
+ init_ed->ed_desc.hub_addr = hub_addr;
+ init_ed->ed_desc.hub_port = hub_port;
+ init_ed->ed_desc.mc = multi_count;
+ init_ed->ed_desc.device_addr = dev_addr;
+ init_ed->ed_desc.endpoint_num = ep_num;
+ init_ed->ed_desc.endpoint_type = ep_type;
+ init_ed->ed_desc.max_packet_size = max_packet_size;
+ init_ed->ed_desc.sched_frame = sched_frame;
+
+ if(init_ed->ed_desc.endpoint_type == INT_TRANSFER) {
+ if(init_ed->ed_desc.dev_speed == LOW_SPEED_OTG ||init_ed->ed_desc.dev_speed == FULL_SPEED_OTG) {
+ init_ed->ed_desc.interval =interval;
+ }
+ else if(init_ed->ed_desc.dev_speed == HIGH_SPEED_OTG) {
+ u8 count = 0;
+ u8 cal_interval = 1;
+
+ for(count = 0;count<(init_ed->ed_desc.interval-1);count++) {
+ cal_interval *=2;
+ }
+
+ init_ed->ed_desc.interval =cal_interval;
+ }
+ else {
+ otg_dbg(OTG_DBG_TRANSFER,"Super-Speed is not supported\n");
+ }
+ init_ed->ed_desc.sched_frame = (SCHEDULE_SLOT+oci_get_frame_num())&HFNUM_MAX_FRNUM;
+ ref_periodic_transfer++;
+ }
+ if(init_ed->ed_desc.endpoint_type==ISOCH_TRANSFER) {
+ u8 count = 0;
+ u8 cal_interval = 1;
+
+ for(count = 0;count<(init_ed->ed_desc.interval-1);count++)
+ {
+ cal_interval *=2;
+ }
+
+ init_ed->ed_desc.interval = cal_interval;
+ init_ed->ed_desc.sched_frame = (SCHEDULE_SLOT+oci_get_frame_num())&HFNUM_MAX_FRNUM;
+ ref_periodic_transfer++;
+ }
+
+ //start to initiate struct ed_status....
+
+ //initiates PID
+ switch(ep_type) {
+ case BULK_TRANSFER:
+ case INT_TRANSFER:
+ init_ed->ed_status.data_tgl = DATA0;
+ break;
+
+ case CONTROL_TRANSFER:
+ init_ed->ed_status.control_data_tgl.setup_tgl = SETUP;
+ init_ed->ed_status.control_data_tgl.data_tgl = DATA1;
+ init_ed->ed_status.control_data_tgl.status_tgl = DATA1;
+ break;
+
+ case ISOCH_TRANSFER:
+ if(f_is_ep_in) {
+ switch(multi_count) {
+ case MULTI_COUNT_ZERO :
+ init_ed->ed_status.data_tgl = DATA0;
+ break;
+ case MULTI_COUNT_ONE :
+ init_ed->ed_status.data_tgl = DATA1;
+ break;
+ case MULTI_COUNT_TWO :
+ init_ed->ed_status.data_tgl = DATA2;
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ switch(multi_count) {
+ case MULTI_COUNT_ZERO :
+ init_ed->ed_status.data_tgl = DATA0;
+ break;
+ case MULTI_COUNT_ONE :
+ init_ed->ed_status.data_tgl = MDATA;
+ break;
+ case MULTI_COUNT_TWO :
+ init_ed->ed_status.data_tgl = MDATA;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if(init_ed->ed_desc.endpoint_type == INT_TRANSFER ||
+ init_ed->ed_desc.endpoint_type == ISOCH_TRANSFER) {
+ u32 usb_time = 0, byte_count = 0;
+
+ //calculates the bytes to be transferred at one (uframe)frame.
+ byte_count = (init_ed->ed_desc.mc+1)*init_ed->ed_desc.max_packet_size;
+
+ usb_time = (u32)otg_usbcore_get_calc_bustime(init_ed->ed_desc.dev_speed,
+ init_ed->ed_desc.is_ep_in,
+ (init_ed->ed_desc.endpoint_type==ISOCH_TRANSFER?true:false),
+ byte_count);
+ usb_time /= 1000; //convert nanosec unit to usec unit
+
+ if(reserve_used_resource_for_periodic(usb_time, init_ed->ed_desc.dev_speed, init_ed->ed_desc.endpoint_type) != USB_ERR_SUCCESS) {
+ return USB_ERR_NOSPACE;
+ }
+
+ init_ed->ed_status.is_alloc_resource_for_ed =true;
+ init_ed->ed_desc.used_bus_time =usb_time;
+ init_ed->ed_desc.mc =multi_count+1;
+ }
+
+ init_ed->ed_status.is_in_transfer_ready_q =false;
+ init_ed->ed_status.is_in_transferring =false;
+ init_ed->ed_status.is_ping_enable =false;
+ init_ed->ed_status.in_transferring_td =0;
+
+ //push the ed_t to ED_list.
+ otg_list_push_prev(&init_ed->ed_list_entry,&ed_list_head);
+
+ if(ref_periodic_transfer) {
+ enable_sof();
+ }
+ return USB_ERR_SUCCESS;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int create_td(td_t **new_td)
+ *
+ * @brief this function creates a new td_t and returns the td_t to Caller
+ *
+ *
+ * @param [OUT] new_td = returns the address of the new td_t .
+ *
+ * @return USB_ERR_SUCCESS -if successes to create the new td_t.
+ * USB_ERR_FAILl -if fails to create to new td_t.
+ */
+/******************************************************************************/
+int create_td(td_t **new_td)
+{
+ int err_code = USB_ERR_SUCCESS;
+
+ err_code = otg_mem_alloc((void **)new_td,(u16)sizeof(td_t), USB_MEM_ASYNC);
+ otg_mem_set(*new_td, 0, sizeof(td_t));
+ return err_code;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int init_td( td_t *init_td,
+ * ed_t *parent_ed,
+ * void *call_back_fun,
+ * void *call_back_param,
+ * u32 transfer_flag,
+ * bool f_is_standard_dev_req,
+ * u32 phy_setup,
+ * u32 vir_setup,
+ * u32 vir_buf_addr,
+ * u32 phy_buf_addr,
+ * u32 buf_size,
+ * u32 isoch_start_frame,
+ * isoch_packet_desc_t *isoch_packet_desc,
+ * u32 isoch_packet_num,
+ * void *td_priv)
+ *
+ * @brief this function initiates the init_td by using another parameter.
+ *
+ *
+ * @param [IN] init_td - indicate the td_t to be initiated.
+ * [IN] parent_ed - indicate the ed_t to manage this init_td
+ * [IN] call_back_func - indicate the call-back function of application.
+ * [IN] call_back_param - indicate the parameter of the call-back function.
+ * [IN] transfer_flag - indicate the transfer flag.
+ * [IN] f_is_standard_dev_req - indicates the issue transfer request is USB Standard Request
+ * [IN] phy_setup - the physical address of buffer to store the USB Standard Request.
+ * [IN] vir_setup - the virtual address of buffer to store the USB Standard Request.
+ * [IN] vir_buf_addr - the virtual address of buffer to store the data to be transferred or received.
+ * [IN] phy_buf_addr - the physical address of buffer to store the data to be transferred or received.
+ * [IN] buf_size - indicates the buffer size.
+ * [IN] isoch_start_frame - if this usb transfer is isochronous transfer
+ * , this indicates the start frame to start the usb transfer.
+ * [IN] isoch_packet_desc - if the usb transfer is isochronous transfer
+ * , this indicates the structure to describe the isochronous transfer.
+ * [IN] isoch_packet_num - if the usb transfer is isochronous transfer
+ * , this indicates the number of packet to consist of the usb transfer.
+ * [IN] td_priv - indicate the private data to be delivered from usb core of linux.
+ * td_priv stores the urb of linux.
+ *
+ * @return USB_ERR_SUCCESS -if successes to initiate the new td_t.
+ * USB_ERR_FAILl -if fails to create to new td_t.
+ */
+/******************************************************************************/
+int init_td( td_t *init_td,
+ ed_t *parent_ed,
+ void *call_back_fun,
+ void *call_back_param,
+ u32 transfer_flag,
+ bool f_is_standard_dev_req,
+ u32 phy_setup,
+ u32 vir_setup,
+ u32 vir_buf_addr,
+ u32 phy_buf_addr,
+ u32 buf_size,
+ u32 isoch_start_frame,
+ isoch_packet_desc_t *isoch_packet_desc,
+ u32 isoch_packet_num,
+ void *td_priv)
+{
+ if(f_is_standard_dev_req) {
+ if((phy_buf_addr>0) && (buf_size>0)) {
+ init_td->standard_dev_req_info.is_data_stage = true;
+ }
+ else {
+ init_td->standard_dev_req_info.is_data_stage = false;
+ }
+ init_td->standard_dev_req_info.conrol_transfer_stage = SETUP_STAGE;
+ init_td->standard_dev_req_info.phy_standard_dev_req_addr = phy_setup;
+ init_td->standard_dev_req_info.vir_standard_dev_req_addr = vir_setup;
+ }
+
+ init_td->call_back_func_p = call_back_fun;
+ init_td->call_back_func_param_p = call_back_param;
+ init_td->error_code = USB_ERR_SUCCESS;
+ init_td->is_standard_dev_req = f_is_standard_dev_req;
+ init_td->is_transfer_done = false;
+ init_td->is_transferring = false;
+ init_td->td_private = td_priv;
+ init_td->err_cnt = 0;
+ init_td->parent_ed_p = parent_ed;
+ init_td->phy_buf_addr = phy_buf_addr;
+ init_td->vir_buf_addr = vir_buf_addr;
+ init_td->buf_size = buf_size;
+ init_td->isoch_packet_desc_p = isoch_packet_desc;
+ init_td->isoch_packet_num = isoch_packet_num;
+ init_td->isoch_packet_index = 0;
+ init_td->isoch_packet_position = 0;
+ init_td->sched_frame = isoch_start_frame;
+ init_td->used_total_bus_time = parent_ed->ed_desc.used_bus_time;
+ init_td->td_id = (u32)init_td;
+ init_td->transfer_flag = transfer_flag;
+ init_td->transferred_szie = 0;
+
+ switch(parent_ed->ed_desc.endpoint_type) {
+ case CONTROL_TRANSFER:
+ init_nonperio_stransfer(true, init_td);
+ break;
+
+ case BULK_TRANSFER:
+ init_nonperio_stransfer(false, init_td);
+ break;
+
+ case INT_TRANSFER:
+ init_perio_stransfer(false, init_td);
+ break;
+
+ case ISOCH_TRANSFER:
+ init_perio_stransfer(true, init_td);
+ break;
+
+ default:
+ return USB_ERR_FAIL;
+ }
+
+ //insert the td_t to parent_ed->td_list_entry.
+ otg_list_push_prev(&init_td->td_list_entry,&parent_ed->td_list_entry);
+ parent_ed->num_td++;
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name int issue_transfer(struct sec_otghost *otghost,
+ * ed_t *parent_ed,
+ * void *call_back_func,
+ * void *call_back_param,
+ * u32 transfer_flag,
+ * bool f_is_standard_dev_req,
+ * u32 setup_vir_addr,
+ * u32 setup_phy_addr,
+ * u32 vir_buf_addr,
+ * u32 phy_buf_addr,
+ * u32 buf_size,
+ * u32 start_frame,
+ * u32 isoch_packet_num,
+ * isoch_packet_desc_t *isoch_packet_desc,
+ * void *td_priv,
+ * unsigned int *return_td_addr)
+ *
+ * @brief this function start USB Transfer
+ *
+ *
+ * @param [IN] parent_ed - indicate the ed_t to manage this issue transfer.
+ * [IN] call_back_func - indicate the call-back function of application.
+ * [IN] call_back_param - indicate the parameter of the call-back function.
+ * [IN] transfer_flag - indicate the transfer flag.
+ * [IN] f_is_standard_dev_req - indicates the issue transfer request is USB Standard Request
+ * [IN] setup_vir_addr - the virtual address of buffer to store the USB Standard Request.
+ * [IN] setup_phy_addr - the physical address of buffer to store the USB Standard Request.
+ * [IN] vir_buf_addr - the virtual address of buffer to store the data to be transferred or received.
+ * [IN] phy_buf_addr - the physical address of buffer to store the data to be transferred or received.
+ * [IN] buf_size - indicates the buffer size.
+ * [IN] start_frame - if this usb transfer is isochronous transfer
+ * , this indicates the start frame to start the usb transfer.
+ * [IN] isoch_packet_num - if the usb transfer is isochronous transfer
+ * , this indicates the number of packet to consist of the usb transfer.
+ * [IN] isoch_packet_desc - if the usb transfer is isochronous transfer
+ * , this indicates the structure to describe the isochronous transfer.
+ * [IN] td_priv - indicate the private data to be delivered from usb core of linux.
+ * td_priv stores the urb of linux.
+ * [OUT] return_td_addr - indicates the variable address to store the new td_t for this transfer
+ *
+ * @return USB_ERR_SUCCESS -if successes to initiate the new td_t.
+ * USB_ERR_FAILl -if fails to create to new td_t.
+ */
+/******************************************************************************/
+int issue_transfer(struct sec_otghost *otghost,
+ ed_t *parent_ed,
+ void *call_back_func,
+ void *call_back_param,
+ u32 transfer_flag,
+ bool f_is_standard_dev_req,
+ u32 setup_vir_addr,
+ u32 setup_phy_addr,
+ u32 vir_buf_addr,
+ u32 phy_buf_addr,
+ u32 buf_size,
+ u32 start_frame,
+ u32 isoch_packet_num,
+ isoch_packet_desc_t *isoch_packet_desc,
+ void *td_priv,
+ unsigned int *return_td_addr)
+{
+ td_t *new_td_p = NULL;
+
+ int err = USB_ERR_SUCCESS;
+ if(create_td(&new_td_p)==USB_ERR_SUCCESS) {
+ err = init_td( new_td_p,
+ parent_ed,
+ call_back_func,
+ call_back_param,
+ transfer_flag,
+ f_is_standard_dev_req,
+ setup_phy_addr,
+ setup_vir_addr,
+ vir_buf_addr,
+ phy_buf_addr,
+ buf_size,
+ start_frame,
+ isoch_packet_desc,
+ isoch_packet_num,
+ td_priv);
+
+ if(err !=USB_ERR_SUCCESS) {
+ return USB_ERR_NOMEM;
+ }
+
+ if(parent_ed->is_need_to_insert_scheduler) {
+ insert_ed_to_scheduler(otghost, parent_ed);
+ }
+
+ *return_td_addr = (u32)new_td_p;
+
+ return USB_ERR_SUCCESS;
+ }
+ else {
+ return USB_ERR_NOMEM;
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int cancel_transfer(struct sec_otghost *otghost,
+ * ed_t *parent_ed,
+ * td_t *cancel_td)
+ *
+ * @brief this function cancels to transfer USB Transfer of cancel_td.
+ * this function firstly check whether this cancel_td is transferring or not
+ * if the cancel_td is transferring, the this function requests to cancel the USB Transfer
+ * to S3CScheduler. if the parent_ed is for Periodic Transfer, and
+ * there is not any td_t at parent_ed, then this function requests to release
+ * some usb resources for the ed_t to S3CScheduler. finally this function deletes the cancel_td.
+ *
+ * @param [IN] pUpdateTD = indicates the pointer ot the td_t to have STransfer to be updated.
+ *
+ * @return USB_ERR_SUCCESS - if success to update the STranfer of pUpdateTD.
+ * USB_ERR_FAIL - if fail to update the STranfer of pUpdateTD.
+ */
+ /******************************************************************************/
+int cancel_transfer(struct sec_otghost *otghost,
+ ed_t *parent_ed,
+ td_t *cancel_td)
+{
+ int err = USB_ERR_DEQUEUED;
+ otg_list_head *tmp_list_p, *tmp_list2_p;
+ bool cond_found = false;
+
+ if(parent_ed == NULL || cancel_td == NULL) {
+ otg_dbg(OTG_DBG_TRANSFER, "parent_ed == NULL || cancel_td == NULL\n");
+ cancel_td->error_code = USB_ERR_NOELEMENT;
+ otg_usbcore_giveback(cancel_td);
+ return cancel_td->error_code;
+ }
+
+ otg_list_for_each_safe(tmp_list_p, tmp_list2_p, &parent_ed->td_list_entry) {
+ if(&cancel_td->td_list_entry == tmp_list_p) {
+ cond_found = true;
+ break;
+ }
+ }
+
+ if (cond_found != true) {
+ otg_dbg(OTG_DBG_TRANSFER, "cond_found != true \n");
+ cancel_td->error_code = USB_ERR_NOELEMENT;
+ otg_usbcore_giveback(cancel_td);
+ return cancel_td->error_code;
+ }
+
+
+ if(cancel_td->is_transferring) {
+ if(!parent_ed->ed_status.is_in_transfer_ready_q) {
+ err = cancel_to_transfer_td(otghost, cancel_td);
+
+ parent_ed->ed_status.in_transferring_td = 0;
+
+ if(err != USB_ERR_SUCCESS) {
+ otg_dbg(OTG_DBG_TRANSFER, "cancel_to_transfer_td \n");
+ cancel_td->error_code = err;
+ otg_usbcore_giveback(cancel_td);
+ goto ErrorStatus;
+ }
+
+ }
+ // kevinh - even if the record was in the ready queue it is important to delete it as well. We can also always remove the ed from the scheduler
+ // once all tds have been removed
+ otg_list_pop(&cancel_td->td_list_entry);
+ parent_ed->num_td--;
+ }
+ else {
+ otg_list_pop(&cancel_td->td_list_entry);
+ parent_ed->num_td--;
+
+ if(parent_ed->num_td==0) {
+ remove_ed_from_scheduler(parent_ed);
+ }
+ }
+
+ if(parent_ed->num_td) {
+ // kevinh - we do not want to force insert_scheduler, because if this endpoint _was_ already scheduled
+ // because the deleted td was not the active td then we will now put ed into the scheduler list twice, thus
+ // corrupting it.
+ // parent_ed->is_need_to_insert_scheduler = true;
+ insert_ed_to_scheduler(otghost, parent_ed);
+ }
+ else {
+ if(parent_ed->ed_desc.endpoint_type == INT_TRANSFER ||
+ parent_ed->ed_desc.endpoint_type == ISOCH_TRANSFER) {
+ //Release channel and usb bus resource for this ed_t.
+ //but, not release memory for this ed_t.
+ free_usb_resource_for_periodic(parent_ed->ed_desc.used_bus_time,
+ cancel_td->cur_stransfer.alloc_chnum,
+ cancel_td->parent_ed_p->ed_desc.endpoint_type);
+
+ parent_ed->ed_status.is_alloc_resource_for_ed =false;
+ }
+ }
+ // the caller of this functions should call otg_usbcore_giveback(cancel_td);
+ cancel_td->error_code = USB_ERR_DEQUEUED;
+ // kevinh - fixed bug, the caller should take care of calling delete_td because they might still want to do some
+ // operations on that memory
+ // delete_td(cancel_td);
+ // otg_usbcore_giveback(cancel_td);
+
+ErrorStatus:
+
+ return err;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int cancel_all_td(struct sec_otghost *otghost, ed_t *parent_ed)
+ *
+ * @brief this function cancels all Transfer which parent_ed manages.
+ *
+ * @param [IN] parent_ed = indicates the pointer ot the ed_t to manage TD_ts to be canceled.
+ *
+ * @return USB_ERR_SUCCESS - if success to cancel all TD_ts of pParentsED.
+ * USB_ERR_FAIL - if fail to cancel all TD_ts of pParentsED.
+ */
+ /******************************************************************************/
+int cancel_all_td(struct sec_otghost *otghost, ed_t *parent_ed)
+{
+ otg_list_head *cancel_td_list_entry;
+ td_t *cancel_td;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "cancel_all_td \n");
+ do {
+ cancel_td_list_entry = parent_ed->td_list_entry.next;
+
+ cancel_td = otg_list_get_node(cancel_td_list_entry,td_t, td_list_entry);
+
+ if(cancel_transfer(otghost, parent_ed, cancel_td) == USB_ERR_DEQUEUED)
+ // kevinh FIXME - do we also need to giveback?
+ delete_td(otghost,cancel_td);
+ } while(parent_ed->num_td);
+
+ return USB_ERR_SUCCESS;
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transfer-nonperiodic.c b/drivers/usb/host/s3c-otg/s3c-otg-transfer-nonperiodic.c
new file mode 100644
index 0000000..013a2a2
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transfer-nonperiodic.c
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : NonPeriodicTransfer.c
+ * [Description] : This source file implements the functions to be defined at NonPeriodicTransfer Module.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/07
+ * [Revision History]
+ * (1) 2008/06/07 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements some functions of NonPeriodicTransfer.
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+
+#include "s3c-otg-transfer-transfer.h"
+
+/******************************************************************************/
+/*!
+ * @name int init_nonperio_stransfer( bool f_is_standard_dev_req,
+ * td_t *parent_td)
+ *
+ * @brief this function initiates the parent_td->cur_stransfer for NonPeriodic Transfer and
+ * inserts this init_td_p to init_td_p->parent_ed_p.
+ *
+ * @param [IN] f_is_standard_dev_req = indicates whether this transfer is Control or not.
+ * [IN] parent_td = indicates the address of td_t to be initiated.
+ *
+ * @return USB_ERR_SUCCESS - if success to update the STranfer of pUpdateTD.
+ * USB_ERR_FAIL - if fail to update the STranfer of pUpdateTD.
+ */
+ /******************************************************************************/
+int init_nonperio_stransfer(bool f_is_standard_dev_req,
+ td_t *parent_td)
+{
+
+
+ parent_td->cur_stransfer.ed_desc_p = &parent_td->parent_ed_p->ed_desc;
+ parent_td->cur_stransfer.ed_status_p = &parent_td->parent_ed_p->ed_status;
+ parent_td->cur_stransfer.alloc_chnum = CH_NONE;
+ parent_td->cur_stransfer.parent_td = (u32)parent_td;
+ parent_td->cur_stransfer.stransfer_id = (u32)&parent_td->cur_stransfer;
+
+ otg_mem_set(&(parent_td->cur_stransfer.hc_reg), 0, sizeof(hc_reg_t));
+
+ parent_td->cur_stransfer.hc_reg.hc_int_msk.b.chhltd = 1;
+
+ if(f_is_standard_dev_req)
+ {
+ parent_td->cur_stransfer.buf_size = USB_20_STAND_DEV_REQUEST_SIZE;
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->standard_dev_req_info.phy_standard_dev_req_addr;
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->standard_dev_req_info.vir_standard_dev_req_addr;
+ }
+ else
+ {
+ parent_td->cur_stransfer.buf_size = (parent_td->buf_size>MAX_CH_TRANSFER_SIZE)
+ ?MAX_CH_TRANSFER_SIZE
+ :parent_td->buf_size;
+
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->phy_buf_addr;
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->vir_buf_addr;
+ }
+
+ parent_td->cur_stransfer.packet_cnt = calc_packet_cnt(parent_td->cur_stransfer.buf_size
+ , parent_td->parent_ed_p->ed_desc.max_packet_size);
+
+ return USB_ERR_SUCCESS;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name void update_nonperio_stransfer(td_t *parent_td)
+ *
+ * @brief this function updates the parent_td->cur_stransfer to be used by S3COCI.
+ *
+ * @param [IN/OUT]parent_td = indicates the pointer of td_t to store the STranser to be updated.
+ *
+ * @return USB_ERR_SUCCESS -if success to update the parent_td->cur_stransfer.
+ * USB_ERR_FAIL -if fail to update the parent_td->cur_stransfer.
+ */
+ /******************************************************************************/
+void update_nonperio_stransfer(td_t *parent_td)
+{
+ switch(parent_td->parent_ed_p->ed_desc.endpoint_type) {
+ case BULK_TRANSFER:
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->phy_buf_addr+parent_td->transferred_szie;
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->vir_buf_addr+parent_td->transferred_szie;
+ parent_td->cur_stransfer.buf_size = ((parent_td->buf_size - parent_td->transferred_szie)>MAX_CH_TRANSFER_SIZE)
+ ?MAX_CH_TRANSFER_SIZE
+ :parent_td->buf_size - parent_td->transferred_szie;
+ break;
+
+ case CONTROL_TRANSFER:
+ if(parent_td->standard_dev_req_info.conrol_transfer_stage == SETUP_STAGE)
+ {
+ // but, this case will not be occured......
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->standard_dev_req_info.phy_standard_dev_req_addr;
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->standard_dev_req_info.vir_standard_dev_req_addr;
+ parent_td->cur_stransfer.buf_size = 8;
+ }
+ else if(parent_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->phy_buf_addr+parent_td->transferred_szie;
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->vir_buf_addr+parent_td->transferred_szie;
+ parent_td->cur_stransfer.buf_size = ((parent_td->buf_size - parent_td->transferred_szie)>MAX_CH_TRANSFER_SIZE)
+ ?MAX_CH_TRANSFER_SIZE
+ :parent_td->buf_size - parent_td->transferred_szie;
+ }
+ else
+ {
+ parent_td->cur_stransfer.start_phy_buf_addr = 0;
+ parent_td->cur_stransfer.start_vir_buf_addr = 0;
+ parent_td->cur_stransfer.buf_size = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ parent_td->cur_stransfer.packet_cnt = calc_packet_cnt(parent_td->cur_stransfer.buf_size, parent_td->parent_ed_p->ed_desc.max_packet_size);
+
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transfer-periodic.c b/drivers/usb/host/s3c-otg/s3c-otg-transfer-periodic.c
new file mode 100644
index 0000000..f254b78
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transfer-periodic.c
@@ -0,0 +1,128 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : NonPeriodicTransfer.c
+ * [Description] : This source file implements the functions to be defined at NonPeriodicTransfer Module.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/09
+ * [Revision History]
+ * (1) 2008/06/09 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements some functions of PeriodicTransfer.
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-transfer-transfer.h"
+
+
+/******************************************************************************/
+/*!
+ * @name int init_perio_stransfer( bool f_is_isoch_transfer,
+ * td_t *parent_td)
+ *
+ * @brief this function initiates the parent_td->cur_stransfer for Periodic Transfer and
+ * inserts this init_td_p to init_td_p->parent_ed_p.
+ *
+ * @param [IN] f_is_isoch_transfer = indicates whether this transfer is Isochronous or not.
+ * [IN] parent_td = indicates the address of td_t to be initiated.
+ *
+ * @return USB_ERR_SUCCESS -if success to update the STranfer of pUpdateTD.
+ * USB_ERR_FAIL -if fail to update the STranfer of pUpdateTD.
+ */
+ /******************************************************************************/
+int init_perio_stransfer( bool f_is_isoch_transfer,
+ td_t *parent_td)
+{
+ parent_td->cur_stransfer.ed_desc_p = &parent_td->parent_ed_p->ed_desc;
+ parent_td->cur_stransfer.ed_status_p = &parent_td->parent_ed_p->ed_status;
+ parent_td->cur_stransfer.alloc_chnum = CH_NONE;
+ parent_td->cur_stransfer.parent_td = (u32)parent_td;
+ parent_td->cur_stransfer.stransfer_id = (u32)&parent_td->cur_stransfer;
+
+ otg_mem_set(&parent_td->cur_stransfer.hc_reg, 0, sizeof(hc_reg_t));
+
+ parent_td->cur_stransfer.hc_reg.hc_int_msk.b.chhltd = 1;
+
+ if(f_is_isoch_transfer)
+ {
+ // initiates the STransfer usinb the IsochPacketDesc[0].
+ parent_td->cur_stransfer.buf_size =parent_td->isoch_packet_desc_p[0].buf_size;
+ parent_td->cur_stransfer.start_phy_buf_addr =parent_td->phy_buf_addr + parent_td->isoch_packet_desc_p[0].isoch_packiet_start_addr;
+ parent_td->cur_stransfer.start_vir_buf_addr =parent_td->vir_buf_addr + parent_td->isoch_packet_desc_p[0].isoch_packiet_start_addr;
+ }
+ else
+ {
+ parent_td->cur_stransfer.buf_size =(parent_td->buf_size>MAX_CH_TRANSFER_SIZE)
+ ?MAX_CH_TRANSFER_SIZE
+ :parent_td->buf_size;
+
+ parent_td->cur_stransfer.start_phy_buf_addr =parent_td->phy_buf_addr;
+ parent_td->cur_stransfer.start_vir_buf_addr =parent_td->vir_buf_addr;
+ }
+
+ parent_td->cur_stransfer.packet_cnt = calc_packet_cnt(parent_td->cur_stransfer.buf_size, parent_td->parent_ed_p->ed_desc.max_packet_size);
+
+ return USB_ERR_SUCCESS;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name void update_perio_stransfer(td_t *parent_td)
+ *
+ * @brief this function updates the parent_td->cur_stransfer to be used by S3COCI.
+ * the STransfer of parent_td is for Periodic Transfer.
+ *
+ * @param [IN/OUT]parent_td = indicates the pointer of td_t to store the STranser to be updated.
+ *
+ * @return USB_ERR_SUCCESS -if success to update the parent_td->cur_stransfer.
+ * USB_ERR_FAIL -if fail to update the parent_td->cur_stransfer.
+ */
+ /******************************************************************************/
+void update_perio_stransfer(td_t *parent_td)
+{
+ switch(parent_td->parent_ed_p->ed_desc.endpoint_type) {
+ case INT_TRANSFER:
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->phy_buf_addr+parent_td->transferred_szie;
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->vir_buf_addr+parent_td->transferred_szie;
+ parent_td->cur_stransfer.buf_size = (parent_td->buf_size>MAX_CH_TRANSFER_SIZE)
+ ?MAX_CH_TRANSFER_SIZE :parent_td->buf_size;
+ break;
+
+ case ISOCH_TRANSFER:
+ parent_td->cur_stransfer.start_phy_buf_addr = parent_td->phy_buf_addr
+ +parent_td->isoch_packet_desc_p[parent_td->isoch_packet_index].isoch_packiet_start_addr
+ +parent_td->isoch_packet_position;
+
+ parent_td->cur_stransfer.start_vir_buf_addr = parent_td->vir_buf_addr
+ +parent_td->isoch_packet_desc_p[parent_td->isoch_packet_index].isoch_packiet_start_addr
+ +parent_td->isoch_packet_position;
+
+ parent_td->cur_stransfer.buf_size = (parent_td->isoch_packet_desc_p[parent_td->isoch_packet_index].buf_size - parent_td->isoch_packet_position)>MAX_CH_TRANSFER_SIZE
+ ?MAX_CH_TRANSFER_SIZE
+ :parent_td->isoch_packet_desc_p[parent_td->isoch_packet_index].buf_size - parent_td->isoch_packet_position;
+
+ break;
+
+ default:
+ break;
+ }
+}
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transfer-transfer.h b/drivers/usb/host/s3c-otg/s3c-otg-transfer-transfer.h
new file mode 100644
index 0000000..6e1532c
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transfer-transfer.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : s3c-otg-transfer-transfer.h
+ * [Description] : The Header file defines the external and internal functions of Transfer.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/03
+ * [Revision History]
+ * (1) 2008/06/03 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of Transfer
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
+ * : Optimizing for performance \n
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _TRANSFER_H
+#define _TRANSFER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+//#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-hcdi-memory.h"
+#include "s3c-otg-hcdi-kal.h"
+#include "s3c-otg-hcdi-debug.h"
+
+#include "s3c-otg-scheduler-scheduler.h"
+#include "s3c-otg-isr.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void init_transfer(void);
+void deinit_transfer(struct sec_otghost *otghost);
+
+int issue_transfer(struct sec_otghost *otghost,
+ ed_t *parent_ed,
+ void *call_back_func,
+ void *call_back_param,
+ u32 transfer_flag,
+ bool f_is_standard_dev_req,
+ u32 setup_vir_addr,
+ u32 setup_phy_addr,
+ u32 vir_buf_addr,
+ u32 phy_buf_addr,
+ u32 buf_size,
+ u32 start_frame,
+ u32 isoch_packet_num,
+ isoch_packet_desc_t *isoch_packet_desc,
+ void *td_priv,
+ unsigned int *return_td_addr);
+
+int cancel_transfer(struct sec_otghost *otghost,
+ ed_t *parent_ed,
+ td_t *cancel_td);
+
+int cancel_all_td(struct sec_otghost *otghost, ed_t *parent_ed);
+
+int create_ed(ed_t ** new_ed);
+
+int init_ed(ed_t * init_ed,
+ u8 dev_addr,
+ u8 ep_num,
+ bool f_is_ep_in,
+ u8 dev_speed,
+ u8 ep_type,
+ u16 max_packet_size,
+ u8 multi_count,
+ u8 interval,
+ u32 sched_frame,
+ u8 hub_addr,
+ u8 hub_port,
+ bool f_is_do_split,
+ void *ep);
+
+int delete_ed(struct sec_otghost *otghost, ed_t *delete_ed);
+
+int delete_td(struct sec_otghost *otghost, td_t * delete_td);
+
+int create_isoch_packet_desc( isoch_packet_desc_t **new_isoch_packet_desc,
+ u32 isoch_packet_num);
+
+int delete_isoch_packet_desc( isoch_packet_desc_t *del_isoch_packet_desc,
+ u32 isoch_packet_num);
+
+
+void init_isoch_packet_desc( isoch_packet_desc_t *init_isoch_packet_desc,
+ u32 offset,
+ u32 isoch_packet_size,
+ u32 index);
+
+// NonPeriodicTransfer.c implements.
+
+int init_nonperio_stransfer(bool f_is_standard_dev_req,
+ td_t *parent_td);
+
+void update_nonperio_stransfer(td_t *parent_td);
+
+//PeriodicTransfer.c implements
+
+int init_perio_stransfer( bool f_is_isoch_transfer,
+ td_t *parent_td);
+
+void update_perio_stransfer(td_t *parent_td);
+
+static inline u32 calc_packet_cnt(u32 data_size, u16 max_packet_size)
+{
+ if(data_size != 0)
+ {
+ return (data_size%max_packet_size==0)?data_size/max_packet_size:data_size/max_packet_size+1;
+ }
+ return 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.c b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.c
new file mode 100644
index 0000000..e544f5c
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.c
@@ -0,0 +1,720 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : BulkTransferChecker.c
+ * [Description] : The Source file implements the external and internal functions of BulkTransferChecker.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/13
+ * [Revision History]
+ * (1) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of BulkTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-transferchecker-bulk.h"
+#include "s3c-otg-isr.h"
+
+/******************************************************************************/
+/*!
+ * @name u8 process_bulk_transfer(td_t *result_td,
+ hc_info_t *hc_reg_data)
+
+ *
+ * @brief this function processes the result of the Bulk Transfer.
+ * firstly, this function checks the result of the Bulk Transfer.
+ * and according to the result, calls the sub-functions to process the result.
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t whose channel is interruped.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if need to retransmit the result_td.
+ * RE_SCHEDULE -if need to reschedule the result_td.
+ * DE_ALLOCATE -if USB Transfer is completed.
+ * NO_ACTION -if we don't need any action,
+ */
+/******************************************************************************/
+u8 process_bulk_transfer(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ hcintn_t hc_intr_info;
+ u8 return_val=0;
+
+ //we just deal with the interrupts to be unmasked.
+ hc_intr_info.d32 = hc_reg_data->hc_int.d32 & result_td->cur_stransfer.hc_reg.hc_int_msk.d32;
+
+ if(result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ if(hc_intr_info.b.chhltd)
+ {
+ return_val = process_chhltd_on_bulk(result_td, hc_reg_data);
+ }
+
+ else if (hc_intr_info.b.ack)
+ {
+ return_val =process_ack_on_bulk(result_td, hc_reg_data);
+ }
+
+ else if (hc_intr_info.b.nak)
+ {
+ return_val =process_nak_on_bulk(result_td, hc_reg_data);
+ }
+
+ else if (hc_intr_info.b.datatglerr)
+ {
+ return_val = process_datatgl_on_bulk(result_td,hc_reg_data);
+ }
+ }
+ else
+ {
+ if(hc_intr_info.b.chhltd)
+ {
+ return_val = process_chhltd_on_bulk(result_td, hc_reg_data);
+
+ }
+
+ else if(hc_intr_info.b.ack)
+ {
+ return_val =process_ack_on_bulk( result_td, hc_reg_data);
+ }
+ }
+
+ return return_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_chhltd_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function processes Channel Halt event according to Synopsys OTG Spec.
+ * firstly, this function checks the reason of the Channel Halt, and according to the reason,
+ * calls the sub-functions to process the result.
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if need to retransmit the result_td.
+ * RE_SCHEDULE -if need to reschedule the result_td.
+ * DE_ALLOCATE -if USB Transfer is completed.
+ */
+/******************************************************************************/
+u8 process_chhltd_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+#if 0
+ if(result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ if(hc_reg_data->hc_int.b.xfercompl)
+ {
+ return process_xfercompl_on_bulk( result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.stall)
+ {
+ return process_stall_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.bblerr)
+ {
+ return process_bblerr_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.xacterr)
+ {
+ return process_xacterr_on_bulk(result_td, hc_reg_data);
+ }
+ else
+ {
+ //Occure Error State.....
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->err_cnt++;
+ if(result_td->err_cnt == 3)
+ {
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ result_td->err_cnt = 0;
+ return DE_ALLOCATE;
+ }
+
+ return RE_TRANSMIT;
+ }
+ }
+ else
+ {
+ if(hc_reg_data->hc_int.b.xfercompl)
+ {
+ return process_xfercompl_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.stall)
+ {
+ return process_stall_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.xacterr)
+ {
+ return process_xacterr_on_bulk(result_td, hc_reg_data);
+ }
+
+ else if(hc_reg_data->hc_int.b.nak)
+ {
+ return process_nak_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.nyet)
+ {
+ return process_nyet_on_bulk(result_td, hc_reg_data);
+ }
+ else
+ {
+ //occur error state...
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->err_cnt++;
+ if(result_td->err_cnt == 3)
+ {
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ result_td->err_cnt = 0;
+ return DE_ALLOCATE;
+ }
+
+ return RE_TRANSMIT;
+ }
+
+
+
+ }
+#else
+ if(hc_reg_data->hc_int.b.xfercompl)
+ {
+ return process_xfercompl_on_bulk( result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.stall)
+ {
+ return process_stall_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.bblerr)
+ {
+ return process_bblerr_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.xacterr)
+ {
+ return process_xacterr_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.nak)
+ {
+ return process_nak_on_bulk(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.nyet)
+ {
+ return process_nyet_on_bulk(result_td, hc_reg_data);
+ }
+ else
+ {
+ //occur error state...
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->err_cnt++;
+ if(result_td->err_cnt == 3)
+ {
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ result_td->err_cnt = 0;
+ return DE_ALLOCATE;
+ }
+
+ return RE_TRANSMIT;
+ }
+#endif
+ return USB_ERR_SUCCESS;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xfercompl_on_bulk( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xfercompl event according to Synopsys OTG Spec.
+ * the procedure of this function is as following
+ * 1. clears all bits of the channel' HCINT by using clear_ch_intr() of S3CIsr.
+ * 2. masks some bit of HCINTMSK
+ * 3. updates the result_td fields
+ * err_cnt/u8/standard_dev_req_info.
+ * 4. updates the result_td->parent_ed_p->ed_status.
+ * BulkDataTgl.
+ * 5. calculates the tranferred size by calling calc_transferred_size() on DATA_STAGE.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+u8 process_xfercompl_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ u8 ret_val=0;
+
+ result_td->err_cnt = 0;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable =false;
+
+ result_td->transferred_szie += calc_transferred_size(true,result_td, hc_reg_data);
+
+ if(result_td->transferred_szie==result_td->buf_size)
+ {//at IN Transfer, short transfer is accepted.
+ result_td->error_code = USB_ERR_STATUS_COMPLETE;
+ ret_val = DE_ALLOCATE;
+ }
+ else
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in&& hc_reg_data->hc_size.b.xfersize)
+ {
+ if(result_td->transfer_flag&USB_TRANS_FLAG_NOT_SHORT)
+ {
+ result_td->error_code =USB_ERR_STATUS_SHORTREAD;
+ }
+ else
+ {
+ result_td->error_code =USB_ERR_STATUS_COMPLETE;
+ }
+ ret_val = DE_ALLOCATE;
+ }
+ else
+ {
+ ret_val = RE_SCHEDULE;
+ }
+ }
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ if(hc_reg_data->hc_int.b.nyet)
+ {
+ //at OUT Transfer, we must re-transmit.
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+ }
+ }
+
+ return ret_val;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ahb_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theAHB Errorl event according to Synopsys OTG Spec.
+ * this function stop the channel to be executed
+ * TBD....
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+u8 process_ahb_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt =0;
+ result_td->error_code =USB_ERR_STATUS_AHBERR;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_AHBErr);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ // we just calculate the size of the transferred data on Data Stage of Bulk Transfer.
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+
+ return DE_ALLOCATE;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_stall_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theStall event according to Synopsys OTG Spec.
+ * when Stall is occured at Bulk Transfer, we should reset the PID as DATA0
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_stall_on_bulk( td_t * result_td,
+ hc_info_t * hc_reg_data)
+{
+ result_td->err_cnt =0;
+ result_td->error_code =USB_ERR_STATUS_STALL;
+
+ //this channel is stalled, So we don't process another interrupts.
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ update_datatgl(DATA0, result_td);
+
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nak_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nak event according to Synopsys OTG Spec.
+ * nak is occured at OUT/IN Transaction of Data/Status Stage, and is not occured at Setup Stage.
+ * If nak is occured at IN Transaction, this function processes this interrupt as following.
+ * 1. resets the result_td->err_cnt.
+ * 2. masks ack/nak/DaaTglErr bit of HCINTMSK.
+ * 3. clears the nak bit of HCINT
+ * 4. be careful, nak of IN Transaction don't require re-transmit.
+ * If nak is occured at OUT Transaction, this function processes this interrupt as following.
+ * 1. all procedures of IN Transaction are executed.
+ * 2. calculates the size of the transferred data.
+ * 3. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 4. update the Toggle
+ * at OUT Transaction, this function check whether the speed of USB Device is High-Speed or not.
+ * if USB Device is High-Speed, then
+ * this function sets the ping protocol.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE -if the direction of the Transfer is OUT
+ * NO_ACTION -if the direction of the Transfer is IN
+ */
+/******************************************************************************/
+u8 process_nak_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+
+ //at OUT Transfer, we must re-transmit.
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ return RE_TRANSMIT;
+ }
+ return NO_ACTION;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ack_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the ack event according to Synopsys OTG Spec.
+ * ack of IN/OUT Transaction don't need any retransmit.
+ * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
+ * finally, this function clears ack bit of HCINT and ed_status.is_ping_enable.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+u8 process_ack_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+
+ return NO_ACTION;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nyet_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nyet event according to Synopsys OTG Spec.
+ * nyet is only occured at OUT Transaction.
+ * If nyet is occured at OUT Transaction, this function processes this interrupt as following.
+ * 1. resets the result_td->err_cnt.
+ * 2. masks ack/nak/datatglerr bit of HCINTMSK.
+ * 3. clears the nyet bit of HCINT
+ * 4. calculates the size of the transferred data.
+ * 5. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 6. update the Data Toggle.
+ * 7. return RE_SCHEDULE to retransmit.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+u8 process_nyet_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ if(result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ // Error State....
+ return NO_ACTION;
+ }
+
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NYET);
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ return RE_TRANSMIT;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xacterr_on_bulk( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xacterr event according to Synopsys OTG Spec.
+ * xacterr is occured at OUT/IN Transaction and we should retransmit the USB Transfer
+ * if the Error Counter is less than the RETRANSMIT_THRESHOLD.
+ * the reasons of xacterr is Timeout/CRC error/false EOP.
+ * the procedure to process xacterr is as following.
+ * 1. increses the result_td->err_cnt
+ * 2. check whether the result_td->err_cnt is equal to 3.
+ * 2. unmasks ack/nak/datatglerr bit of HCINTMSK.
+ * 3. clears the xacterr bit of HCINT
+ * 4. calculates the size of the transferred data.
+ * 5. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 6. update the Data Toggle.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if the error count is less than 3
+ * DE_ALLOCATE -if the error count is equal to 3
+ */
+/******************************************************************************/
+u8 process_xacterr_on_bulk( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ u8 ret_val = 0;
+
+ if(result_td->err_cnt<RETRANSMIT_THRESHOLD)
+ {
+ result_td->cur_stransfer.hc_reg.hc_int_msk.d32 |= (CH_STATUS_ACK+CH_STATUS_NAK+CH_STATUS_DataTglErr);
+ ret_val = RE_TRANSMIT;
+ result_td->err_cnt++ ;
+ }
+ else
+ {
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ ret_val = DE_ALLOCATE;
+ result_td->err_cnt = 0 ;
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ }
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+ }
+
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ return ret_val;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name void process_bblerr_on_bulk(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the Babble event according to Synopsys OTG Spec.
+ * babble error is occured when the buffer to receive data to be transmit is overflow.
+ * So, babble error can be just occured at IN Transaction.
+ * when Babble Error is occured, we should stop the USB Transfer, and return the fact
+ * to Application.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_bblerr_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+
+ if(!result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ return NO_ACTION;
+ }
+
+ result_td->err_cnt =0;
+ result_td->error_code =USB_ERR_STATUS_BBLERR;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable =false;
+ result_td->transferred_szie += calc_transferred_size(false, result_td, hc_reg_data);
+
+ return DE_ALLOCATE;
+
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_datatgl_on_bulk( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the datatglerr event according to Synopsys OTG Spec.
+ * the datatglerr event is occured at IN Transfer, and the channel is not halted.
+ * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
+ * finally, this function clears datatglerr bit of HCINT.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+u8 process_datatgl_on_bulk(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ return NO_ACTION;
+
+}
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.h b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.h
new file mode 100644
index 0000000..e1f84ca
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-bulk.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : BulkTransferChecker.h
+ * [Description] : The Header file defines the external and internal functions of BulkTransferChecker
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/18
+ * [Revision History]
+ * (1) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of BulkTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _BULK_TRANSFER_CHECKER_H
+#define _BULK_TRANSFER_CHECKER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+u8 process_bulk_transfer(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_xfercompl_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_chhltd_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_ahb_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_stall_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_nak_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_ack_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_nyet_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_xacterr_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_bblerr_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_datatgl_on_bulk(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-checker.h b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-checker.h
new file mode 100644
index 0000000..cefbcaf
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-checker.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : DoneTransferChecker.h
+ * [Description] : The Header file defines the external and internal functions of S3CDoneTransferChecker.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/12
+ * [Revision History]
+ * (1) 2008/06/12 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of S3CDoneTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _DONE_TRANSFER_CHECKER_H
+#define _DONE_TRANSFER_CHECKER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+
+#include "s3c-otg-hcdi-debug.h"
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
+
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.c b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.c
new file mode 100644
index 0000000..689d379
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.c
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : CommonTransferChecker.c
+ * [Description] : The Source file implements the external and internal functions of CommonTransferChecker.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2009/01/12
+ * [Revision History]
+ * (1) 2008/06/12 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of CommonTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-transferchecker-common.h"
+
+/******************************************************************************/
+/*!
+ * @name int init_done_transfer_checker(void)
+ *
+ * @brief this function initiates S3CDoneTransferChecker Module.
+ *
+ *
+ * @param void
+ *
+ * @return void
+ */
+/******************************************************************************/
+//ss1
+/*void init_done_transfer_checker(void)
+{
+ return USB_ERR_SUCCESS;
+}*/
+
+/******************************************************************************/
+/*!
+ * @name void do_transfer_checker(struct sec_otghost *otghost)
+ *
+ * @brief this function processes the result of USB Transfer. So, do_transfer_checker fistly
+ * check which channel occurs OTG Interrupt and gets the status information of the channel.
+ * do_transfer_checker requests the information of td_t to S3CScheduler.
+ * To process the interrupt of the channel, do_transfer_checker calls the sub-modules of
+ * S3CDoneTransferChecker, for example, ControlTransferChecker, BulkTransferChecker.
+ * according to the process result of the channel interrupt, do_transfer_checker decides
+ * the USB Transfer will be done or retransmitted.
+ *
+ *
+ * @param void
+ *
+ * @return void
+ */
+/*******************************************************************************/
+void do_transfer_checker (struct sec_otghost *otghost)
+__releases(&otghost->lock)
+__acquires(&otghost->lock)
+{
+ u32 hc_intr = 0;
+ u32 hc_intr_msk = 0;
+ u8 do_try_cnt = 0;
+
+ hc_info_t ch_info;
+ u32 td_addr = 0;
+ td_t *done_td = {0};
+ u8 proc_result = 0;
+
+ //by ss1
+ otg_mem_set((void *)&ch_info, 0, sizeof(hc_info_t));
+
+ // Get value of HAINT...
+ get_intr_ch(&hc_intr,&hc_intr_msk);
+
+start_do_transfer_checker:
+
+ while(do_try_cnt<MAX_CH_NUMBER) {
+ //checks the channel number to be masked or not.
+ if(!(hc_intr & hc_intr_msk & (1<<do_try_cnt))) {
+ do_try_cnt++;
+ goto start_do_transfer_checker;
+ }
+
+ //Gets the address of the td_t to have the channel to be interrupted.
+ if(get_td_info(do_try_cnt, &td_addr) == USB_ERR_SUCCESS) {
+
+ done_td = (td_t *)td_addr;
+
+ if(do_try_cnt != done_td->cur_stransfer.alloc_chnum) {
+ do_try_cnt++;
+ goto start_do_transfer_checker;
+ }
+ }
+ else {
+ do_try_cnt++;
+ goto start_do_transfer_checker;
+ }
+
+ //Gets the informationof channel to be interrupted.
+ get_ch_info(&ch_info,do_try_cnt);
+
+ switch(done_td->parent_ed_p->ed_desc.endpoint_type) {
+ case CONTROL_TRANSFER:
+ proc_result = process_control_transfer(done_td, &ch_info);
+ break;
+ case BULK_TRANSFER:
+ proc_result = process_bulk_transfer(done_td, &ch_info);
+ break;
+ case INT_TRANSFER:
+ proc_result = process_intr_transfer(done_td, &ch_info);
+ break;
+ case ISOCH_TRANSFER:
+ /* proc_result = ProcessIsochTransfer(done_td, &ch_info); */
+ break;
+ default:break;
+ }
+
+ if((proc_result == RE_TRANSMIT) || (proc_result == RE_SCHEDULE)) {
+ done_td->parent_ed_p->ed_status.is_in_transferring = false;
+ done_td->is_transfer_done = false;
+ done_td->is_transferring = false;
+
+ if(done_td->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER ||
+ done_td->parent_ed_p->ed_desc.endpoint_type==BULK_TRANSFER) {
+ update_nonperio_stransfer(done_td);
+ }
+ else {
+ update_perio_stransfer(done_td);
+ }
+
+ if(proc_result == RE_TRANSMIT) {
+ retransmit(otghost, done_td);
+ }
+ else {
+ reschedule(done_td);
+ }
+ }
+
+ else if(proc_result==DE_ALLOCATE) {
+ done_td->parent_ed_p->ed_status.is_in_transferring = false;
+ done_td->parent_ed_p->ed_status.in_transferring_td = 0;
+ done_td->is_transfer_done = true;
+ done_td->is_transferring = false;
+
+ spin_unlock_otg(&otghost->lock);
+ otg_usbcore_giveback( done_td);
+ spin_lock_otg(&otghost->lock);
+ release_trans_resource(otghost, done_td);
+ }
+ else { //NO_ACTION....
+ done_td->parent_ed_p->ed_status.is_in_transferring = true;
+ done_td->parent_ed_p->ed_status.in_transferring_td = (u32)done_td;
+ done_td->is_transfer_done = false;
+ done_td->is_transferring = true;
+ }
+ do_try_cnt++;
+ }
+ // Complete to process the Channel Interrupt.
+ // So. we now start to scheduler of S3CScheduler.
+ do_schedule(otghost);
+}
+
+
+int release_trans_resource(struct sec_otghost *otghost, td_t *done_td)
+{
+ //remove the pDeallocateTD from parent_ed_p.
+ otg_list_pop(&done_td->td_list_entry);
+ done_td->parent_ed_p->num_td--;
+
+ //Call deallocate to release the channel and bandwidth resource of S3CScheduler.
+ deallocate(done_td);
+ delete_td(otghost, done_td);
+ return USB_ERR_SUCCESS;
+}
+
+u32 calc_transferred_size(bool f_is_complete, td_t *td, hc_info_t *hc_info)
+{
+ if(f_is_complete) {
+ if(td->parent_ed_p->ed_desc.is_ep_in) {
+ return td->cur_stransfer.buf_size - hc_info->hc_size.b.xfersize;
+ }
+ else {
+ return td->cur_stransfer.buf_size;
+ }
+ }
+ else {
+ return (td->cur_stransfer.packet_cnt - hc_info->hc_size.b.pktcnt)*td->parent_ed_p->ed_desc.max_packet_size;
+ }
+}
+
+void update_frame_number(td_t *pResultTD)
+{
+ u32 cur_frame_num=0;
+
+ if(pResultTD->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER ||
+ pResultTD->parent_ed_p->ed_desc.endpoint_type == BULK_TRANSFER) {
+ return;
+ }
+
+ pResultTD->parent_ed_p->ed_desc.sched_frame+= pResultTD->parent_ed_p->ed_desc.interval;
+ pResultTD->parent_ed_p->ed_desc.sched_frame &= HFNUM_MAX_FRNUM;
+
+ cur_frame_num = oci_get_frame_num();
+ if(((cur_frame_num - pResultTD->parent_ed_p->ed_desc.sched_frame)&HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM>>1)) {
+ pResultTD->parent_ed_p->ed_desc.sched_frame = cur_frame_num;
+ }
+}
+
+void update_datatgl(u8 ubCurDataTgl, td_t *td)
+{
+ switch(td->parent_ed_p->ed_desc.endpoint_type) {
+ case CONTROL_TRANSFER:
+ if(td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE) {
+ td->parent_ed_p->ed_status.control_data_tgl.data_tgl = ubCurDataTgl;
+ }
+ break;
+ case BULK_TRANSFER:
+ case INT_TRANSFER:
+ td->parent_ed_p->ed_status.data_tgl = ubCurDataTgl;
+ break;
+
+ case ISOCH_TRANSFER:
+ break;
+ default:break;
+ }
+}
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.h b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.h
new file mode 100644
index 0000000..2ea05b8
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-common.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : CommonTransferChecker.h
+ * [Description] : The Header file defines the external and internal functions of CommonTransferChecker.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/12
+ * [Revision History]
+ * (1) 2008/06/12 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of CommonTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _COMMON_TRANSFER_CHECKER_H
+#define _COMMON_TRANSFER_CHECKER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+#include "s3c-otg-common-common.h"
+//#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-common-regdef.h"
+#include "s3c-otg-transfer-transfer.h"
+
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-hcdi-memory.h"
+#include "s3c-otg-scheduler-scheduler.h"
+#include "s3c-otg-isr.h"
+#include "s3c-otg-transferchecker-control.h"
+#include "s3c-otg-transferchecker-bulk.h"
+#include "s3c-otg-transferchecker-interrupt.h"
+//#include "s3c-otg-transferchecker-iso.h"
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//void init_done_transfer_checker (void);
+void do_transfer_checker (struct sec_otghost *otghost);
+int release_trans_resource(struct sec_otghost *otghost, td_t *done_td);
+u32 calc_transferred_size(bool f_is_complete,
+ td_t *td,
+ hc_info_t *hc_info);
+void update_frame_number(td_t *result_td);
+void update_datatgl(u8 cur_data_tgl,
+ td_t *td);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.c b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.c
new file mode 100644
index 0000000..863f951
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.c
@@ -0,0 +1,698 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : ControlTransferChecker.c
+ * [Description] : The Source file implements the external and internal functions of ControlTransferChecker.
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2009/02/10
+ * [Revision History]
+ * (1) 2008/06/13 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of ControlTransferChecker
+ * (2) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Completed to implement ControlTransferChecker.c v1.0
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#include "s3c-otg-transferchecker-control.h"
+#include "s3c-otg-isr.h"
+
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_control_transfer(td_t *result_td,
+ hc_info_t *hc_reg_data)
+
+ *
+ * @brief this function processes the result of the Control Transfer.
+ * firstly, this function checks the result the Control Transfer.
+ * and according to the result, calls the sub-functions to process the result.
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] ubChNum -indicates the number of the channel to be interrupted.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if need to retransmit the result_td.
+ * RE_SCHEDULE -if need to reschedule the result_td.
+ * DE_ALLOCATE -if USB Transfer is completed.
+ */
+/******************************************************************************/
+u8 process_control_transfer(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ hcintn_t hcintr_info;
+ u8 ret_val=0;
+
+ //we just deal with the interrupts to be unmasked.
+ hcintr_info.d32 = hc_reg_data->hc_int.d32&result_td->cur_stransfer.hc_reg.hc_int_msk.d32;
+
+ if(result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ if(hcintr_info.b.chhltd)
+ {
+ ret_val = process_chhltd_on_control(result_td, hc_reg_data);
+ }
+
+ else if (hcintr_info.b.ack)
+ {
+ ret_val =process_ack_on_control(result_td, hc_reg_data);
+ }
+
+ else if (hcintr_info.b.nak)
+ {
+ ret_val =process_nak_on_control(result_td, hc_reg_data);
+ }
+
+ else if (hcintr_info.b.datatglerr)
+ {
+ ret_val = process_datatgl_on_control(result_td,hc_reg_data);
+ }
+ }
+ else
+ {
+ if(hcintr_info.b.chhltd)
+ {
+ ret_val = process_chhltd_on_control(result_td, hc_reg_data);
+ }
+
+ else if(hcintr_info.b.ack)
+ {
+ ret_val =process_ack_on_control( result_td, hc_reg_data);
+
+ }
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_chhltd_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function processes Channel Halt event according to Synopsys OTG Spec.
+ * firstly, this function checks the reason of the Channel Halt, and according to the reason,
+ * calls the sub-functions to process the result.
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if need to retransmit the result_td.
+ * RE_SCHEDULE -if need to reschedule the result_td.
+ * DE_ALLOCATE -if USB Transfer is completed.
+ */
+/******************************************************************************/
+u8 process_chhltd_on_control( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ if(hc_reg_data->hc_int.b.xfercompl)
+ {
+ return process_xfercompl_on_control( result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.stall)
+ {
+ return process_stall_on_control(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.bblerr)
+ {
+ return process_bblerr_on_control(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.xacterr)
+ {
+ return process_xacterr_on_control(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.nak)
+ {
+ return process_nak_on_control(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.nyet)
+ {
+ return process_nyet_on_control(result_td, hc_reg_data);
+ }
+ else
+ {
+
+ //Occure Error State.....
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ result_td->err_cnt++;
+ if(result_td->err_cnt == 3)
+ {
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ result_td->err_cnt = 0;
+ return DE_ALLOCATE;
+ }
+ return RE_TRANSMIT;
+ }
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xfercompl_on_control(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xfercompl event according to Synopsys OTG Spec.
+ * the procedure of this function is as following
+ * 1. clears all bits of the channel' HCINT by using clear_ch_intr() of S3CIsr.
+ * 2. masks some bit of HCINTMSK
+ * 3. updates the result_td fields
+ * err_cnt/u8/standard_dev_req_info.
+ * 4. updates the result_td->parent_ed_p->ed_status.
+ * control_data_tgl.
+ * 5. calculates the tranferred size by calling calc_transferred_size() on DATA_STAGE.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+u8 process_xfercompl_on_control(td_t *result_td, hc_info_t *hc_reg_data)
+{
+ u8 ret_val = 0;
+
+ result_td->err_cnt = 0;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum,CH_STATUS_ALL);
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+
+ switch(result_td->standard_dev_req_info.conrol_transfer_stage) {
+ case SETUP_STAGE:
+ if(result_td->standard_dev_req_info.is_data_stage) {
+ result_td->standard_dev_req_info.conrol_transfer_stage = DATA_STAGE;
+ }
+ else {
+ result_td->standard_dev_req_info.conrol_transfer_stage = STATUS_STAGE;
+ }
+ ret_val = RE_TRANSMIT;
+
+ break;
+
+ case DATA_STAGE:
+
+ result_td->transferred_szie += calc_transferred_size(true,result_td, hc_reg_data);
+
+ /* at IN Transfer, short transfer is accepted. */
+ if(result_td->transferred_szie==result_td->buf_size) {
+ result_td->standard_dev_req_info.conrol_transfer_stage =STATUS_STAGE;
+ result_td->error_code = USB_ERR_STATUS_COMPLETE;
+ }
+ else {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in&& hc_reg_data->hc_size.b.xfersize) {
+ if(result_td->transfer_flag&USB_TRANS_FLAG_NOT_SHORT) {
+ result_td->error_code = USB_ERR_STATUS_SHORTREAD;
+ result_td->standard_dev_req_info.conrol_transfer_stage=STATUS_STAGE;
+ }
+ else {
+ result_td->error_code = USB_ERR_STATUS_COMPLETE;
+ result_td->standard_dev_req_info.conrol_transfer_stage =STATUS_STAGE;
+ }
+ }
+ else { // the Data Stage is not completed. So we need to continue Data Stage.
+ result_td->standard_dev_req_info.conrol_transfer_stage = DATA_STAGE;
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+ }
+ }
+
+ if(hc_reg_data->hc_int.b.nyet) {
+ /* at OUT Transfer, we must re-transmit. */
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false) {
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG) {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ else {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+ }
+ }
+ ret_val = RE_TRANSMIT;
+ break;
+
+ case STATUS_STAGE:
+ result_td->standard_dev_req_info.conrol_transfer_stage = COMPLETE_STAGE;
+
+ if(hc_reg_data->hc_int.b.nyet) {
+ //at OUT Transfer, we must re-transmit.
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false) {
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG) {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ else {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+ }
+ }
+
+ ret_val = DE_ALLOCATE;
+ break;
+
+ default:
+ break;
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ahb_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theAHB Errorl event according to Synopsys OTG Spec.
+ * this function stop the channel to be executed
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_ahb_on_control( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt =0;
+ result_td->error_code =USB_ERR_STATUS_AHBERR;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_AHBErr);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ // we just calculate the size of the transferred data on Data Stage of Control Transfer.
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+ }
+
+ return DE_ALLOCATE;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_stall_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theStall event according to Synopsys OTG Spec.
+ * but USB2.0 Spec don't permit the Stall on Setup Stage of Control Transfer.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_stall_on_control( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt =0;
+ result_td->error_code =USB_ERR_STATUS_STALL;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+
+ // we just calculate the size of the transferred data on Data Stage of Control Transfer.
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+ }
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nak_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nak event according to Synopsys OTG Spec.
+ * nak is occured at OUT/IN Transaction of Data/Status Stage, and is not occured at Setup Stage.
+ * If nak is occured at IN Transaction, this function processes this interrupt as following.
+ * 1. resets the result_td->err_cnt.
+ * 2. masks ack/nak/DaaTglErr bit of HCINTMSK.
+ * 3. clears the nak bit of HCINT
+ * 4. be careful, nak of IN Transaction don't require re-transmit.
+ * If nak is occured at OUT Transaction, this function processes this interrupt as following.
+ * 1. all procedures of IN Transaction are executed.
+ * 2. calculates the size of the transferred data.
+ * 3. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 4. update the Toggle
+ * at OUT Transaction, this function check whether the speed of USB Device is High-Speed or not.
+ * if USB Device is High-Speed, then
+ * this function sets the ping protocol.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+u8 process_nak_on_control( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+
+ //at OUT Transfer, we must re-transmit.
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+ }
+
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ }
+ else if(result_td->standard_dev_req_info.conrol_transfer_stage == STATUS_STAGE)
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==true)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+
+ }
+
+ return RE_SCHEDULE;
+
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ack_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the ack event according to Synopsys OTG Spec.
+ * ack of IN/OUT Transaction don't need any retransmit.
+ * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
+ * finally, this function clears ack bit of HCINT.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+u8 process_ack_on_control(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable =false;
+
+ return NO_ACTION;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nyet_on_control(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nyet event according to Synopsys OTG Spec.
+ * nyet is occured at OUT Transaction of Data/Status Stage, and is not occured at Setup Stage.
+ * If nyet is occured at OUT Transaction, this function processes this interrupt as following.
+ * 1. resets the result_td->err_cnt.
+ * 2. masks ack/nak/datatglerr bit of HCINTMSK.
+ * 3. clears the nyet bit of HCINT
+ * 4. calculates the size of the transferred data.
+ * 5. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 6. update the Data Toggle.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+u8 process_nyet_on_control(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NYET);
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ }
+ else if(result_td->standard_dev_req_info.conrol_transfer_stage == STATUS_STAGE)
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==true)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+
+ }
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ return RE_SCHEDULE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xacterr_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xacterr event according to Synopsys OTG Spec.
+ * xacterr is occured at OUT/IN Transaction of Data/Status Stage, and is not occured at Setup Stage.
+ * if Timeout/CRC error/false EOP is occured, then xacterr is occured.
+ * the procedure to process xacterr is as following.
+ * 1. increses the result_td->err_cnt
+ * 2. check whether the result_td->err_cnt is equal to 3.
+ * 2. unmasks ack/nak/datatglerr bit of HCINTMSK.
+ * 3. clears the xacterr bit of HCINT
+ * 4. calculates the size of the transferred data.
+ * 5. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 6. update the Data Toggle.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if the Error Counter is less than RETRANSMIT_THRESHOLD
+ * DE_ALLOCATE -if the Error Counter is equal to RETRANSMIT_THRESHOLD
+ */
+/******************************************************************************/
+u8 process_xacterr_on_control(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ u8 ret_val=0;
+
+ if(result_td->err_cnt<RETRANSMIT_THRESHOLD)
+ {
+ result_td->cur_stransfer.hc_reg.hc_int_msk.d32 |= (CH_STATUS_ACK+CH_STATUS_NAK+CH_STATUS_DataTglErr);
+ ret_val = RE_TRANSMIT;
+ unmask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ unmask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ unmask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ result_td->err_cnt++ ;
+ }
+ else
+ {
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ ret_val = DE_ALLOCATE;
+ result_td->err_cnt = 0 ;
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ }
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ }
+
+ if(result_td->parent_ed_p->ed_desc.dev_speed == HIGH_SPEED_OTG)
+ {
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==false)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ }
+ else if(result_td->standard_dev_req_info.conrol_transfer_stage == STATUS_STAGE)
+ {
+ if(result_td->parent_ed_p->ed_desc.is_ep_in==true)
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = true;
+ }
+ }
+ else
+ {
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+ }
+
+
+ }
+
+
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ return ret_val;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name void process_bblerr_on_control( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the Babble event according to Synopsys OTG Spec.
+ * babble error can be just occured at IN Transaction. So if the direction of transfer is
+ * OUT, this function return Error Code.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ * NO_ACTION -if the direction is OUT
+ */
+/******************************************************************************/
+u8 process_bblerr_on_control( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+
+ if(!result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ return NO_ACTION;
+ }
+
+ result_td->err_cnt = 0;
+ result_td->error_code =USB_ERR_STATUS_BBLERR;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->parent_ed_p->ed_status.is_ping_enable =false;
+
+ // we just calculate the size of the transferred data on Data Stage of Control Transfer.
+ if(result_td->standard_dev_req_info.conrol_transfer_stage == DATA_STAGE)
+ {
+ result_td->transferred_szie += calc_transferred_size(false, result_td, hc_reg_data);
+ }
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_datatgl_on_control(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the datatglerr event according to Synopsys OTG Spec.
+ * the datatglerr event is occured at IN Transfer.
+ * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
+ * finally, this function clears datatglerr bit of HCINT.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] hc_reg_data -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+u8 process_datatgl_on_control( td_t * result_td,
+ hc_info_t * hc_reg_data)
+{
+ result_td->err_cnt = 0;
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ return NO_ACTION;
+
+}
+
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.h b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.h
new file mode 100644
index 0000000..4d85367
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-control.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : ControlTransferChecker.h
+ * [Description] : The Header file defines the external and internal functions of ControlTransferChecker
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2009/01/12
+ * [Revision History]
+ * (1) 2008/06/13 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of ControlTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _CONTROL_TRANSFER_CHECKER_H
+#define _CONTROL_TRANSFER_CHECKER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+#include "s3c-otg-common-common.h"
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-common-regdef.h"
+
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-scheduler-scheduler.h"
+
+#include "s3c-otg-transferchecker-checker.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+u8 process_control_transfer( td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_xfercompl_on_control(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_chhltd_on_control( td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_ahb_on_control( td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_stall_on_control( td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_nak_on_control (td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_ack_on_control (td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_nyet_on_control( td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_xacterr_on_control(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_bblerr_on_control( td_t *raw_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_datatgl_on_control(td_t *raw_td,
+ hc_info_t *hc_reg_data);
+u8 process_indirection_on_control( td_t *result_td,
+ hc_info_t *hc_reg_data);
+
+u8 process_outdirection_on_control(td_t *result_td,
+ hc_info_t *hc_reg_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.c b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.c
new file mode 100644
index 0000000..653628e
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.c
@@ -0,0 +1,574 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : IntTransferChecker.c
+ * [Description] : The Source file implements the external and internal functions of IntTransferChecker
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/19
+ * [Revision History]
+ * (1) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and implements functions of IntTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+
+#include "s3c-otg-transferchecker-interrupt.h"
+
+/******************************************************************************/
+/*!
+ * @name u8 process_intr_transfer(td_t *result_td,
+ * hc_info_t *HCRegData)
+ *
+ *
+ * @brief this function processes the result of the Interrupt Transfer.
+ * firstly, this function checks the result of the Interrupt Transfer.
+ * and according to the result, calls the sub-functions to process the result.
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t whose channel is interruped.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if need to retransmit the result_td.
+ * RE_SCHEDULE -if need to reschedule the result_td.
+ * DE_ALLOCATE -if USB Transfer is completed.
+ * NO_ACTION -if we don't need any action,
+ */
+/******************************************************************************/
+u8 process_intr_transfer(td_t *result_td, hc_info_t *hc_reg_data)
+{
+ hcintn_t hc_intr_info;
+ u8 ret_val=0;
+
+ //we just deal with the interrupts to be unmasked.
+ hc_intr_info.d32 = hc_reg_data->hc_int.d32&result_td->cur_stransfer.hc_reg.hc_int_msk.d32;
+
+ if(result_td->parent_ed_p->ed_desc.is_ep_in) {
+ if(hc_intr_info.b.chhltd) {
+ ret_val = process_chhltd_on_intr(result_td, hc_reg_data);
+ }
+
+ else if (hc_intr_info.b.ack) {
+ ret_val = process_ack_on_intr(result_td, hc_reg_data);
+ }
+ }
+ else {
+ if(hc_intr_info.b.chhltd) {
+ ret_val = process_chhltd_on_intr(result_td, hc_reg_data);
+ }
+
+ else if(hc_intr_info.b.ack) {
+ ret_val = process_ack_on_intr( result_td, hc_reg_data);
+ }
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_chhltd_on_intr(td_t *result_td,
+ * hc_info_t *HCRegData)
+ *
+ *
+ * @brief this function processes Channel Halt event according to Synopsys OTG Spec.
+ * firstly, this function checks the reason of the Channel Halt, and according to the reason,
+ * calls the sub-functions to process the result.
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_TRANSMIT -if need to retransmit the result_td.
+ * RE_SCHEDULE -if need to reschedule the result_td.
+ * DE_ALLOCATE -if USB Transfer is completed.
+ */
+/******************************************************************************/
+u8 process_chhltd_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ if(result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ if(hc_reg_data->hc_int.b.xfercompl)
+ {
+ return process_xfercompl_on_intr( result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.stall)
+ {
+ return process_stall_on_intr(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.bblerr)
+ {
+ return process_bblerr_on_intr(result_td, hc_reg_data);
+ }
+ else if (hc_reg_data->hc_int.b.nak)
+ {
+ return process_nak_on_intr(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.datatglerr)
+ {
+ return process_datatgl_on_intr(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.frmovrun)
+ {
+ return process_frmovrrun_on_intr(result_td,hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.xacterr)
+ {
+ return process_xacterr_on_intr(result_td, hc_reg_data);
+ }
+ else
+ {
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ return RE_TRANSMIT;
+ }
+ }
+ else
+ {
+ if(hc_reg_data->hc_int.b.xfercompl)
+ {
+ return process_xfercompl_on_intr( result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.stall)
+ {
+ return process_stall_on_intr(result_td, hc_reg_data);
+ }
+ else if (hc_reg_data->hc_int.b.nak)
+ {
+ return process_nak_on_intr(result_td, hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.frmovrun)
+ {
+ return process_frmovrrun_on_intr(result_td,hc_reg_data);
+ }
+ else if(hc_reg_data->hc_int.b.xacterr)
+ {
+ return process_xacterr_on_intr(result_td, hc_reg_data);
+ }
+ else
+ {
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->err_cnt++;
+ if(result_td->err_cnt == 3)
+ {
+ result_td->error_code = USB_ERR_STATUS_XACTERR;
+ result_td->err_cnt = 0;
+ return DE_ALLOCATE;
+ }
+
+ return RE_TRANSMIT;
+ }
+
+ }
+
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xfercompl_on_intr( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xfercompl event according to Synopsys OTG Spec.
+ * the procedure of this function is as following
+ * 1. clears all bits of the channel' HCINT by using clear_ch_intr() of S3CIsr.
+ * 2. masks ack/nak(?)/datatglerr(?) bit of HCINTMSK
+ * 3. Resets the err_cnt of result_td.
+ * 4. updates the result_td->parent_ed_p->ed_status.
+ * IntDataTgl.
+ * 5. calculates the tranferred size by calling calc_transferred_size() on DATA_STAGE.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE -if USB Transfer is completed.
+ * RE_TRANSMIT -if need to retransmit the result_td.
+ */
+/******************************************************************************/
+u8 process_xfercompl_on_intr( td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ u8 ret_val=0;
+
+ result_td->err_cnt =0;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->transferred_szie += calc_transferred_size(true,result_td, hc_reg_data);
+
+ if(result_td->transferred_szie==result_td->buf_size)
+ {//at IN Transfer, short transfer is accepted.
+ result_td->error_code = USB_ERR_STATUS_COMPLETE;
+ ret_val = DE_ALLOCATE;
+ }
+ else
+ {
+ // this routine will not be executed on Interrupt Transfer.
+ // So, we should decide to remove this routine or not.
+ if(result_td->parent_ed_p->ed_desc.is_ep_in&& hc_reg_data->hc_size.b.xfersize)
+ {
+ if(result_td->transfer_flag&USB_TRANS_FLAG_NOT_SHORT)
+ {
+ result_td->error_code = USB_ERR_STATUS_SHORTREAD;
+ }
+ else
+ {
+ result_td->error_code = USB_ERR_STATUS_COMPLETE;
+ }
+ ret_val = DE_ALLOCATE;
+ }
+ else
+ { // the Data Stage is not completed. So we need to continue Data Stage.
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+ ret_val = RE_TRANSMIT;
+ }
+ }
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ return ret_val;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ahb_on_intr(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theAHB Errorl event according to Synopsys OTG Spec.
+ * this function stop the channel to be executed
+ *
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_ahb_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+ result_td->error_code = USB_ERR_STATUS_AHBERR;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_AHBErr);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ // we just calculate the size of the transferred data on Data Stage of Int Transfer.
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+ result_td->parent_ed_p->ed_status.is_ping_enable =false;
+
+ return DE_ALLOCATE;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_stall_on_intr(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the Stall event according to Synopsys OTG Spec.
+ * when Stall is occured at Int Transfer, we should reset the PID as DATA0
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_stall_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+ result_td->error_code = USB_ERR_STATUS_STALL;
+
+ //this channel is stalled, So we don't process another interrupts.
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ update_datatgl(DATA0, result_td);
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nak_on_intr(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nak event according to Synopsys OTG Spec.
+ * nak is occured at OUT/IN Transaction of Interrupt Transfer.
+ * we can't use ping protocol on Interrupt Transfer. and Syonopsys OTG IP occures
+ * chhltd interrupt on nak of IN/OUT Transaction. So we should retransmit the transfer
+ * on IN Transfer.
+ * If nak is occured at IN Transaction, this function processes this interrupt as following.
+ * 1. resets the result_td->err_cnt.
+ * 2. masks ack/nak/DaaTglErr bit of HCINTMSK.
+ * 3. clears the nak bit of HCINT
+ * 4. calculates frame number to retransmit this Interrupt Transfer.
+ *
+ * If nak is occured at OUT Transaction, this function processes this interrupt as following.
+ * 1. all procedures of IN Transaction are executed.
+ * 2. calculates the size of the transferred data.
+ * 3. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 4. update the Toggle
+ * at OUT Transaction, this function check whether the speed of USB Device is High-Speed or not.
+ * if USB Device is High-Speed, then
+ * this function sets the ping protocol.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE -if the direction of the Transfer is OUT
+ * NO_ACTION -if the direction of the Transfer is IN
+ */
+/******************************************************************************/
+u8 process_nak_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ update_frame_number(result_td);
+
+ return RE_SCHEDULE;
+// return RE_TRANSMIT;
+
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ack_on_intr(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the ack event according to Synopsys OTG Spec.
+ * ack of IN/OUT Transaction don't need any retransmit.
+ * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
+ * finally, this function clears ack bit of HCINT and ed_status.is_ping_enable.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+u8 process_ack_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+
+ return NO_ACTION;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xacterr_on_intr(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ * @brief this function deals with the xacterr event according to Synopsys OTG Spec.
+ * xacterr is occured at OUT/IN Transaction and we should retransmit the USB Transfer
+ * if the Error Counter is less than the RETRANSMIT_THRESHOLD.
+ * the reasons of xacterr is Timeout/CRC error/false EOP.
+ * the procedure to process xacterr is as following.
+ * 1. increses the result_td->err_cnt
+ * 2. check whether the result_td->err_cnt is equal to 3.
+ * 2. unmasks ack/nak/datatglerr bit of HCINTMSK.
+ * 3. clears the xacterr bit of HCINT
+ * 4. calculates the size of the transferred data.
+ * 5. update the Data Toggle.
+ * 6. update the frame number to start retransmitting the Interrupt Transfer.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE -if the error count is less than 3
+ * DE_ALLOCATE -if the error count is equal to 3
+ */
+/******************************************************************************/
+u8 process_xacterr_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ u8 ret_val = 0;
+
+ if(result_td->err_cnt<RETRANSMIT_THRESHOLD)
+ {
+ result_td->cur_stransfer.hc_reg.hc_int_msk.d32 |=(CH_STATUS_ACK+CH_STATUS_NAK+CH_STATUS_DataTglErr);
+ ret_val = RE_SCHEDULE;
+ result_td->err_cnt++ ;
+ }
+ else
+ {
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+ ret_val = DE_ALLOCATE;
+ result_td->err_cnt = 0 ;
+ }
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ if(ret_val == RE_SCHEDULE)
+ { //Calculates the frame number
+ update_frame_number(result_td);
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name void process_bblerr_on_intr(td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the Babble event according to Synopsys OTG Spec.
+ * babble error is occured when the USB device continues to send packets
+ * althrough EOP is occured. So Babble error is only occured at IN Transfer.
+ * when Babble Error is occured, we should stop the USB Transfer, and return the fact
+ * to Application.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+u8 process_bblerr_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+
+ if(!result_td->parent_ed_p->ed_desc.is_ep_in)
+ {
+ return NO_ACTION;
+ }
+
+ result_td->err_cnt = 0;
+ result_td->error_code =USB_ERR_STATUS_BBLERR;
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ //Mask ack Interrupt..
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ result_td->transferred_szie += calc_transferred_size(false, result_td, hc_reg_data);
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_datatgl_on_intr( td_t *result_td,
+ * hc_info_t *hc_reg_data)
+ *
+ * @brief this function deals with the datatglerr event according to Synopsys OTG Spec.
+ * the datatglerr event is occured at IN Transfer, and the channel is not halted.
+ * this function just resets result_td->err_cnt and masks ack/nak/DataTgl of HCINTMSK.
+ * finally, this function clears datatglerr bit of HCINT.
+ *
+ * @param [IN] result_td -indicates the pointer of the td_t to be mapped with the uChNum.
+ * [IN] HCRegData -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+u8 process_datatgl_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+ result_td->err_cnt = 0;
+
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ACK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+ mask_channel_interrupt(result_td->cur_stransfer.alloc_chnum, CH_STATUS_DataTglErr);
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+
+ result_td->transferred_szie += calc_transferred_size(false,result_td, hc_reg_data);
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ update_frame_number(result_td);
+
+ return RE_SCHEDULE;
+}
+
+u8 process_frmovrrun_on_intr(td_t *result_td,
+ hc_info_t *hc_reg_data)
+{
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_NAK);
+
+ update_datatgl(hc_reg_data->hc_size.b.pid, result_td);
+
+ update_frame_number(result_td);
+
+ return RE_TRANSMIT;
+}
+
diff --git a/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.h b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.h
new file mode 100644
index 0000000..0a735a2
--- /dev/null
+++ b/drivers/usb/host/s3c-otg/s3c-otg-transferchecker-interrupt.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * [File Name] : IntTransferChecker.h
+ * [Description] : The Header file defines the external and internal functions of IntTransferChecker
+ * [Author] : Yang Soon Yeal { syatom.yang@samsung.com }
+ * [Department] : System LSI Division/System SW Lab
+ * [Created Date]: 2008/06/19
+ * [Revision History]
+ * (1) 2008/06/18 by Yang Soon Yeal { syatom.yang@samsung.com }
+ * - Created this file and defines functions of IntTransferChecker
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ ****************************************************************************/
+
+#ifndef _INT_TRANSFER_CHECKER_H
+#define _INT_TRANSFER_CHECKER_H
+
+/*
+// ----------------------------------------------------------------------------
+// Include files : None.
+// ----------------------------------------------------------------------------
+*/
+
+#include "s3c-otg-common-common.h"
+//#include "s3c-otg-common-typedef.h"
+#include "s3c-otg-common-const.h"
+#include "s3c-otg-common-errorcode.h"
+#include "s3c-otg-common-datastruct.h"
+#include "s3c-otg-common-regdef.h"
+
+#include "s3c-otg-hcdi-debug.h"
+#include "s3c-otg-scheduler-scheduler.h"
+#include "s3c-otg-isr.h"
+#include "s3c-otg-transferchecker-checker.h"
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+u8 process_intr_transfer(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_xfercompl_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_chhltd_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_ahb_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_stall_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_nak_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_frmovrrun_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_ack_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_xacterr_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_bblerr_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+u8 process_datatgl_on_intr(td_t *pRawTD,
+ hc_info_t *pHCRegData);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/drivers/usb/notify/Kconfig b/drivers/usb/notify/Kconfig
new file mode 100755
index 0000000..159affa
--- /dev/null
+++ b/drivers/usb/notify/Kconfig
@@ -0,0 +1,11 @@
+#
+# USB Host notify configuration
+#
+
+config USB_HOST_NOTIFY
+ boolean "USB Host notify Driver"
+ depends on USB
+ help
+ Android framework needs uevents for usb host operation.
+ Host notify Driver serves uevent format
+ that is used by usb host or otg. \ No newline at end of file
diff --git a/drivers/usb/notify/Makefile b/drivers/usb/notify/Makefile
new file mode 100755
index 0000000..996eaa3
--- /dev/null
+++ b/drivers/usb/notify/Makefile
@@ -0,0 +1,4 @@
+
+# host notify driver
+obj-y += host_notify_class.o
+
diff --git a/drivers/usb/notify/host_notify_class.c b/drivers/usb/notify/host_notify_class.c
new file mode 100755
index 0000000..09ad529
--- /dev/null
+++ b/drivers/usb/notify/host_notify_class.c
@@ -0,0 +1,262 @@
+/*
+ * drivers/usb/notify/host_notify_class.c
+ *
+ * Copyright (C) 2011 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/host_notify.h>
+
+struct notify_data {
+ struct class *host_notify_class;
+ atomic_t device_count;
+};
+
+static struct notify_data host_notify;
+
+static ssize_t mode_show(
+ struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct host_notify_dev *ndev = (struct host_notify_dev *)
+ dev_get_drvdata(dev);
+ char *mode;
+
+ switch (ndev->mode) {
+ case NOTIFY_HOST_MODE:
+ mode = "HOST";
+ break;
+ case NOTIFY_PERIPHERAL_MODE:
+ mode = "PERIPHERAL";
+ break;
+ case NOTIFY_TEST_MODE:
+ mode = "TEST";
+ break;
+ case NOTIFY_NONE_MODE:
+ default:
+ mode = "NONE";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", mode);
+}
+
+static ssize_t mode_store(
+ struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct host_notify_dev *ndev = (struct host_notify_dev *)
+ dev_get_drvdata(dev);
+
+ char *mode;
+ size_t ret = -ENOMEM;
+
+ mode = kzalloc(size+1, GFP_KERNEL);
+ if (!mode)
+ goto error;
+
+ sscanf(buf, "%s", mode);
+
+ if (ndev->set_mode) {
+ if (!strcmp(mode, "HOST"))
+ ndev->set_mode(NOTIFY_SET_ON);
+ else if (!strcmp(mode, "NONE"))
+ ndev->set_mode(NOTIFY_SET_OFF);
+ printk(KERN_INFO "host_notify: set mode %s\n", mode);
+ }
+ ret = size;
+ kfree(mode);
+error:
+ return ret;
+}
+
+static ssize_t booster_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct host_notify_dev *ndev = (struct host_notify_dev *)
+ dev_get_drvdata(dev);
+ char *booster;
+
+ switch (ndev->booster) {
+ case NOTIFY_POWER_ON:
+ booster = "ON";
+ break;
+ case NOTIFY_POWER_OFF:
+ default:
+ booster = "OFF";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", booster);
+}
+
+static ssize_t booster_store(
+ struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct host_notify_dev *ndev = (struct host_notify_dev *)
+ dev_get_drvdata(dev);
+
+ char *booster;
+ size_t ret = -ENOMEM;
+
+ booster = kzalloc(size+1, GFP_KERNEL);
+ if (!booster)
+ goto error;
+
+ sscanf(buf, "%s", booster);
+
+ if (ndev->set_booster) {
+ if (!strcmp(booster, "ON")) {
+ ndev->set_booster(NOTIFY_SET_ON);
+ ndev->mode = NOTIFY_TEST_MODE;
+ } else if (!strcmp(booster, "OFF")) {
+ ndev->set_booster(NOTIFY_SET_OFF);
+ ndev->mode = NOTIFY_NONE_MODE;
+ }
+ printk(KERN_INFO "host_notify: set booster %s\n", booster);
+ }
+ ret = size;
+ kfree(booster);
+error:
+ return ret;
+}
+
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR | S_IWGRP, mode_show, mode_store);
+static DEVICE_ATTR(booster, S_IRUGO | S_IWUSR | S_IWGRP,
+ booster_show, booster_store);
+
+static struct attribute *host_notify_attrs[] = {
+ &dev_attr_mode.attr,
+ &dev_attr_booster.attr,
+ NULL,
+};
+
+static struct attribute_group host_notify_attr_grp = {
+ .attrs = host_notify_attrs,
+};
+
+void host_state_notify(struct host_notify_dev *ndev, int state)
+{
+ printk(KERN_INFO "host_notify: ndev name=%s: from state=%d -> to state=%d\n",
+ ndev->name, ndev->state, state);
+ if (ndev->state != state) {
+ ndev->state = state;
+ kobject_uevent(&ndev->dev->kobj, KOBJ_CHANGE);
+ }
+}
+EXPORT_SYMBOL_GPL(host_state_notify);
+
+static int
+host_notify_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct host_notify_dev *ndev = (struct host_notify_dev *)
+ dev_get_drvdata(dev);
+ char *state;
+
+ if (!ndev) {
+ /* this happens when the device is first created */
+ return 0;
+ }
+ switch (ndev->state) {
+ case NOTIFY_HOST_ADD:
+ state = "ADD";
+ break;
+ case NOTIFY_HOST_REMOVE:
+ state = "REMOVE";
+ break;
+ case NOTIFY_HOST_OVERCURRENT:
+ state = "OVERCURRENT";
+ break;
+ case NOTIFY_HOST_LOWBATT:
+ state = "LOWBATT";
+ break;
+ case NOTIFY_HOST_UNKNOWN:
+ state = "UNKNOWN";
+ break;
+ case NOTIFY_HOST_NONE:
+ default:
+ return 0;
+ }
+ if (add_uevent_var(env, "DEVNAME=%s", ndev->dev->kobj.name))
+ return -ENOMEM;
+ if (add_uevent_var(env, "STATE=%s", state))
+ return -ENOMEM;
+ return 0;
+}
+
+static int create_notify_class(void)
+{
+ if (!host_notify.host_notify_class) {
+ host_notify.host_notify_class
+ = class_create(THIS_MODULE, "host_notify");
+ if (IS_ERR(host_notify.host_notify_class))
+ return PTR_ERR(host_notify.host_notify_class);
+ atomic_set(&host_notify.device_count, 0);
+ host_notify.host_notify_class->dev_uevent = host_notify_uevent;
+ }
+
+ return 0;
+}
+
+int host_notify_dev_register(struct host_notify_dev *ndev)
+{
+ int ret;
+
+ if (!host_notify.host_notify_class) {
+ ret = create_notify_class();
+ if (ret < 0)
+ return ret;
+ }
+
+ ndev->index = atomic_inc_return(&host_notify.device_count);
+ ndev->dev = device_create(host_notify.host_notify_class, NULL,
+ MKDEV(0, ndev->index), NULL, ndev->name);
+ if (IS_ERR(ndev->dev))
+ return PTR_ERR(ndev->dev);
+
+ ret = sysfs_create_group(&ndev->dev->kobj, &host_notify_attr_grp);
+ if (ret < 0) {
+ device_destroy(host_notify.host_notify_class,
+ MKDEV(0, ndev->index));
+ return ret;
+ }
+
+ dev_set_drvdata(ndev->dev, ndev);
+ ndev->state = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(host_notify_dev_register);
+
+void host_notify_dev_unregister(struct host_notify_dev *ndev)
+{
+ ndev->state = NOTIFY_HOST_NONE;
+ sysfs_remove_group(&ndev->dev->kobj, &host_notify_attr_grp);
+ device_destroy(host_notify.host_notify_class, MKDEV(0, ndev->index));
+ dev_set_drvdata(ndev->dev, NULL);
+}
+EXPORT_SYMBOL_GPL(host_notify_dev_unregister);
+
+static int __init notify_class_init(void)
+{
+ return create_notify_class();
+}
+
+static void __exit notify_class_exit(void)
+{
+ class_destroy(host_notify.host_notify_class);
+}
+
+module_init(notify_class_init);
+module_exit(notify_class_exit);
+
+MODULE_AUTHOR("Dongrak Shin <dongrak.shin@samsung.com>");
+MODULE_DESCRIPTION("Usb host notify driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/host_notify.h b/include/linux/host_notify.h
new file mode 100755
index 0000000..1ea0cd3
--- /dev/null
+++ b/include/linux/host_notify.h
@@ -0,0 +1,53 @@
+/*
+ * Host notify class driver
+ *
+ * Copyright (C) 2011 Samsung, Inc.
+ * Author: Dongrak Shin <dongrak.shin@samsung.com>
+ *
+*/
+
+#ifndef __LINUX_HOST_NOTIFY_H__
+#define __LINUX_HOST_NOTIFY_H__
+
+enum host_uevent_state {
+ NOTIFY_HOST_NONE,
+ NOTIFY_HOST_ADD,
+ NOTIFY_HOST_REMOVE,
+ NOTIFY_HOST_OVERCURRENT,
+ NOTIFY_HOST_LOWBATT,
+ NOTIFY_HOST_UNKNOWN,
+};
+
+enum otg_mode {
+ NOTIFY_NONE_MODE,
+ NOTIFY_HOST_MODE,
+ NOTIFY_PERIPHERAL_MODE,
+ NOTIFY_TEST_MODE,
+};
+
+enum booster_power{
+ NOTIFY_POWER_OFF,
+ NOTIFY_POWER_ON,
+};
+
+enum set_command{
+ NOTIFY_SET_OFF,
+ NOTIFY_SET_ON,
+};
+
+struct host_notify_dev {
+ const char *name;
+ struct device *dev;
+ int index;
+ int state;
+ int mode;
+ int booster;
+ void (*set_mode)(int);
+ void (*set_booster)(int);
+};
+
+extern void host_state_notify(struct host_notify_dev *ndev, int state);
+extern int host_notify_dev_register(struct host_notify_dev *ndev);
+extern void host_notify_dev_unregister(struct host_notify_dev *ndev);
+
+#endif /* __LINUX_HOST_NOTIFY_H__ */
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 32ba8c5..f54e9ef 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -22,6 +22,7 @@
#ifdef __KERNEL__
#include <linux/rwsem.h>
+#include <linux/host_notify.h>
#define MAX_TOPO_LEVEL 6
@@ -175,6 +176,14 @@ struct usb_hcd {
* input size of periodic table to an interrupt scheduler.
* (ohci 32, uhci 1024, ehci 256/512/1024).
*/
+#ifdef CONFIG_USB_HOST_NOTIFY
+ struct host_notify_dev ndev;
+ int host_notify;
+#endif
+#ifdef CONFIG_USB_SEC_WHITELIST
+ int sec_whlist_table_num;
+#endif
+
/* The HC driver's private data is stored at the end of
* this structure.