aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/shost
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/shost')
-rw-r--r--drivers/usb/host/shost/Makefile9
-rw-r--r--drivers/usb/host/shost/shost.h56
-rw-r--r--drivers/usb/host/shost/shost_const.h140
-rw-r--r--drivers/usb/host/shost/shost_debug.h78
-rw-r--r--drivers/usb/host/shost/shost_driver.c450
-rw-r--r--drivers/usb/host/shost/shost_errorcode.h81
-rw-r--r--drivers/usb/host/shost/shost_hcd.c912
-rw-r--r--drivers/usb/host/shost/shost_kal.h361
-rw-r--r--drivers/usb/host/shost/shost_list.h188
-rw-r--r--drivers/usb/host/shost/shost_mem.h155
-rw-r--r--drivers/usb/host/shost/shost_oci.c809
-rw-r--r--drivers/usb/host/shost/shost_oci.h50
-rw-r--r--drivers/usb/host/shost/shost_readyq.c240
-rw-r--r--drivers/usb/host/shost/shost_regs.h747
-rw-r--r--drivers/usb/host/shost/shost_roothub.c579
-rw-r--r--drivers/usb/host/shost/shost_scheduler.c420
-rw-r--r--drivers/usb/host/shost/shost_scheduler.h56
-rw-r--r--drivers/usb/host/shost/shost_schedulerlib.c426
-rw-r--r--drivers/usb/host/shost/shost_struct.h189
-rw-r--r--drivers/usb/host/shost/shost_transfer.c1025
-rw-r--r--drivers/usb/host/shost/shost_transfer.h52
-rw-r--r--drivers/usb/host/shost/shost_transferchecker.c503
-rw-r--r--drivers/usb/host/shost/shost_transferchecker_bulk.c671
-rw-r--r--drivers/usb/host/shost/shost_transferchecker_control.c777
-rw-r--r--drivers/usb/host/shost/shost_transferchecker_interrupt.c617
25 files changed, 9591 insertions, 0 deletions
diff --git a/drivers/usb/host/shost/Makefile b/drivers/usb/host/shost/Makefile
new file mode 100644
index 0000000..c891a18
--- /dev/null
+++ b/drivers/usb/host/shost/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for USB OTG Host Controller Drivers
+#
+
+obj-$(CONFIG_USB_S3C_OTG_HOST) += shost_hcd.o
+
+shost_hcd-objs += shost_driver.o
+shost_hcd-objs += shost_scheduler.o
+shost_hcd-objs += shost_transferchecker.o
diff --git a/drivers/usb/host/shost/shost.h b/drivers/usb/host/shost/shost.h
new file mode 100644
index 0000000..6774667
--- /dev/null
+++ b/drivers/usb/host/shost/shost.h
@@ -0,0 +1,56 @@
+#ifndef _SHOST_H
+#define _SHOST_H
+
+
+#include <linux/usb.h>
+#include <linux/errno.h>
+#include <linux/wakelock.h>
+#include <plat/s5p-otghost.h>
+
+
+#include "shost_debug.h"
+#include "shost_list.h"
+
+#include "shost_const.h"
+#include "shost_errorcode.h"
+#include "shost_regs.h"
+#include "shost_struct.h"
+
+#include "shost_kal.h"
+#include "shost_mem.h"
+#include "shost_oci.h"
+
+#include "shost_scheduler.h"
+#include "shost_transfer.h"
+
+/* #ifdef CONFIG_MACH_C1 GB */
+#if 0
+ #include <plat/regs-otg.h>
+ #define OTG_CLOCK S5P_CLKGATE_IP_FSYS
+ #define OTG_PHY_CONTROL S5P_USBOTG_PHY_CONTROL
+ #define OTG_PHYPWR S3C_USBOTG_PHYPWR
+ #define OTG_PHYCLK S3C_USBOTG_PHYCLK
+ #define OTG_RSTCON S3C_USBOTG_RSTCON
+ #define S3C_VA_HSOTG S3C_VA_OTG
+#else /* ICS */
+ #include <mach/regs-usb-phy.h>
+ #define OTG_CLOCK EXYNOS4_CLKGATE_IP_FSYS
+ #define OTG_PHY_CONTROL S5P_USBOTG_PHY_CONTROL
+ #define OTG_PHYPWR EXYNOS4_PHYPWR
+ #define OTG_PHYCLK EXYNOS4_PHYCLK
+ #define OTG_RSTCON EXYNOS4_RSTCON
+ #define IRQ_OTG IRQ_USB_HSOTG
+ #define S3C_VA_OTG S3C_VA_HSOTG
+#endif
+
+/* transferchecker-common.c
+ * called by isr
+ */
+void do_transfer_checker(struct sec_otghost *otghost);
+void otg_print_registers(void);
+
+#ifdef CONFIG_USB_HOST_NOTIFY
+#undef CONFIG_USB_HOST_NOTIFY
+#endif
+
+#endif
diff --git a/drivers/usb/host/shost/shost_const.h b/drivers/usb/host/shost/shost_const.h
new file mode 100644
index 0000000..8ba1494
--- /dev/null
+++ b/drivers/usb/host/shost/shost_const.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * (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_
+
+/**
+ * @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.. */
+#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
+
+
+#endif
+
+
diff --git a/drivers/usb/host/shost/shost_debug.h b/drivers/usb/host/shost/shost_debug.h
new file mode 100644
index 0000000..dd67b98
--- /dev/null
+++ b/drivers/usb/host/shost/shost_debug.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * (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 _SHOST_DEBUG_H
+#define _SHOST_DEBUG_H
+
+#define OTG_DEBUG
+
+#ifdef OTG_DEBUG
+
+#define OTG_DBG_OTGHCDI_DRIVER 1
+#define OTG_DBG_OTGHCDI_HCD 0
+#define OTG_DBG_OTGHCDI_KAL 0
+#define OTG_DBG_OTGHCDI_LIST 0
+#define OTG_DBG_OTGHCDI_MEM 0
+#define OTG_DBG_OTGHCDI_IRQ 0
+
+#define OTG_DBG_TRANSFER 0
+#define OTG_DBG_SCHEDULE 0
+#define OTG_DBG_SCHEDULE_ED 0
+#define OTG_DBG_OCI 0
+#define OTG_DBG_DONETRASF 0
+#define OTG_DBG_ISR 0
+#define OTG_DBG_ROOTHUB 0
+
+
+#include <linux/kernel.h> /* for printk */
+
+#define otg_err(is_active, msg, args...) \
+ do { \
+ if ((is_active) == true) {\
+ pr_err("OTG_ERR %s(%d): " msg, \
+ __func__ , __LINE__, ##args); \
+ } \
+ } while (0)
+
+#define otg_dbg(is_active, msg, args...) \
+ do { \
+ if ((is_active) == true) { \
+ pr_info("OTG %s(%d): " msg, \
+ __func__, __LINE__, ##args); \
+ } \
+ } while (0)
+
+#else /* OTG_DEBUG */
+
+#define otg_err(is_active, msg...) do {} while (0)
+#define otg_dbg(is_active, msg...) do {} while (0)
+
+#endif
+
+
+#endif /* SHOST_DEBUG_H */
diff --git a/drivers/usb/host/shost/shost_driver.c b/drivers/usb/host/shost/shost_driver.c
new file mode 100644
index 0000000..f10136c
--- /dev/null
+++ b/drivers/usb/host/shost/shost_driver.c
@@ -0,0 +1,450 @@
+/****************************************************************************
+ * (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.
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Creating the initial version of this code
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Optimizing for performance
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Modifying for successful rmmod & disconnecting
+ * @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 <linux/module.h>
+#include <linux/init.h>
+
+#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 "shost.h"
+
+
+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);
+}
+
+
+#include "shost_oci.c"
+#include "shost_transfer.c"
+#include "shost_roothub.c"
+#include "shost_hcd.c"
+
+volatile u8 *g_pUDCBase;
+struct usb_hcd *g_pUsbHcd;
+
+static const char gHcdName[] = "EMSP_OTG_HCD";
+static struct platform_device *g_pdev;
+
+
+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) {
+ pr_info("otg power off - don't turn off the power\n");
+ hdata->set_pwr_cb(0);
+#ifdef CONFIG_USB_HOST_NOTIFY
+ if (hdata->host_notify_cb)
+ hdata->host_notify_cb(NOTIFY_HOST_OVERCURRENT);
+#endif
+ } else {
+ otg_err(true, "invalid otghost data\n");
+ }
+}
+
+static int s5pc110_mapping_resources(struct platform_device *pdev)
+{
+ 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");
+ return -EBUSY;
+ }
+
+ pr_info("otg rsrc_start %llu, ren %llu\n",
+ g_pUsbHcd->rsrc_start,
+ g_pUsbHcd->rsrc_len);
+
+ pr_info("otg regs : %p\n", S3C_VA_HSOTG);
+
+ /* Physical address => Virtual address */
+ g_pUsbHcd->regs = S3C_VA_HSOTG;
+ g_pUDCBase = (u8 *)g_pUsbHcd->regs;
+
+ return 0;
+}
+
+static void s5pc110_prevent_suspend(struct usb_device *rhdev)
+{
+ dev_info(&rhdev->dev, "otg host do not enter suspend.\n");
+ pm_runtime_disable(&rhdev->dev);
+}
+
+static int s5pc110_start_otg(u32 regs)
+{
+ int ret_val = 0;
+ u32 reg_val = 0;
+ struct platform_device *pdev = g_pdev;
+ struct sec_otghost *otghost = NULL;
+ struct sec_otghost_data *otg_data = dev_get_platdata(&pdev->dev);
+
+ pr_info("%s + regs=0x%x\n", __func__, regs);
+
+ /* 1. hcd */
+ g_pUsbHcd = usb_create_hcd(&s5pc110_otg_hc_driver, &pdev->dev,
+ "s3cotg");/*pdev->dev.bus_id*/
+ if (g_pUsbHcd == NULL) {
+ otg_err(1, "failed to usb_create_hcd\n");
+ return -ENOMEM;
+ }
+ g_pUsbHcd->self.otg_port = 1;
+
+ /* sec_otghost */
+ 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;
+
+ /* 2. wake lock */
+ wake_lock_init(&otghost->wake_lock, WAKE_LOCK_SUSPEND, "usb_otg");
+ wake_lock(&otghost->wake_lock);
+
+ /* base address */
+ if (!regs) {
+ pr_info("otg mapping hcd resource\n");
+ ret_val = s5pc110_mapping_resources(pdev);
+ if (ret_val)
+ goto err_out_create_hcd;
+ } else
+ g_pUDCBase = (u8 *)regs;
+
+ pr_info("otg g_pUDCBase 0x%p\n", g_pUDCBase);
+
+ /* 3. workqueue */
+ INIT_WORK(&otghost->work, otg_power_work);
+ otghost->wq = create_singlethread_workqueue("sec_otghostd");
+
+ /* 4. phy */
+ 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);
+ pr_info("otg reg 0x40 = %x\n", reg_val);
+ 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_SEC_WHITELIST
+ if (otg_data->sec_whlist_table_num)
+ g_pUsbHcd->sec_whlist_table_num =
+ otg_data->sec_whlist_table_num;
+#endif
+
+ /* 5. hcd
+ * 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) {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "Failed to add hcd driver\n");
+ goto err_out_create_hcd_init;
+ }
+
+ s5pc110_prevent_suspend(g_pUsbHcd->self.root_hub);
+
+ 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(); */
+ pr_info("%s -\n", __func__);
+
+ return USB_ERR_SUCCESS;
+
+err_out_create_hcd_init:
+ otg_hcd_deinit_modules(otghost);
+ if (!regs)
+ release_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len);
+
+err_out_create_hcd:
+ usb_put_hcd(g_pUsbHcd);
+
+ return ret_val;
+}
+
+static int s5pc110_stop_otg(void)
+{
+ struct sec_otghost *otghost = NULL;
+ struct sec_otghost_data *otgdata = NULL;
+
+ pr_info("%s +\n", __func__);
+
+ otg_dbg(OTG_DBG_OTGHCDI_DRIVER, "s5pc110_stop_otg\n");
+
+ otghost = hcd_to_sec_otghost(g_pUsbHcd);
+
+ otg_hcd_deinit_modules(otghost);
+
+ /* 5. hcd */
+ usb_remove_hcd(g_pUsbHcd);
+#if 1
+ if (g_pUDCBase == S3C_VA_HSOTG) {
+ pr_info("otg release_mem_region\n");
+ release_mem_region(g_pUsbHcd->rsrc_start, g_pUsbHcd->rsrc_len);
+ }
+#endif
+ /* 4. phy */
+ otgdata = otghost->otg_data;
+ if (otgdata && otgdata->phy_exit && otgdata->pdev) {
+ pr_info("otg phy_off\n");
+ otgdata->phy_exit(0);
+ clk_disable(otgdata->clk);
+ }
+
+ /* 3. workqueue */
+ destroy_workqueue(otghost->wq);
+
+ /* 2. wake lock */
+ wake_unlock(&otghost->wake_lock);
+ wake_lock_destroy(&otghost->wake_lock);
+
+ /* 1. hcd */
+ usb_put_hcd(g_pUsbHcd);
+
+ pr_info("%s -\n", __func__);
+
+ return 0;
+}
+
+/**
+ * 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
+ * USB_ERR_FAIL : If fail
+ * @remark
+ * it allocates resources of it and call other modules' init function.
+ * then call usb_create_hcd, usb_add_hcd, s5pc110_otghcd_start functions
+ */
+
+static int s5pc110_otg_drv_probe(struct platform_device *pdev)
+{
+ struct sec_otghost_data *otg_data = dev_get_platdata(&pdev->dev);
+ g_pdev = pdev;
+
+ otg_data->clk = clk_get(&pdev->dev, "usbotg");
+
+ if (IS_ERR(otg_data->clk)) {
+ otg_err(OTG_DBG_OTGHCDI_DRIVER,
+ "Failed to get clock\n");
+ return PTR_RET(otg_data->clk);
+ }
+
+ pr_info("otg host_probe start %p\n", s5pc110_start_otg);
+ otg_data->start = s5pc110_start_otg;
+ otg_data->stop = s5pc110_stop_otg;
+ otg_data->pdev = pdev;
+
+ return 0;
+}
+
+
+/**
+ * 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
+ * USB_ERR_FAIL : If fail
+ * @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 *pdev)
+{
+ struct sec_otghost_data *otg_data = dev_get_platdata(&pdev->dev);
+
+ clk_put(otg_data->clk);
+ 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 */
+
+ pr_info("otg clock = %s\n",
+ (readl(OTG_CLOCK) & (1<<13)) ? "ON" : "OFF");
+ pr_info("otg USB_CONTROL = 0x%x.\n", readl(OTG_PHY_CONTROL));
+ pr_info("otg UPHYPWR = 0x%x.\n", readl(OTG_PHYPWR));
+ pr_info("otg UPHYCLK = 0x%x.\n", readl(OTG_PHYCLK));
+ pr_info("otg URSTCON = 0x%x.\n", readl(OTG_RSTCON));
+
+ /* OTG LINK Core registers (Core Global Registers) */
+ pr_info("otg GOTGCTL = 0x%x.\n", read_reg_32(GOTGCTL));
+ pr_info("otg GOTGINT = 0x%x.\n", read_reg_32(GOTGINT));
+ pr_info("otg GAHBCFG = 0x%x.\n", read_reg_32(GAHBCFG));
+ pr_info("otg GUSBCFG = 0x%x.\n", read_reg_32(GUSBCFG));
+ pr_info("otg GINTSTS = 0x%x.\n", read_reg_32(GINTSTS));
+ pr_info("otg GINTMSK = 0x%x.\n", read_reg_32(GINTMSK));
+
+ /* Host Mode Registers */
+ pr_info("otg HCFG = 0x%x.\n", read_reg_32(HCFG));
+ pr_info("otg HPRT = 0x%x.\n", read_reg_32(HPRT));
+ pr_info("otg HFIR = 0x%x.\n", read_reg_32(HFIR));
+
+ /* Synopsys ID */
+ pr_info("otg GSNPSID = 0x%x.\n", read_reg_32(GSNPSID));
+
+ /* HWCFG */
+ pr_info("otg GHWCFG1 = 0x%x.\n", read_reg_32(GHWCFG1));
+ pr_info("otg GHWCFG2 = 0x%x.\n", read_reg_32(GHWCFG2));
+ pr_info("otg GHWCFG3 = 0x%x.\n", read_reg_32(GHWCFG3));
+ pr_info("otg GHWCFG4 = 0x%x.\n", read_reg_32(GHWCFG4));
+
+ /* PCGCCTL */
+ pr_info("otg PCGCCTL = 0x%x.\n", read_reg_32(PCGCCTL));
+}
+
+late_initcall(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/shost/shost_errorcode.h b/drivers/usb/host/shost/shost_errorcode.h
new file mode 100644
index 0000000..f52b606
--- /dev/null
+++ b/drivers/usb/host/shost/shost_errorcode.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * (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 _ERRORCODE_H
+#define _ERRORCODE_H
+
+
+/* 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.
+ ************************************************/
+
+#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)
+
+
+#endif
+
diff --git a/drivers/usb/host/shost/shost_hcd.c b/drivers/usb/host/shost/shost_hcd.c
new file mode 100644
index 0000000..f06b237
--- /dev/null
+++ b/drivers/usb/host/shost/shost_hcd.c
@@ -0,0 +1,912 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-hcd.c
+ * @brief implementation of structure hc_drive
+ * @version
+ * -# Jun 11,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Creating the initial version of this code
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Optimizing for performance
+ * -# Aug 18,2008 v1.3 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Modifying for successful rmmod & disconnecting
+ * @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
+ ****************************************************************************/
+
+/*Internal function of isr */
+static 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);
+}
+
+/**
+ * void otg_handle_interrupt(void)
+ *
+ * @brief Main interrupt processing routine
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+
+static 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);
+}
+
+
+
+/**
+ * otg_hcd_init_modules(struct sec_otghost *otghost)
+ *
+ * @brief call other modules' init functions
+ *
+ * @return PASS : If success
+ * FAIL : If fail
+ */
+static int otg_hcd_init_modules(struct sec_otghost *otghost)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "otg_hcd_init_modules\n");
+
+ spin_lock_init(&otghost->lock);
+
+ init_transfer();
+ init_scheduler();
+ oci_init(otghost);
+
+ return USB_ERR_SUCCESS;
+};
+
+/**
+ * void otg_hcd_deinit_modules(struct sec_otghost *otghost)
+ *
+ * @brief call other modules' de-init functions
+ *
+ * @return PASS : If success
+ * FAIL : If fail
+ */
+static 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_irqsave(&otghost->lock, spin_lock_flag);
+
+ deinit_transfer(otghost);
+
+ spin_unlock_irqrestore(&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
+ */
+static irqreturn_t s5pc110_otghcd_irq(struct usb_hcd *hcd)
+{
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ otg_dbg(OTG_DBG_OTGHCDI_IRQ, "s5pc110_otghcd_irq\n");
+
+ spin_lock(&otghost->lock);
+ otg_handle_interrupt(hcd);
+ spin_unlock(&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
+ * USB_ERR_FAIL : If call fail
+ */
+static 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;
+ }
+
+/* #ifdef CONFIG_MACH_C1 */
+#if 0
+ usb_hcd_p->poll_rh = 1;
+#else
+ set_bit(HCD_FLAG_POLL_RH, &usb_hcd_p->flags);
+#endif
+ usb_hcd_p->uses_new_polling = 1;
+ usb_hcd_p->has_tt = 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
+ *
+ */
+static 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_irqsave(&otghost->lock, spin_lock_flag);
+
+ oci_stop();
+
+ root_hub_feature(hcd, 0, ClearPortFeature, USB_PORT_FEAT_POWER, NULL);
+
+ spin_unlock_irqrestore(&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
+ *
+ */
+static 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_irqsave(&otghost->lock, spin_lock_flag);
+
+ oci_stop();
+ root_hub_feature(usb_hcd_p, 0, ClearPortFeature,
+ USB_PORT_FEAT_POWER, NULL);
+
+ spin_unlock_irqrestore(&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
+ */
+static int s5pc110_otghcd_get_frame_number(struct usb_hcd *hcd)
+{
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+ unsigned long spin_lock_flag = 0;
+ int ret = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_get_frame_number\n");
+
+ spin_lock_irqsave(&otghost->lock, spin_lock_flag);
+ ret = oci_get_frame_num();
+ spin_unlock_irqrestore(&otghost->lock, spin_lock_flag);
+
+ return ret;
+}
+
+int compare_ed(struct sec_otghost *otghost, void *hcpriv, struct urb *urb)
+{
+ struct ed *ped = NULL;
+ int ret = 0;
+ u32 update = 0;
+
+ if (!hcpriv)
+ return ret;
+
+ ped = (struct ed *)hcpriv;
+
+ if (ped->ed_desc.device_addr != usb_pipedevice(urb->pipe)) {
+ ped->ed_desc.device_addr = usb_pipedevice(urb->pipe);
+ update |= 1 << 1;
+ }
+
+ if (ped->ed_desc.endpoint_num != usb_pipeendpoint(urb->pipe)) {
+ ped->ed_desc.endpoint_num = usb_pipeendpoint(urb->pipe);
+ update |= 1 << 2;
+ }
+
+ if (ped->ed_desc.is_ep_in != (usb_pipein(urb->pipe) ? 1 : 0)) {
+ ped->ed_desc.is_ep_in = usb_pipein(urb->pipe) ? 1 : 0;
+ update |= 1 << 3;
+ }
+
+ if (ped->ed_desc.max_packet_size !=
+ usb_maxpacket(urb->dev, urb->pipe,
+ !(usb_pipein(urb->pipe)))) {
+ update |= 1 << 4;
+ }
+
+ if (update)
+ otg_dbg(1, "update ed %d (0x%x)\n", update, update);
+
+ 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
+ * USB_ERR_FAIL : If call fail
+ */
+static 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;
+
+ struct ed *target_ed = NULL;
+ struct isoch_packet_desc *new_isoch_packet_desc = NULL;
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+
+ unsigned long spin_lock_flag = 0;
+
+ if (!otghost && !otghost->port_flag.b.port_connect_status) {
+ otg_err(1, "Error : %s is zero\n", otghost ?
+ "Port status" : "otghost");
+ return USB_ERR_NOIO;
+ }
+
+ spin_lock_irqsave(&otghost->lock, spin_lock_flag);
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "enqueue\n");
+ if (compare_ed(otghost, urb->ep->hcpriv, urb)) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "compare ed error\n");
+ pr_info("otg compare ed error\n");
+ spin_unlock_irqrestore(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ /* 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_irqrestore(&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_irqrestore(&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_irqrestore(&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_irqrestore(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ urb->ep->hcpriv = (void *)(target_ed);
+
+ } else { /* if (!(ep->hcpriv)) */
+
+ dev_addr = usb_pipedevice(urb->pipe);
+ if (((struct ed *)(urb->ep->hcpriv))->ed_desc.device_addr
+ != dev_addr)
+ ((struct ed *)urb->ep->hcpriv)->ed_desc.device_addr
+ = dev_addr;
+ }
+
+ target_ed = (struct ed *)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_irqrestore(&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_irqrestore(&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_irqrestore(&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_irqrestore(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+ urb->hcpriv = (void *)return_td_addr;
+
+ spin_unlock_irqrestore(&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
+ * USB_ERR_FAIL : If call fail
+ */
+static 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;
+ struct td *cancel_td = (struct td *)_urb->hcpriv;
+
+ spin_lock_irqsave(&otghost->lock, spin_lock_flag);
+
+ /* otg_dbg(OTG_DBG_OTGHCDI_HCD, "dequeue\n"); */
+
+ if (cancel_td == NULL) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "cancel_td is NULL\n");
+ spin_unlock_irqrestore(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "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_irqrestore(&otghost->lock, spin_lock_flag);
+ return ret_val;
+ }
+
+ if (!HC_IS_RUNNING(_hcd->state)) {
+ otg_err(OTG_DBG_OTGHCDI_HCD, "!HC_IS_RUNNING(hcd->state)\n");
+ spin_unlock_irqrestore(&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_irqrestore(&otghost->lock, spin_lock_flag);
+ return USB_ERR_FAIL;
+ }
+
+/* otg_usbcore_giveback(cancel_td); */
+ spin_unlock_irqrestore(&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
+ */
+static void s5pc110_otghcd_endpoint_disable(
+ struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+ unsigned long spin_lock_flag = 0;
+ int ret_val = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_endpoint_disable\n");
+
+ if (!((struct ed *)ep->hcpriv))
+ return;
+
+ spin_lock_irqsave(&otghost->lock, spin_lock_flag);
+ ret_val = delete_ed(otghost, (struct ed *)ep->hcpriv);
+ spin_unlock_irqrestore(&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
+ */
+static 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_irqsave(&otghost->lock, spin_lock_flag);
+ ret_val = get_otg_port_status(_hcd, OTG_PORT_NUMBER, _buf);
+ spin_unlock_irqrestore(&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
+ */
+static 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_irqsave(&otghost->lock, spin_lock_flag);
+
+ ret_val = root_hub_feature(hcd, OTG_PORT_NUMBER,
+ typeReq, value, (void *)buf_p);
+
+ spin_unlock_irqrestore(&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
+ */
+static 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_irqsave(&otghost->lock, spin_lock_flag);
+ bus_suspend();
+ spin_unlock_irqrestore(&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
+ */
+static int s5pc110_otghcd_bus_resume(struct usb_hcd *hcd)
+{
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+ unsigned long spin_lock_flag = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_bus_resume\n");
+
+ spin_lock_irqsave(&otghost->lock, spin_lock_flag);
+
+ if (bus_resume(otghost) != USB_ERR_SUCCESS)
+ return USB_ERR_FAIL;
+
+ spin_unlock_irqrestore(&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
+ * ret_val : If call fail
+ */
+static int s5pc110_otghcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
+{
+ struct sec_otghost *otghost = hcd_to_sec_otghost(hcd);
+ unsigned long spin_lock_flag = 0;
+ int ret_val = 0;
+
+ otg_dbg(OTG_DBG_OTGHCDI_HCD, "s5pc110_otghcd_start_port_reset\n");
+
+ spin_lock_irqsave(&otghost->lock, spin_lock_flag);
+ ret_val = reset_and_enable_port(hcd, OTG_PORT_NUMBER);
+ spin_unlock_irqrestore(&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;
+}
+
+
+/**
+ * @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,
+};
+
+
diff --git a/drivers/usb/host/shost/shost_kal.h b/drivers/usb/host/shost/shost_kal.h
new file mode 100644
index 0000000..1a213a1
--- /dev/null
+++ b/drivers/usb/host/shost/shost_kal.h
@@ -0,0 +1,361 @@
+/****************************************************************************
+ * (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 _SHOST_KAL_H_
+#define _SHOST_KAL_H_
+
+#include <linux/io.h> /* for readl, writel */
+#include <linux/usb/ch9.h>
+#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;
+
+#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(struct ed *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(struct ed *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(struct td td_p)
+ *
+ * @brief give-back a td as urb
+ *
+ * @param [in] td_p : pointer of struct td to give back
+ *
+ * @return void \n
+ */
+static inline void
+otg_usbcore_giveback(struct td *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\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\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));
+}
+
+#endif /* _S3C_OTG_HCDI_KAL_H_ */
+
diff --git a/drivers/usb/host/shost/shost_list.h b/drivers/usb/host/shost/shost_list.h
new file mode 100644
index 0000000..7283fb7
--- /dev/null
+++ b/drivers/usb/host/shost/shost_list.h
@@ -0,0 +1,188 @@
+/****************************************************************************
+ * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
+ *
+ * @file s3c-otg-hcdi-list.h
+ * @brief list functions for otg
+ * @version
+ * -# Jun 9,2008 v1.0 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Creating the initial version of this code
+ * -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com)
+ * : Optimizing for performance
+ * @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_
+
+#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 *n, otg_list_head *list)
+ *
+ * @brief push a list node into the next of head
+ *
+ * @param [in] n : 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 *n, otg_list_head *list)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_push_next\n");
+ list_add(n, list);
+}
+
+/**
+ * void otg_list_push_prev(otg_list_head *n, otg_list_head *list)
+ *
+ * @brief push a list node into the previous of head
+ *
+ * @param [in] n : 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 *n, otg_list_head *list)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_push_prev\n");
+ list_add_tail(n, list);
+}
+
+/**
+ * void otg_list_pop(otg_list_head *list_entity_p)
+ *
+ * @brief pop a list node
+ *
+ * @param [in] n : 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");
+
+ if (list_entity_p->prev && list_entity_p->next)
+ list_del(list_entity_p);
+ else
+ pr_info("usb: otg_list_pop error\n");
+}
+
+/**
+ * void otg_list_move_next(otg_list_head *node_p, otg_list_head *list)
+ *
+ * @brief move a list to next of head
+ *
+ * @param [in] n : 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)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_move_next\n");
+ list_move(node_p, list);
+}
+
+/**
+ * void otg_list_move_prev(otg_list_head *node_p, otg_list_head *list)
+ *
+ * @brief move a list to previous of head
+ *
+ * @param [in] n : 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)
+{
+ otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_move_prev\n");
+ list_move_tail(node_p, list);
+}
+
+/**
+ * bool otg_list_empty(otg_list_head *list)
+ *
+ * @brief check a list empty or not
+ *
+ * @param [in] list : node to check
+ *
+ * @return true : empty list \n
+ * false : not empty list
+ */
+static inline
+bool otg_list_empty(otg_list_head *list)
+{
+ /* otg_dbg(OTG_DBG_OTGHCDI_LIST, "otg_list_empty\n"); */
+ if (list_empty(list))
+ 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;
+}
+
+#endif /* _S3C_OTG_HCDI_LIST_H_ */
+
diff --git a/drivers/usb/host/shost/shost_mem.h b/drivers/usb/host/shost/shost_mem.h
new file mode 100644
index 0000000..ecbbed2
--- /dev/null
+++ b/drivers/usb/host/shost/shost_mem.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+ * (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_
+
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+/**
+ * @enum otg_mem_alloc_flag
+ *
+ * @brief enumeration for flag of memory allocation
+ */
+enum otg_mem_type {
+ USB_MEM_SYNC,
+ USB_MEM_ASYNC,
+ USB_MEM_DMA
+};
+
+/**
+ * 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 : enum otg_mem_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,
+ enum otg_mem_type 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 enum otg_mem_type\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;
+}
+
+
+#endif /* _S3C_OTG_HCDI_MEMORY_H_ */
diff --git a/drivers/usb/host/shost/shost_oci.c b/drivers/usb/host/shost/shost_oci.c
new file mode 100644
index 0000000..4f47055
--- /dev/null
+++ b/drivers/usb/host/shost/shost_oci.c
@@ -0,0 +1,809 @@
+/****************************************************************************
+ * (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
+ ****************************************************************************/
+
+
+static bool ch_enable[16];
+
+/* OCI Internal Functions */
+
+static 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);
+}
+
+static int oci_channel_alloc(u8 *ch_num)
+{
+ hcchar_t hcchar = {.d32 = 0};
+ u8 ch;
+
+ 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;
+}
+
+
+
+static 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);
+}
+
+static 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);
+}
+
+static 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();
+}
+
+static int oci_core_reset(void)
+{
+ grstctl_t greset = {.d32 = 0};
+ u32 count = 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_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
+ *
+ */
+static 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);
+
+ 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
+ *
+ */
+
+static 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_channel_init( u8 ch_num, struct stransfer *transfer)
+ *
+ * @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
+ *
+ */
+static int oci_channel_init(u8 ch_num, struct stransfer *transfer)
+{
+ 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), transfer->hc_reg.hc_int_msk.d32);
+
+ /* Program the HCSIZn register with the endpoint characteristics for */
+ hctsiz.b.xfersize = transfer->buf_size;
+ hctsiz.b.pktcnt = transfer->packet_cnt;
+
+ /* Program the HCCHARn register with the endpoint characteristics for */
+ hcchar.b.mps = transfer->ed_desc_p->max_packet_size;
+ hcchar.b.epnum = transfer->ed_desc_p->endpoint_num;
+ hcchar.b.epdir = transfer->ed_desc_p->is_ep_in;
+ hcchar.b.lspddev = (transfer->ed_desc_p->dev_speed == LOW_SPEED_OTG);
+ hcchar.b.eptype = transfer->ed_desc_p->endpoint_type;
+ hcchar.b.multicnt = transfer->ed_desc_p->mc;
+ hcchar.b.devaddr = transfer->ed_desc_p->device_addr;
+
+ if (transfer->ed_desc_p->endpoint_type == INT_TRANSFER ||
+ transfer->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 (transfer->ed_desc_p->endpoint_type == CONTROL_TRANSFER) {
+
+ struct td *td_p;
+ td_p = (struct td *)transfer->parent_td;
+
+ switch (td_p->standard_dev_req_info.conrol_transfer_stage) {
+
+ case SETUP_STAGE:
+ hctsiz.b.pid = transfer->ed_status_p->
+ control_data_toggle.setup;
+ hcchar.b.epdir = EP_OUT;
+ break;
+
+ case DATA_STAGE:
+ hctsiz.b.pid =
+ transfer->ed_status_p->control_data_toggle.data;
+ hcchar.b.epdir = transfer->ed_desc_p->is_ep_in;
+ break;
+
+ case STATUS_STAGE:
+ hctsiz.b.pid = transfer->ed_status_p->
+ control_data_toggle.status;
+
+ if (td_p->standard_dev_req_info.is_data_stage) {
+ hcchar.b.epdir =
+ ~(transfer->ed_desc_p->is_ep_in);
+ } else
+ hcchar.b.epdir = EP_IN;
+ break;
+ default:
+ break;
+ }
+
+ } else
+ hctsiz.b.pid = transfer->ed_status_p->data_toggle;
+
+ otg_dbg(OTG_DBG_OCI, "eptype %d, stage %d, dir %d\n",
+ transfer->ed_desc_p->endpoint_type,
+ ((struct td *)transfer->parent_td)->
+ standard_dev_req_info.conrol_transfer_stage,
+ hcchar.b.epdir);
+
+ hctsiz.b.dopng = transfer->ed_status_p->is_ping_enable;
+ write_reg_32(HCTSIZ(ch_num), hctsiz.d32);
+ transfer->ed_status_p->is_ping_enable = false;
+
+ /* Write DMA Address */
+ write_reg_32(HCDMA(ch_num), transfer->phy_addr);
+
+ /* Wrote HCCHAR Register */
+ write_reg_32(HCCHAR(ch_num), hcchar.d32);
+
+ return USB_ERR_SUCCESS;
+}
+
+static int oci_dev_init(void)
+{
+ otg_dbg(OTG_DBG_OCI, "oci_dev_init - do nothing.\n");
+ /* return USB_ERR_FAIL; */
+ return USB_ERR_SUCCESS;
+}
+
+static 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;
+}
+
+
+
+/**
+ * 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
+ *
+ */
+static 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
+ *
+ */
+static int oci_stop(void)
+{
+ 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;
+}
+
+
+static int oci_sys_init(struct sec_otghost *otghost)
+{
+ struct sec_otghost_data *pdata = otghost->otg_data;
+
+ if (pdata && pdata->phy_init && pdata->pdev) {
+ pr_info("otg phy_init\n");
+ clk_enable(pdata->clk);
+ pdata->phy_init(0);
+
+ writel(0, OTG_PHYPWR);
+ writel(0x87, OTG_PHYCLK);
+ } else
+ pr_info("otg phy_init failed\n");
+
+ return USB_ERR_SUCCESS;
+}
+
+/**
+ * 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
+ *
+ */
+static 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(otghost) == 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;
+}
+
+/***********************************************************************
+ * API
+ */
+
+/* also called by ischeduler.c */
+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;
+}
+
+/**
+ * oci_start_transfer(struct sec_otghost *otghost, struct stransfer *transfer)
+ *
+ * @brief start transfer by using transfer information to receive from scheduler
+ *
+ * @param [IN] *transfer - 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, struct stransfer *transfer)
+{
+ hcchar_t hcchar = {.d32 = 0};
+
+ otg_dbg(OTG_DBG_OCI, "oci_start_transfer\n");
+
+ if (transfer->alloc_chnum == CH_NONE) {
+
+ if (oci_channel_alloc(&(transfer->alloc_chnum))
+ != USB_ERR_SUCCESS) {
+
+ otg_dbg(OTG_DBG_OCI,
+ "Fail - Channel Allocation Error\n");
+ return CH_NONE;
+ }
+ }
+
+ oci_channel_init(transfer->alloc_chnum, transfer);
+
+ hcchar.b.chen = 1;
+ update_reg_32(HCCHAR(transfer->alloc_chnum), hcchar.d32);
+
+ return transfer->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);
+
+ 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;
+}
+
+/**
+ * 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);
+}
+
diff --git a/drivers/usb/host/shost/shost_oci.h b/drivers/usb/host/shost/shost_oci.h
new file mode 100644
index 0000000..8fa6bbb
--- /dev/null
+++ b/drivers/usb/host/shost/shost_oci.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * (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_
+
+
+#include <mach/map.h> /* virtual address*/
+
+extern void otg_host_phy_init(void);
+#include <mach/regs-clock.h>
+
+int oci_channel_dealloc(u8 ch_num);
+
+u8 oci_start_transfer(struct sec_otghost *otghost, struct stransfer *st_t);
+int oci_stop_transfer(struct sec_otghost *otghost, u8 ch_num);
+
+u32 oci_get_frame_num(void);
+u16 oci_get_frame_interval(void);
+void oci_set_frame_interval(u16 intervl);
+
+
+#endif /* _OCI_H_ */
diff --git a/drivers/usb/host/shost/shost_readyq.c b/drivers/usb/host/shost/shost_readyq.c
new file mode 100644
index 0000000..9e41da5
--- /dev/null
+++ b/drivers/usb/host/shost/shost_readyq.c
@@ -0,0 +1,240 @@
+/****************************************************************************
+ * (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
+ ****************************************************************************/
+
+static struct trans_ready_q periodic_trans_ready_q;
+static struct trans_ready_q nonperiodic_trans_ready_q;
+
+/******************************************************************************/
+/*!
+ * @name void init_transfer_ready_q(void)
+ *
+ * @brief this function initiates PeriodicTransferReadyQ
+ * and NonPeriodicTransferReadyQ.
+ *
+ *
+ * @param void
+ *
+ * @return void.
+ */
+/******************************************************************************/
+static void init_transfer_ready_q(void)
+{
+ otg_dbg(OTG_DBG_SCHEDULE, "start init_transfer_ready_q\n");
+
+ otg_list_init(&periodic_trans_ready_q.entity_list);
+ periodic_trans_ready_q.is_periodic = true;
+ periodic_trans_ready_q.entity_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.entity_list);
+ nonperiodic_trans_ready_q.is_periodic = false;
+ nonperiodic_trans_ready_q.entity_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(struct ed *insert_ed,
+ * bool is_first)
+ *
+ * @brief this function inserts ed_t * to TransferReadyQ.
+ *
+ *
+ * @param [IN] insert_ed
+ * = indicates the ed_t to be inserted to TransferReadyQ.
+ * [IN] is_first
+ * = 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.
+ */
+/******************************************************************************/
+static int insert_ed_to_ready_q(struct ed *insert_ed, bool is_first)
+{
+ otg_dbg(OTG_DBG_SCHEDULE_ED, "ed_id %d, td_id %d, %d\n",
+ insert_ed->ed_id, insert_ed->num_td, is_first);
+
+ if (insert_ed->ed_desc.endpoint_type == BULK_TRANSFER ||
+ insert_ed->ed_desc.endpoint_type == CONTROL_TRANSFER) {
+
+ if (is_first) {
+ otg_list_push_next(&insert_ed->readyq_list,
+ &nonperiodic_trans_ready_q.entity_list);
+ } else {
+ otg_list_push_prev(&insert_ed->readyq_list,
+ &nonperiodic_trans_ready_q.entity_list);
+ }
+ nonperiodic_trans_ready_q.entity_num++;
+
+ } else {
+ if (is_first) {
+ otg_list_push_next(&insert_ed->readyq_list,
+ &periodic_trans_ready_q.entity_list);
+ } else {
+ otg_list_push_prev(&insert_ed->readyq_list,
+ &periodic_trans_ready_q.entity_list);
+ }
+ periodic_trans_ready_q.entity_num++;
+ }
+ return USB_ERR_SUCCESS;
+}
+
+
+static u32 get_periodic_ready_q_entity_num(void)
+{
+ return periodic_trans_ready_q.entity_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.
+ */
+/******************************************************************************/
+static int remove_ed_from_ready_q(struct ed *remove_ed)
+{
+ otg_dbg(OTG_DBG_SCHEDULE_ED, "ed_id %d, td_id %d\n",
+ remove_ed->ed_id, remove_ed->num_td);
+
+ otg_list_pop(&remove_ed->readyq_list);
+
+ if (remove_ed->ed_desc.endpoint_type == BULK_TRANSFER ||
+ remove_ed->ed_desc.endpoint_type == CONTROL_TRANSFER) {
+
+ nonperiodic_trans_ready_q.entity_num--;
+
+ } else
+ periodic_trans_ready_q.entity_num--;
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name int get_ed_from_ready_q(bool is_periodic,
+ * struct td **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] is_periodic
+ * = 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.
+ */
+/******************************************************************************/
+
+static int get_ed_from_ready_q(struct ed **get_ed, bool is_periodic)
+{
+ otg_list_head *qlist = NULL;
+
+ /* periodic transfer : control and bulk */
+ if (is_periodic) {
+
+ if (periodic_trans_ready_q.entity_num == 0)
+ return USB_ERR_NO_ENTITY;
+
+ qlist = periodic_trans_ready_q.entity_list.next;
+
+ if (!otg_list_empty(&periodic_trans_ready_q.entity_list)) {
+
+ *get_ed = otg_list_get_node(qlist,
+ struct ed, readyq_list);
+
+ if (qlist->prev == LIST_POISON2 ||
+ qlist->next == LIST_POISON1) {
+
+ printk(KERN_ERR "shost scheduler: get_ed_from_ready_q error\n");
+ periodic_trans_ready_q.entity_num = 0;
+
+ } else {
+ otg_list_pop(qlist);
+ periodic_trans_ready_q.entity_num--;
+ }
+ return USB_ERR_SUCCESS;
+
+ } else
+ return USB_ERR_NO_ENTITY;
+
+ /* non-periodic transfer : interrupt and ischo */
+ } else {
+
+ if (nonperiodic_trans_ready_q.entity_num == 0)
+ return USB_ERR_NO_ENTITY;
+
+ qlist = nonperiodic_trans_ready_q.entity_list.next;
+
+ if (!otg_list_empty(&nonperiodic_trans_ready_q.entity_list)) {
+
+ *get_ed = otg_list_get_node(qlist,
+ struct ed, readyq_list);
+
+ if (qlist->prev == LIST_POISON2 ||
+ qlist->next == LIST_POISON1) {
+
+ printk(KERN_ERR "s3c-otg-scheduler get_ed_from_ready_q error\n");
+ nonperiodic_trans_ready_q.entity_num = 0;
+
+ } else {
+ otg_list_pop(qlist);
+ nonperiodic_trans_ready_q.entity_num--;
+ }
+ return USB_ERR_SUCCESS;
+ } else
+ return USB_ERR_NO_ENTITY;
+ }
+}
+
+
diff --git a/drivers/usb/host/shost/shost_regs.h b/drivers/usb/host/shost/shost_regs.h
new file mode 100644
index 0000000..d560567
--- /dev/null
+++ b/drivers/usb/host/shost/shost_regs.h
@@ -0,0 +1,747 @@
+/****************************************************************************
+* (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
+
+
+#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 */
+
+#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
+
+/* Bits to write to EP_INT_EN_REG - Use CLEAR */
+#define EP_INTERRUPT_DISABLE_ALL 0x0
+
+/* 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)
+
+
+/*********************************************************************
+ * Global CSR
+ *********************************************************************/
+
+/* GAHBCFG
+ * OTG AHB Configuration Register
+ * p1359
+ * d201
+ */
+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 0
+#define INT_DMA_MODE_INCR 1
+#define INT_DMA_MODE_INCR4 3
+#define INT_DMA_MODE_INCR8 5
+#define INT_DMA_MODE_INCR16 7
+ 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;
+
+
+/* GUSBCFG
+ * OTG USB Configuration Register
+ * p1360
+ * d202
+ */
+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;
+
+
+/* GRSTCTL
+ * Core Reset Register
+ * p1362
+ * d208
+ */
+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;
+
+
+/* GINTSTS
+ * Core Interrupt Register
+ * p1364
+ * d212
+ */
+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;
+
+
+/* GINTMSK
+ * Core Interrupt Mask Register
+ * p1369
+ * d217
+ */
+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;
+
+
+/* GRXSTSR/GRXSTSP
+ * Host Mode Receive Status Debug Read/Status Read and Pop Registers
+ * p1370
+ * d219
+ */
+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;
+
+
+/* User HW Config2 Register
+ * d230
+ */
+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;
+
+
+/*********************************************************************
+ * Host Mode Registers
+ *********************************************************************/
+
+/* Host Configuration Register
+ * d247
+ */
+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;
+
+
+/* Host Frame Interval Register
+ * d247
+ */
+typedef union _hfir_t {
+ /* raw register data */
+ u32 d32;
+
+ /* register bits */
+ struct {
+ unsigned frint:16;
+ unsigned Reserved:16;
+ } b;
+} hfir_t;
+
+/* Host Frame Number/Frame Time Remaining Register
+ * d248
+ */
+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;
+
+
+/* Host Channel Interrupt Mask Register
+ d257
+ */
+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;
+
+
+/* Host Channel Interrupt Register
+ d254
+ */
+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;
+
+
+/* Host All Channels Interrupt Register
+ d250
+ */
+
+#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;
+
+
+/* Host Port Control and Status Register
+ * d250
+ */
+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;
+
+
+/* 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
+
+/* Host Channel-n Charracteristics Register
+ * d253
+ */
+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;
+
+/* Host Channel-n Transfer Size Register
+ * d257
+ */
+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;
+
+
+/* The Power and Clock Gating Control Register
+ d292
+ */
+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;
+
+
+#endif
+
+
diff --git a/drivers/usb/host/shost/shost_roothub.c b/drivers/usb/host/shost/shost_roothub.c
new file mode 100644
index 0000000..3e2541d
--- /dev/null
+++ b/drivers/usb/host/shost/shost_roothub.c
@@ -0,0 +1,579 @@
+/****************************************************************************
+ * (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
+ ****************************************************************************/
+
+
+/**
+ * void bus_suspend(void)
+ *
+ * @brief Make suspend status when this platform support PM Mode
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+static 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
+ *
+ */
+static 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;
+}
+
+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
+ *
+ */
+static 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
+ *
+ */
+static 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
+ *
+ */
+static 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;
+ struct hub_descriptor *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 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 = (struct hub_descriptor *)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;
+}
+
diff --git a/drivers/usb/host/shost/shost_scheduler.c b/drivers/usb/host/shost/shost_scheduler.c
new file mode 100644
index 0000000..1739298
--- /dev/null
+++ b/drivers/usb/host/shost/shost_scheduler.c
@@ -0,0 +1,420 @@
+/****************************************************************************
+ * (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 "shost.h"
+
+#include "shost_readyq.c"
+#include "shost_schedulerlib.c"
+
+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(struct ed *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,
+ * struct td *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 struct td 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, struct td *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, struct td *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 struct td 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, struct td *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(struct td *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 struct td 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(struct td *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;
+
+ }
+ /* this case is not support....
+ else {
+ }
+ */
+ }
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name int deallocate(struct td *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 struct td at ed_t,
+ * deallocate() insert the ed_t to TransferReadyQ.
+ *
+ * @param [IN] deallocate_td
+ * - indicates the pointer ot the struct td 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(struct td *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.... */
+/* transferchecker-common.c
+ hcd.c */
+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
+ * struct td at TransferringTDArray[chnum]
+ *
+ * @param [IN] chnum
+ * - indicates the index of TransferringTDArray
+ * to include the address of struct td which we gets
+ * [OUT] td_addr_p
+ * - indicate pointer to store the address of struct td.
+ *
+ * @return
+ * USB_ERR_SUCCESS -if success to get the address of struct td.
+ * USB_ERR_FAIL-if fail to get the address of struct td.
+ */
+/******************************************************************************/
+/* transferchecker-common.c */
+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/shost/shost_scheduler.h b/drivers/usb/host/shost/shost_scheduler.h
new file mode 100644
index 0000000..fed5035
--- /dev/null
+++ b/drivers/usb/host/shost/shost_scheduler.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * (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)
+ * : Optimizing for performance
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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
+
+/* hcd.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(struct ed *remove_ed);
+extern int cancel_to_transfer_td(struct sec_otghost *otghost,
+ struct td *cancel_td);
+extern int retransmit(struct sec_otghost *otghost, struct td *retransmit_td);
+extern int reschedule(struct td *resched_td);
+extern int deallocate(struct td *dealloc_td);
+extern void do_schedule(struct sec_otghost *otghost);
+extern int get_td_info(u8 chnum, unsigned int *td_addr);
+
+/* transfer-common.c */
+int insert_ed_to_scheduler(struct sec_otghost *otghost, struct ed *insert_ed);
+
+#endif
+
diff --git a/drivers/usb/host/shost/shost_schedulerlib.c b/drivers/usb/host/shost/shost_schedulerlib.c
new file mode 100644
index 0000000..de17401
--- /dev/null
+++ b/drivers/usb/host/shost/shost_schedulerlib.c
@@ -0,0 +1,426 @@
+/****************************************************************************
+ * (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)
+ * : Optimizing for performance
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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
+ ****************************************************************************/
+
+/* 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;
+
+static u32 perio_used_bustime;
+static u8 perio_used_chnum;
+static u8 nonperio_used_chnum;
+static u8 total_used_chnum;
+static u32 transferring_td_array[16];
+
+
+static 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;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static u8 get_avail_chnum(void)
+{
+ return total_chnum_threshold - total_used_chnum;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static 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 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
+ */
+/******************************************************************************/
+static void do_periodic_schedule(struct sec_otghost *otghost)
+{
+ struct ed *scheduling_ed = NULL;
+ int err_sched = USB_ERR_SUCCESS;
+ u32 sched_cnt = 0;
+
+ otg_list_head *td_list_entry;
+ struct td *td;
+ u32 cur_frame_num = 0;
+ u8 alloc_ch;
+
+ otg_dbg(OTG_DBG_SCHEDULE, "***** Start periodicSchedul *****\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;
+
+ otg_dbg(OTG_DBG_SCHEDULE, "sched_cnt : %d\n", sched_cnt);
+
+ err_sched = get_ed_from_ready_q(&scheduling_ed, true);
+
+ if (err_sched != USB_ERR_SUCCESS) {
+ /* there is no ED on PeriodicTransferQ.
+ So we finish scheduling.*/
+ otg_dbg(OTG_DBG_SCHEDULE, "no ed\n");
+ goto end_sched_perio_transfer;
+ }
+
+ cur_frame_num = 0;
+
+ otg_dbg(OTG_DBG_SCHEDULE,
+ "the %d ed to be scheduled\n", (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 struct td.
+ so we schedules another ed 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 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,
+ struct td, td_list_entry);
+
+ if ((td->is_transferring) || (td->is_transfer_done)) {
+ /* the selected struct td was already transferring
+ or completed to transfer.
+ we should decide how to control this case.*/
+ goto end_sched_perio_transfer;
+ }
+
+ otg_dbg(OTG_DBG_SCHEDULE,
+ "the struct td 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;
+ 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 current ed 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;
+ }
+
+ }
+
+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.
+ * if there are some ed on NonPeriodicTransferReadyQ,
+ * this function request to start USB Trasnfer to S3C6400OCI.
+ *
+ * @param void
+ * @return void
+ */
+/******************************************************************************/
+static void do_nonperiodic_schedule(struct sec_otghost *otghost)
+{
+ struct ed *scheduling_ed;
+ int err_sched;
+
+ otg_list_head *td_list_entry;
+ struct td *td;
+ u8 alloc_ch;
+
+ if (total_used_chnum >= total_chnum_threshold) {
+ pr_info("shost nonperiodic: used_chnum >= total_chnum\n");
+ return;
+ }
+
+ while (1) {
+
+start_nonperiodic:
+ /* check there is available channel resource
+ for Non-Periodic Transfer. */
+ if (total_used_chnum == total_chnum_threshold) {
+ pr_info("shost nonperiodic: used_chnum == total_chnum\n");
+ goto end_nonperiodic;
+ }
+
+ err_sched = get_ed_from_ready_q(&scheduling_ed, false);
+
+ if (err_sched != USB_ERR_SUCCESS) {
+ /* pr_info("shost: non: nothing to schedule\n"); */
+ goto end_nonperiodic;
+ }
+
+ td_list_entry = scheduling_ed->td_list_entry.next;
+
+ if (otg_list_empty(&scheduling_ed->td_list_entry)) {
+ /* scheduling_ed has no td.
+ so we schedules another ed
+ on PeriodicTransferReadyQ.*/
+ goto start_nonperiodic;
+ }
+
+ if (scheduling_ed->ed_status.is_in_transferring) {
+ /* scheduling_ed is already Scheduled.
+ so we schedules another ed
+ on PeriodicTransferReadyQ.*/
+ goto start_nonperiodic;
+ }
+
+ td = otg_list_get_node(td_list_entry, struct td, td_list_entry);
+
+ if ((td->is_transferring) || (td->is_transfer_done)) {
+ pr_info("shost nonperiodic: td is busy\n");
+ goto end_nonperiodic;
+ }
+
+ alloc_ch = oci_start_transfer(otghost, &td->cur_stransfer);
+
+ if (alloc_ch < total_chnum_threshold) {
+
+ td->cur_stransfer.alloc_chnum = alloc_ch;
+ 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 must insert the ed to queue,
+ because the USB Transfer of the ed 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_nonperiodic;
+ }
+ } /* while */
+
+end_nonperiodic:
+ return;
+}
+
+/******************************************************************************/
+/*!
+ * @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, struct ed *insert_ed)
+{
+ if (!insert_ed->is_need_to_insert_scheduler)
+ return USB_ERR_ALREADY_EXIST;
+
+ otg_dbg(OTG_DBG_SCHEDULE_ED, "ed_id %d, td %d\n",
+ insert_ed->ed_id, insert_ed->num_td);
+
+ 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;
+}
+
diff --git a/drivers/usb/host/shost/shost_struct.h b/drivers/usb/host/shost/shost_struct.h
new file mode 100644
index 0000000..638c6f2
--- /dev/null
+++ b/drivers/usb/host/shost/shost_struct.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+ * (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
+
+
+struct isoch_packet_desc {
+ /* start address of buffer is buffer address + uiOffsert.*/
+ u32 isoch_packiet_start_addr;
+ u32 buf_size;
+ u32 transferred_szie;
+ u32 isoch_status;
+};
+
+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;
+};
+
+struct control_data_toggle {
+ u8 setup;
+ u8 data;
+ u8 status;
+};
+
+struct ed_status {
+ struct control_data_toggle control_data_toggle;
+ u8 data_toggle;
+ bool is_ping_enable;
+ bool is_in_transfer_ready_q;
+ bool is_in_transferring;
+ u32 in_transferring_td;
+ bool is_alloc_resource_for_ed;
+};
+
+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;
+};
+
+struct hc_reg {
+ hcintmsk_t hc_int_msk;
+ hcintn_t hc_int;
+ u32 dma_addr;
+
+};
+
+struct stransfer {
+ u32 stransfer_id;
+ u32 parent_td;
+ struct ed_desc *ed_desc_p;
+ struct ed_status *ed_status_p;
+ u32 vir_addr;
+ u32 phy_addr;
+ u32 buf_size;
+ u32 packet_cnt;
+ u8 alloc_chnum;
+ struct hc_reg hc_reg;
+};
+
+struct ed {
+ u32 ed_id;
+ bool is_halted;
+ bool is_need_to_insert_scheduler;
+ struct ed_desc ed_desc;
+ struct ed_status ed_status;
+ otg_list_head ed_list_entry;
+ otg_list_head td_list_entry;
+ otg_list_head readyq_list;
+ u32 num_td;
+ void *ed_private;
+};
+
+struct td {
+ u32 td_id;
+ struct ed *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;
+
+ struct standard_dev_req_info standard_dev_req_info;
+ u32 vir_buf_addr;
+ u32 phy_buf_addr;
+ u32 buf_size;
+ u32 transfer_flag;
+
+ struct stransfer cur_stransfer;
+ u32 error_code;
+ u32 err_cnt;
+ otg_list_head td_list_entry;
+
+ /* Isochronous Transfer Specific */
+ u32 isoch_packet_num;
+ struct isoch_packet_desc *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;
+};
+
+struct trans_ready_q {
+ bool is_periodic;
+ otg_list_head entity_list;
+ u32 entity_num;
+
+ /* In case of Periodic Transfer */
+ u32 total_perio_bus_bandwidth;
+ u8 total_alloc_chnum;
+};
+
+struct hc_info {
+ hcintmsk_t hc_int_msk;
+ hcintn_t hc_int;
+ u32 dma_addr;
+ hcchar_t hc_char;
+ hctsiz_t hc_size;
+};
+
+#ifndef USB_MAXCHILDREN
+ #define USB_MAXCHILDREN (31)
+#endif
+
+/* TODO: use usb_hub_descriptor
+ * <linux/usb/ch11.h>
+ */
+struct hub_descriptor {
+ 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];
+} __packed;
+
+#endif
diff --git a/drivers/usb/host/shost/shost_transfer.c b/drivers/usb/host/shost/shost_transfer.c
new file mode 100644
index 0000000..122ce65
--- /dev/null
+++ b/drivers/usb/host/shost/shost_transfer.c
@@ -0,0 +1,1025 @@
+/****************************************************************************
+ * (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 )
+ * - Optimizing for performance
+ * (3) 2008/08/18 by SeungSoo Yang ( ss1.yang@samsung.com )
+ * - Modifying for successful rmmod & disconnecting
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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 "shost_transfer.h"
+
+/* the header pointer to indicate the ED_list
+ * to manage the struct ed to be created and initiated.
+ */
+static otg_list_head ed_list_head;
+static u32 ref_periodic_transfer;
+
+/**
+ * void enable_sof(void)
+ *
+ * @brief Generate SOF Interrupt.
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remark
+ *
+ */
+static 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
+ *
+ */
+static void disable_sof(void)
+{
+ gintmsk_t gintmsk = {.d32 = 0};
+ gintmsk.b.sofintr = 1;
+ clear_reg_32(GINTMSK, gintmsk.d32);
+}
+
+
+
+/******************************************************************************/
+/*!
+ * @name int cancel_transfer(struct sec_otghost *otghost,
+ * struct ed *parent_ed,
+ * struct td *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 struct td at parent_ed, then this function requests
+ * to release some usb resources for the struct ed to S3CScheduler.
+ * finally this function deletes the cancel_td.
+ *
+ * @param [IN] pUpdateTD = indicates the pointer ot the struct td
+ * 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.
+ */
+/******************************************************************************/
+static int cancel_transfer(struct sec_otghost *otghost,
+ struct ed *parent_ed, struct td *cancel_td)
+{
+ otg_list_head *tmp_list_p, *tmp_list2_p;
+ int err = USB_ERR_DEQUEUED;
+ bool cond_found = false;
+
+ if (parent_ed == NULL || cancel_td == NULL) {
+ otg_err(1, "%s is null.\n", parent_ed ?
+ "cancel_td" : "parent_ed");
+ return USB_ERR_NOELEMENT;
+ }
+
+ 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;
+ }
+
+ 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);
+ parent_ed->is_need_to_insert_scheduler = true;
+ }
+ }
+
+ if (parent_ed->num_td) {
+ 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 struct ed. but, not release memory for this ed.
+ */
+ 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;
+ otg_usbcore_giveback(cancel_td);
+
+ /* TODO: recursive call occured. FIX */
+ delete_td(otghost, cancel_td);
+
+ErrorStatus:
+
+ return err;
+}
+
+
+
+
+/******************************************************************************/
+/*!
+ * @name int cancel_all_td(struct sec_otghost *otghost, struct ed *parent_ed)
+ *
+ * @brief this function cancels all Transfer which parent_ed manages.
+ *
+ * @param [IN] parent_ed = indicates the pointer ot the struct ed
+ * 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.
+ */
+/******************************************************************************/
+static int cancel_all_td(struct sec_otghost *otghost, struct ed *parent_ed)
+{
+ otg_list_head *cancel_td_list_entry;
+ struct td *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,
+ struct td, td_list_entry);
+
+ cancel_transfer(otghost, parent_ed, cancel_td);
+
+ } while (parent_ed->num_td);
+
+ return USB_ERR_SUCCESS;
+}
+
+
+
+
+/******************************************************************************/
+/*!
+ * @name int delete_ed(struct ed *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 struct td
+ *
+ * @param [IN] delete_ed = indicates the address of struct ed to be deleted.
+ *
+ * @return USB_ERR_SUCCESS -if successes to delete the struct ed.
+ * USB_ERR_FAILl -if fails to delete the ed.
+ */
+/******************************************************************************/
+static int delete_ed(struct sec_otghost *otghost, struct ed *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 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 to be existed.
+ *
+ * @param void
+ * @return void
+ */
+/******************************************************************************/
+
+static 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 on ED_list_head. if some ed exists,
+ * deinit_transfer() deletes the ed.
+ *
+ * @param void
+ * @return void
+ */
+/******************************************************************************/
+static void deinit_transfer(struct sec_otghost *otghost)
+{
+ otg_list_head *ed_list_member;
+ struct ed *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,
+ struct ed, ed_list_entry);
+
+ delete_ed(otghost, delete_ed_p);
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name int delete_td(struct sec_otghost *otghost, struct td *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 scheduler.
+ *
+ *
+ * @param [OUT] new_td_p = returns the address of the new struct td.
+ *
+ * @return USB_ERR_SUCCESS -if successes to create the new struct td.
+ * USB_ERR_FAILl -if fails to create to new struct td.
+ */
+/******************************************************************************/
+int delete_td(struct sec_otghost *otghost, struct td *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;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int create_ed(struct ed **new_ed)
+ *
+ * @brief this function creates a new ed and returns the ed to Caller
+ *
+ * @param [OUT] new_ed = returns the address of the new ed .
+ *
+ * @return USB_ERR_SUCCESS -if successes to create the new ed.
+ * USB_ERR_FAILl -if fails to create to new ed.
+ */
+/******************************************************************************/
+static int create_ed(struct ed **new_ed)
+{
+ int err_code = USB_ERR_SUCCESS;
+
+ err_code = otg_mem_alloc((void **)new_ed,
+ (u16)sizeof(struct ed), USB_MEM_ASYNC);
+ otg_mem_set(*new_ed, 0, sizeof(struct ed));
+ return err_code;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name int init_ed(struct ed *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 struct ed 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.
+ * USB_ERR_FAILl -if fails to initiate the ed.
+ * USB_ERR_NOSPACE -if fails to initiate the ed
+ * because there is no USB Resource for this init_ed.
+ */
+/******************************************************************************/
+static int init_ed(struct ed *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_toggle = DATA0;
+ break;
+
+ case CONTROL_TRANSFER:
+ init_ed->ed_status.control_data_toggle.setup = SETUP;
+ init_ed->ed_status.control_data_toggle.data = DATA1;
+ init_ed->ed_status.control_data_toggle.status = DATA1;
+ break;
+
+ case ISOCH_TRANSFER:
+ if (f_is_ep_in) {
+ switch (multi_count) {
+ case MULTI_COUNT_ZERO:
+ init_ed->ed_status.data_toggle = DATA0;
+ break;
+ case MULTI_COUNT_ONE:
+ init_ed->ed_status.data_toggle = DATA1;
+ break;
+ case MULTI_COUNT_TWO:
+ init_ed->ed_status.data_toggle = DATA2;
+ break;
+ default:
+ break;
+ }
+
+ } else {
+ switch (multi_count) {
+ case MULTI_COUNT_ZERO:
+ init_ed->ed_status.data_toggle = DATA0;
+ break;
+ case MULTI_COUNT_ONE:
+ init_ed->ed_status.data_toggle = MDATA;
+ break;
+ case MULTI_COUNT_TWO:
+ init_ed->ed_status.data_toggle = 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 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(struct td **new_td)
+ *
+ * @brief this function creates a new struct td and returns the struct td to Caller
+ *
+ *
+ * @param [OUT] new_td = returns the address of the new struct td .
+ *
+ * @return USB_ERR_SUCCESS -if successes to create the new struct td.
+ * USB_ERR_FAILl -if fails to create to new struct td.
+ */
+/*****************************************************************************/
+static int create_td(struct td **new_td)
+{
+ int err_code = USB_ERR_SUCCESS;
+
+ err_code = otg_mem_alloc((void **)new_td,
+ (u16)sizeof(struct td), USB_MEM_ASYNC);
+ otg_mem_set(*new_td, 0, sizeof(struct td));
+ return err_code;
+}
+
+
+/*****************************************************************************/
+/*!
+ * @name int init_perio_stransfer( bool f_is_isoch_transfer,
+ * struct td *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 struct td 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.
+ */
+/*****************************************************************************/
+static int init_perio_stransfer(bool f_is_isoch_transfer,
+ struct td *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(struct hc_reg));
+
+ 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.phy_addr =
+ parent_td->phy_buf_addr +
+ parent_td->isoch_packet_desc_p[0].
+ isoch_packiet_start_addr;
+
+ parent_td->cur_stransfer.vir_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.phy_addr = parent_td->phy_buf_addr;
+ parent_td->cur_stransfer.vir_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 int init_nonperio_stransfer(bool f_is_standard_dev_req,
+ * struct td *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 is Control or not.
+ * [IN] parent_td- indicates the address of struct td 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.
+ */
+/******************************************************************************/
+static int init_nonperio_stransfer(bool f_is_standard_dev_req,
+ struct td *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(struct hc_reg));
+
+ 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.phy_addr =
+ parent_td->standard_dev_req_info.
+ phy_standard_dev_req_addr;
+ parent_td->cur_stransfer.vir_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.phy_addr
+ = parent_td->phy_buf_addr;
+ parent_td->cur_stransfer.vir_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 int init_td(struct td *init_td,
+ * struct ed *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 struct td to be initiated.
+ * [IN] parent_ed- indicate the ed 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 Request
+ * [IN] phy_setup- the physical address of buffer to store the Request.
+ * [IN] vir_setup- the virtual address of buffer to store the 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.
+ * td_priv stores the urb of linux.
+ *
+ * @return USB_ERR_SUCCESS -if successes to initiate the new struct td.
+ * USB_ERR_FAILl -if fails to create to new struct td.
+ */
+/******************************************************************************/
+static int init_td(struct td *init_td,
+ struct ed *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,
+ struct isoch_packet_desc *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 struct td 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,
+ * struct ed *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 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 Request.
+ * [IN] setup_phy_addr - the physical address of buffer to store the 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_siz- 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.
+ * td_priv stores the urb of linux.
+ * [OUT] return_td_addr - indicates the variable address
+ * to store the new struct td for this transfer
+ *
+ * @return USB_ERR_SUCCESS - if successes to initiate the new struct td.
+ * USB_ERR_FAILl - if fails to create to new struct td.
+ */
+/******************************************************************************/
+static int issue_transfer(struct sec_otghost *otghost,
+ struct ed *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,
+ struct isoch_packet_desc *isoch_packet_desc,
+ void *td_priv,
+ unsigned int *return_td_addr)
+{
+ struct td *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;
+}
+
+
+/* TODO: not used. removed */
+#if 0
+static 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);
+}
+
+static 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.
+ *
+ * @return void
+ */
+/******************************************************************************/
+static 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;
+}
+#endif
+
+
diff --git a/drivers/usb/host/shost/shost_transfer.h b/drivers/usb/host/shost/shost_transfer.h
new file mode 100644
index 0000000..397fdae
--- /dev/null
+++ b/drivers/usb/host/shost/shost_transfer.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+ * (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)
+ * : Optimizing for performance
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * 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
+
+/*
+ transfer-common.c
+ transferchecker_common.c
+ */
+int delete_td(struct sec_otghost *otghost, struct td * delete_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;
+}
+#endif
+
diff --git a/drivers/usb/host/shost/shost_transferchecker.c b/drivers/usb/host/shost/shost_transferchecker.c
new file mode 100644
index 0000000..855164c
--- /dev/null
+++ b/drivers/usb/host/shost/shost_transferchecker.c
@@ -0,0 +1,503 @@
+/****************************************************************************
+ * (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 "shost.h"
+
+/**
+ * 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
+ *
+ */
+static 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
+ *
+ */
+static void unmask_channel_interrupt(u32 ch_num, u32 mask_info)
+{
+ update_reg_32(HCINTMSK(ch_num), mask_info);
+}
+
+/**
+ * int get_ch_info(struct hc_info * 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
+ *
+ */
+static int get_ch_info(struct hc_info *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
+ *
+ */
+static 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
+ *
+ */
+static void clear_ch_intr(u8 ch_num, u32 clear_bit)
+{
+ update_reg_32(HCINT(ch_num), clear_bit);
+}
+
+
+static int
+release_trans_resource(struct sec_otghost *otghost,
+ struct td *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;
+}
+
+static u32 calc_transferred_size(bool f_is_complete,
+ struct td *td, struct hc_info *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;
+ }
+}
+
+static void update_frame_number(struct td *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;
+ }
+}
+
+static void update_data_toggle(struct td *td, u8 toggle)
+{
+ 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_toggle.data = toggle;
+ }
+ break;
+ case BULK_TRANSFER:
+ case INT_TRANSFER:
+ td->parent_ed_p->ed_status.data_toggle = toggle;
+ break;
+
+ case ISOCH_TRANSFER:
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************/
+/*!
+ * @name void update_perio_stransfer(struct td *parent_td)
+ *
+ * @brief this function updates the parent_td->cur_stransfer
+ * to be used by oci. the STransfer of parent_td is for Periodic Transfer.
+ *
+ * @param [IN/OUT]parent_td = indicates the pointer of struct td
+ * 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.
+ */
+/******************************************************************************/
+static void update_perio_stransfer(struct td *parent_td)
+{
+ switch (parent_td->parent_ed_p->ed_desc.endpoint_type) {
+ case INT_TRANSFER:
+ parent_td->cur_stransfer.phy_addr =
+ parent_td->phy_buf_addr +
+ parent_td->transferred_szie;
+
+ parent_td->cur_stransfer.vir_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.phy_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.vir_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;
+ }
+}
+
+/****************************************************************************/
+/*!
+ * @name void update_nonperio_stransfer(struct td *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 struct td
+ * 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.
+ */
+/****************************************************************************/
+static void update_nonperio_stransfer(struct td *parent_td)
+{
+ switch (parent_td->parent_ed_p->ed_desc.endpoint_type) {
+
+ case BULK_TRANSFER:
+ parent_td->cur_stransfer.phy_addr =
+ parent_td->phy_buf_addr +
+ parent_td->transferred_szie;
+
+ parent_td->cur_stransfer.vir_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.phy_addr =
+ parent_td->standard_dev_req_info.
+ phy_standard_dev_req_addr;
+ parent_td->cur_stransfer.vir_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.phy_addr =
+ parent_td->phy_buf_addr +
+ parent_td->transferred_szie;
+
+ parent_td->cur_stransfer.vir_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.phy_addr = 0;
+ parent_td->cur_stransfer.vir_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);
+
+}
+
+#include "shost_transferchecker_control.c"
+#include "shost_transferchecker_interrupt.c"
+#include "shost_transferchecker_bulk.c"
+
+/******************************************************************************/
+/*!
+ * @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 to scheduler.
+ * 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;
+
+ struct hc_info ch_info;
+ struct td *done_td = {0};
+
+ u32 td_addr = 0;
+ u8 proc_result = 0;
+
+ otg_mem_set((void *)&ch_info, 0, sizeof(struct hc_info));
+
+ /* 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 struct td
+ to have the channel to be interrupted. */
+ if (!(get_td_info(do_try_cnt, &td_addr))) {
+
+ done_td = (struct td *)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(&otghost->lock);
+ otg_usbcore_giveback(done_td);
+ spin_lock(&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);
+}
+
+
diff --git a/drivers/usb/host/shost/shost_transferchecker_bulk.c b/drivers/usb/host/shost/shost_transferchecker_bulk.c
new file mode 100644
index 0000000..13c6b0c
--- /dev/null
+++ b/drivers/usb/host/shost/shost_transferchecker_bulk.c
@@ -0,0 +1,671 @@
+/****************************************************************************
+ * (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
+ ****************************************************************************/
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xfercompl_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xfercompl event.
+ * the procedure of this function is as following
+ * 1. clears all bits of the channel' HCINT
+ * 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 on DATA_STAGE.
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+static u8 process_xfercompl_on_bulk(struct td *result_td,
+ struct hc_info *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_data_toggle(result_td, hc_reg_data->hc_size.b.pid);
+
+ 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(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theAHB Errorl event.
+ * this function stop the channel to be executed
+ * TBD....
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+/* TODO: not used. removed */
+#if 0
+static u8 process_ahb_on_bulk(struct td *result_td,
+ struct hc_info *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;
+
+}
+#endif
+
+/******************************************************************************/
+/*!
+ * @name u8 process_stall_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with theStall event.
+ * when Stall is occured at Bulk Transfer, we should reset the PID as DATA0
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+static u8 process_stall_on_bulk(struct td *result_td,
+ struct hc_info *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_data_toggle(result_td, DATA0);
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nak_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nak event.
+ * 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 struct td 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
+ */
+/******************************************************************************/
+static u8 process_nak_on_bulk(struct td *result_td,
+ struct hc_info *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_data_toggle(result_td, hc_reg_data->hc_size.b.pid);
+
+ return RE_TRANSMIT;
+ }
+ return NO_ACTION;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ack_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the ack event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+static u8 process_ack_on_bulk(struct td *result_td,
+ struct hc_info *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(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the nyet event.
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+static u8 process_nyet_on_bulk(struct td *result_td,
+ struct hc_info *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_data_toggle(result_td, hc_reg_data->hc_size.b.pid);
+
+ return RE_TRANSMIT;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xacterr_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the xacterr event.
+ * 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.
+ * 3. unmasks ack/nak/datatglerr bit of HCINTMSK.
+ * 4. clears the xacterr bit of HCINT
+ * 5. calculates the size of the transferred data.
+ * 6. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 7. update the Data Toggle.
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td 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
+ */
+/******************************************************************************/
+static u8 process_xacterr_on_bulk(struct td *result_td,
+ struct hc_info *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_data_toggle(result_td, hc_reg_data->hc_size.b.pid);
+
+ return ret_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name void process_bblerr_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the Babble event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+static u8 process_bblerr_on_bulk(struct td *result_td,
+ struct hc_info *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( struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ *
+ * @brief this function deals with the datatglerr
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hc_reg_data
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+static u8 process_datatgl_on_bulk(struct td *result_td,
+ struct hc_info *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;
+
+}
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_chhltd_on_bulk(struct td *result_td,
+ * struct hc_info *hc_reg_data)
+ *
+ * @brief this function processes Channel Halt event.
+ * 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 struct td 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.
+ */
+/******************************************************************************/
+static u8 process_chhltd_on_bulk(struct td *result_td,
+ struct hc_info *hc_reg_data)
+{
+ 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;
+ }
+
+ return USB_ERR_SUCCESS;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_bulk_transfer(struct td *result_td,
+ * struct hc_info *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 struct td 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,
+ */
+/******************************************************************************/
+static u8 process_bulk_transfer(struct td *result_td,
+ struct hc_info *hc_reg_data)
+{
+ hcintn_t hc_intr_info;
+ u8 ret = 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 = process_chhltd_on_bulk(result_td, hc_reg_data);
+
+ else if (hc_intr_info.b.ack)
+ ret = process_ack_on_bulk(result_td, hc_reg_data);
+
+ else if (hc_intr_info.b.nak)
+ ret = process_nak_on_bulk(result_td, hc_reg_data);
+
+ else if (hc_intr_info.b.datatglerr)
+ ret = process_datatgl_on_bulk(result_td, hc_reg_data);
+
+ } else {
+
+ if (hc_intr_info.b.chhltd)
+ ret = process_chhltd_on_bulk(result_td, hc_reg_data);
+
+ else if (hc_intr_info.b.ack)
+ ret = process_ack_on_bulk(result_td, hc_reg_data);
+ }
+
+ return ret;
+}
+
diff --git a/drivers/usb/host/shost/shost_transferchecker_control.c b/drivers/usb/host/shost/shost_transferchecker_control.c
new file mode 100644
index 0000000..8d0cfbc
--- /dev/null
+++ b/drivers/usb/host/shost/shost_transferchecker_control.c
@@ -0,0 +1,777 @@
+/****************************************************************************
+ * (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
+ ****************************************************************************/
+
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xfercompl_on_control(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the xfercompl event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return USB_ERR_SUCCESS
+ */
+/******************************************************************************/
+static u8 process_xfercompl_on_control(struct td *result_td, struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ /* 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 &&
+ hcinfo->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_data_toggle(result_td,
+ hcinfo->hc_size.b.pid);
+ }
+ }
+
+ if (hcinfo->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 (hcinfo->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(ruct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with theAHB Errorl event
+ * this function stop the channel to be executed
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+
+/* TODO: not used. remove */
+#if 0
+static u8 process_ahb_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ return DE_ALLOCATE;
+
+}
+#endif
+
+/******************************************************************************/
+/*!
+ * @name u8 process_stall_on_control(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with theStall event
+ * but USB2.0 Spec don't permit the Stall
+ * on Setup Stage of Control Transfer.
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+static u8 process_stall_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nak_on_control(ruct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the nak event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+static u8 process_nak_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+ }
+
+ 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(ruct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the ack event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+static u8 process_ack_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ * @brief this function deals with the nyet event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+static u8 process_nyet_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ 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_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ return RE_SCHEDULE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xacterr_on_control(ruct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the xacterr event
+ * 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.
+ * 3. unmasks ack/nak/datatglerr bit of HCINTMSK.
+ * 4. clears the xacterr bit of HCINT
+ * 5. calculates the size of the transferred data.
+ * 6. if the speed of USB Device is High-Speed, sets the ping protocol.
+ * 7. update the Data Toggle.
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -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
+ */
+/******************************************************************************/
+static u8 process_xacterr_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ 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_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ return ret_val;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name void process_bblerr_on_control(truct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the Babble event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ * NO_ACTION -if the direction is OUT
+ */
+/******************************************************************************/
+static u8 process_bblerr_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+
+ 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, hcinfo);
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_datatgl_on_control(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the datatglerr event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+static u8 process_datatgl_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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;
+
+}
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_chhltd_on_control(truct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function processes Channel Halt event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] hcinfo
+ * -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.
+ */
+/******************************************************************************/
+static u8 process_chhltd_on_control(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ if (hcinfo->hc_int.b.xfercompl)
+ return process_xfercompl_on_control(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.stall)
+ return process_stall_on_control(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.bblerr)
+ return process_bblerr_on_control(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.xacterr)
+ return process_xacterr_on_control(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.nak)
+ return process_nak_on_control(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.nyet)
+ return process_nyet_on_control(result_td, hcinfo);
+
+ 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_control_transfer(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ * @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 struct td to be mapped with the uChNum.
+ * [IN] ubChNum
+ * -indicates the number of the channel to be interrupted.
+ * [IN] hcinfo
+ * -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.
+ */
+/******************************************************************************/
+static u8 process_control_transfer(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ hcintn_t hcintr_info;
+ u8 ret_val = 0;
+
+ /* we just deal with the interrupts to be unmasked. */
+ hcintr_info.d32 = hcinfo->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, hcinfo);
+
+ else if (hcintr_info.b.ack)
+ ret_val = process_ack_on_control(result_td, hcinfo);
+
+ else if (hcintr_info.b.nak)
+ ret_val = process_nak_on_control(result_td, hcinfo);
+
+ else if (hcintr_info.b.datatglerr)
+ ret_val = process_datatgl_on_control(result_td, hcinfo);
+
+ } else {
+
+ if (hcintr_info.b.chhltd)
+ ret_val = process_chhltd_on_control(result_td, hcinfo);
+
+ else if (hcintr_info.b.ack)
+ ret_val = process_ack_on_control(result_td, hcinfo);
+ }
+
+ return ret_val;
+}
+
diff --git a/drivers/usb/host/shost/shost_transferchecker_interrupt.c b/drivers/usb/host/shost/shost_transferchecker_interrupt.c
new file mode 100644
index 0000000..fa85721
--- /dev/null
+++ b/drivers/usb/host/shost/shost_transferchecker_interrupt.c
@@ -0,0 +1,617 @@
+/****************************************************************************
+ * (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
+ ****************************************************************************/
+
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_xfercompl_on_intr( struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the xfercompl event
+ * 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 struct td 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.
+ */
+/******************************************************************************/
+static u8 process_xfercompl_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ u8 ret_val = 0;
+
+ result_td->err_cnt = 0;
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum, CH_STATUS_ALL);
+
+ 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, hcinfo);
+
+ 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 &&
+ hcinfo->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 {
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+ ret_val = RE_TRANSMIT;
+ }
+ }
+
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ return ret_val;
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ahb_on_intr(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with theAHB Errorl event
+ * this function stop the channel to be executed
+ *
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] HCRegData
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+/* TODO: not used. removed */
+#if 0
+static u8 process_ahb_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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_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, hcinfo);
+ result_td->parent_ed_p->ed_status.is_ping_enable = false;
+
+ return DE_ALLOCATE;
+
+}
+#endif
+
+/******************************************************************************/
+/*!
+ * @name u8 process_stall_on_intr(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the Stall event
+ * when Stall is occured at Int Transfer, we should reset the PID as DATA0
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td to be mapped with the uChNum.
+ * [IN] HCRegData
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+static u8 process_stall_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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_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, hcinfo);
+
+ update_data_toggle(result_td, DATA0);
+
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_nak_on_intr(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the nak event
+ * 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 struct td 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
+ */
+/******************************************************************************/
+static u8 process_nak_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ update_frame_number(result_td);
+
+ return RE_SCHEDULE;
+
+
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_ack_on_intr(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ *
+ * @brief this function deals with the ack event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] HCRegData
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return NO_ACTION
+ */
+/******************************************************************************/
+static u8 process_ack_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ * @brief this function deals with the xacterr event
+ * 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.
+ * 3. unmasks ack/nak/datatglerr bit of HCINTMSK.
+ * 4. clears the xacterr bit of HCINT
+ * 5. calculates the size of the transferred data.
+ * 6. update the Data Toggle.
+ * 7. update the frame number to start retransmitting
+ * the Interrupt Transfer.
+ *
+ * @param [IN] result_td
+ * -indicates the pointer of the struct td 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
+ */
+/******************************************************************************/
+static u8 process_xacterr_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ if (ret_val == RE_SCHEDULE)
+ update_frame_number(result_td);
+
+ return ret_val;
+}
+
+/******************************************************************************/
+/*!
+ * @name void process_bblerr_on_intr(struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ * @brief this function deals with the Babble event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] HCRegData
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return DE_ALLOCATE
+ */
+/******************************************************************************/
+static u8 process_bblerr_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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_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, hcinfo);
+ return DE_ALLOCATE;
+}
+
+/******************************************************************************/
+/*!
+ * @name u8 process_datatgl_on_intr( struct td *result_td,
+ * struct hc_info *hcinfo)
+ *
+ * @brief this function deals with the datatglerr event
+ * 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 struct td to be mapped with the uChNum.
+ * [IN] HCRegData
+ * -indicates the interrupt information of the Channel to be interrupted
+ *
+ * @return RE_SCHEDULE
+ */
+/******************************************************************************/
+static u8 process_datatgl_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ 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, hcinfo);
+
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ update_frame_number(result_td);
+
+ return RE_SCHEDULE;
+}
+
+static u8 process_frmovrrun_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum,
+ CH_STATUS_NAK);
+
+ update_data_toggle(result_td, hcinfo->hc_size.b.pid);
+
+ update_frame_number(result_td);
+
+ return RE_TRANSMIT;
+}
+
+
+/******************************************************************************/
+/*!
+ * @name u8 process_chhltd_on_intr(struct td *result_td,
+ * struct hc_info *HCRegData)
+ *
+ *
+ * @brief this function processes Channel Halt event
+ * 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 struct td 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.
+ */
+/******************************************************************************/
+static u8 process_chhltd_on_intr(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ if (result_td->parent_ed_p->ed_desc.is_ep_in) {
+ if (hcinfo->hc_int.b.xfercompl)
+ return process_xfercompl_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.stall)
+ return process_stall_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.bblerr)
+ return process_bblerr_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.nak)
+ return process_nak_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.datatglerr)
+ return process_datatgl_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.frmovrun)
+ return process_frmovrrun_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.xacterr)
+ return process_xacterr_on_intr(result_td, hcinfo);
+
+ else {
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum,
+ CH_STATUS_ALL);
+
+ 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 (hcinfo->hc_int.b.xfercompl)
+ return process_xfercompl_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.stall)
+ return process_stall_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.nak)
+ return process_nak_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.frmovrun)
+ return process_frmovrrun_on_intr(result_td, hcinfo);
+
+ else if (hcinfo->hc_int.b.xacterr)
+ return process_xacterr_on_intr(result_td, hcinfo);
+
+ else {
+ clear_ch_intr(result_td->cur_stransfer.alloc_chnum,
+ CH_STATUS_ALL);
+
+ 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_intr_transfer(struct td *result_td,
+ * struct hc_info *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 struct td 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,
+ */
+/******************************************************************************/
+static u8 process_intr_transfer(struct td *result_td,
+ struct hc_info *hcinfo)
+{
+ hcintn_t hc_intr_info;
+ u8 ret_val = 0;
+
+ hc_intr_info.d32 = hcinfo->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, hcinfo);
+
+ else if (hc_intr_info.b.ack)
+ ret_val = process_ack_on_intr(result_td, hcinfo);
+
+ } else {
+ if (hc_intr_info.b.chhltd)
+ ret_val = process_chhltd_on_intr(result_td, hcinfo);
+
+ else if (hc_intr_info.b.ack)
+ ret_val = process_ack_on_intr(result_td, hcinfo);
+ }
+
+ return ret_val;
+}
+
+