add ltq-hcd
authorJohn Crispin <john@openwrt.org>
Sat, 15 Dec 2012 01:59:53 +0000 (01:59 +0000)
committerJohn Crispin <john@openwrt.org>
Sat, 15 Dec 2012 01:59:53 +0000 (01:59 +0000)
SVN-Revision: 34688

18 files changed:
package/platform/lantiq/ltq-hcd/Makefile [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/Kconfig [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/Makefile [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxhcd.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxhcd.h [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_ctl.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_plat.h [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h [new file with mode: 0644]
package/platform/lantiq/ltq-hcd/src/ifxusb_version.h [new file with mode: 0644]

diff --git a/package/platform/lantiq/ltq-hcd/Makefile b/package/platform/lantiq/ltq-hcd/Makefile
new file mode 100644 (file)
index 0000000..6f654b4
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (C) 2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=ltq-hcd
+PKG_RELEASE:=1
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/ltq-hcd-$(BUILD_VARIANT)
+
+PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/ltq-hcd-template
+  SECTION:=sys
+  CATEGORY:=Kernel modules
+  SUBMENU:=USB Support
+  TITLE:=USB driver for $(1)
+  URL:=http://www.lantiq.com/
+  VARIANT:=$(1)
+  DEPENDS:=@TARGET_lantiq_$(2) +kmod-usb-core
+  FILES:=$(PKG_BUILD_DIR)/ltq_hcd_$(1).ko
+  AUTOLOAD:=$(call AutoLoad,50,ltq_hcd_$(1))
+endef
+
+KernelPackage/ltq-hcd-ase=$(call KernelPackage/ltq-hcd-template,ase,ase)
+KernelPackage/ltq-hcd-danube=$(call KernelPackage/ltq-hcd-template,danube,xway)
+KernelPackage/ltq-hcd-ar9=$(call KernelPackage/ltq-hcd-template,ar9,xway)
+KernelPackage/ltq-hcd-vr9=$(call KernelPackage/ltq-hcd-template,vr9,xway)
+
+define Build/Prepare
+       $(INSTALL_DIR) $(PKG_BUILD_DIR)
+       $(CP) ./src/* $(PKG_BUILD_DIR)
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+       cd $(LINUX_DIR); \
+               ARCH=mips CROSS_COMPILE="$(KERNEL_CROSS)" \
+               $(MAKE) BUILD_VARIANT=$(BUILD_VARIANT) M=$(PKG_BUILD_DIR) V=1 modules
+endef
+
+$(eval $(call KernelPackage,ltq-hcd-ase))
+$(eval $(call KernelPackage,ltq-hcd-danube))
+$(eval $(call KernelPackage,ltq-hcd-ar9))
+$(eval $(call KernelPackage,ltq-hcd-vr9))
diff --git a/package/platform/lantiq/ltq-hcd/src/Kconfig b/package/platform/lantiq/ltq-hcd/src/Kconfig
new file mode 100644 (file)
index 0000000..2a3a38d
--- /dev/null
@@ -0,0 +1,104 @@
+
+config USB_HOST_IFX
+       tristate "Infineon USB Host Controller Driver"
+       depends on USB
+       default n
+       help
+       Infineon USB Host Controller
+
+choice
+       prompt "Infineon USB Host Controller Driver Operation mode"
+       depends on USB_HOST_IFX && ( AMAZON_S || AR9 || VR9 || AR10 ||  MIPS_AMAZON_S || MIPS_AR9 || MIPS_VR9 || MIPS_AR10 )
+       help
+          The IFX USB core can be configured as dual-host and single host.
+          The unused core can be set as Device-mode.
+
+config USB_HOST_IFX_B
+       boolean "USB host mode on core 1 and 2"
+       help
+       Both cores run as host
+
+config USB_HOST_IFX_1
+       boolean "USB host mode on core 1 only"
+       help
+       Core #1 runs as host
+
+config USB_HOST_IFX_2
+       boolean "USB host mode on core 2 only"
+       help
+       Core #2 runs as host
+
+endchoice
+
+config USB_HOST_IFX_FORCE_USB11
+       boolean "Forced USB1.1"
+       depends on USB_HOST_IFX
+       default n
+       help
+       force to be USB 1.1
+
+config USB_HOST_IFX_WITH_HS_ELECT_TST
+       boolean "With HS_Electrical Test"
+       depends on USB_HOST_IFX
+       default n
+       help
+       With USBIF HSET routines
+
+config USB_HOST_IFX_WITH_ISO
+       boolean "With ISO transfer"
+       depends on USB_HOST_IFX
+       default n
+       help
+       With USBIF ISO transfer
+
+config USB_HOST_IFX_COC
+       boolean "CoC in USB Host"
+       depends on USB_HOST_IFX
+       default n
+       help
+       With CoC on Host
+
+choice
+       prompt "IFX unaligned buffer policy"
+       depends on USB_HOST_IFX
+       help
+          IFX unaligned buffer policy
+
+config USB_HOST_IFX_UNALIGNED_ADJ
+       boolean "Adjust"
+       help
+       USB_HOST_IFX_UNALIGNED_ADJ
+
+config USB_HOST_IFX_UNALIGNED_CHK
+       boolean "Check-only"
+       help
+       USB_HOST_IFX_UNALIGNED_CHK
+
+config USB_HOST_IFX_UNALIGNED_NONE
+       boolean "No process"
+       help
+       USB_HOST_IFX_UNALIGNED_NONE
+
+endchoice
+
+
+config USB_HOST_IFX_XHCI
+        tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
+        depends on USB && PCI && ( VR9 || MIPS_VR9 || AR10 || MIPS_AR10 )
+        ---help---
+          The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
+          "SuperSpeed" host controller hardware.
+
+          To compile this driver as a module, choose M here: the
+          module will be called xhci-hcd.
+
+config USB_HOST_IFX_XHCI_DEBUGGING
+        bool "Debugging for the xHCI host controller"
+        depends on USB_HOST_IFX_XHCI
+        ---help---
+          Say 'Y' to turn on debugging for the xHCI host controller driver.
+          This will spew debugging output, even in interrupt context.
+          This should only be used for debugging xHCI driver bugs.
+
+          If unsure, say N.
+
diff --git a/package/platform/lantiq/ltq-hcd/src/Makefile b/package/platform/lantiq/ltq-hcd/src/Makefile
new file mode 100644 (file)
index 0000000..153fd42
--- /dev/null
@@ -0,0 +1,74 @@
+ltq_hcd_$(BUILD_VARIANT)-objs    := ifxusb_driver.o ifxusb_ctl.o ifxusb_cif.o \
+                       ifxusb_cif_h.o ifxhcd.o ifxhcd_es.o \
+                       ifxhcd_intr.o ifxhcd_queue.o
+obj-m = ltq_hcd_$(BUILD_VARIANT).o
+
+ifeq ($(BUILD_VARIANT),danube)
+  EXTRA_CFLAGS += -D__IS_DANUBE__
+endif
+
+ifeq ($(BUILD_VARIANT),ase)
+  EXTRA_CFLAGS += -D__IS_AMAZON_SE__
+endif
+
+ifeq ($(BUILD_VARIANT),ar9)
+  EXTRA_CFLAGS += -D__IS_AR9__
+  EXTRA_CFLAGS += -D__IS_DUAL__
+endif
+
+ifeq ($(BUILD_VARIANT),vr9)
+  EXTRA_CFLAGS += -D__IS_VR9__
+  EXTRA_CFLAGS += -D__PHY_LONG_PREEMP__
+  EXTRA_CFLAGS += -D__PINGSTOP_CTRL__
+  EXTRA_CFLAGS += -D__PINGSTOP_BULK__
+  EXTRA_CFLAGS += -D__IS_DUAL__
+endif
+
+ifeq ($(BUILD_VARIANT),ar10)
+  EXTRA_CFLAGS += -D__IS_AR10__
+  EXTRA_CFLAGS += -D__PHY_LONG_PREEMP__
+  EXTRA_CFLAGS += -D__PINGSTOP_CTRL__
+  EXTRA_CFLAGS += -D__PINGSTOP_BULK__
+endif
+
+ifeq ($(CONFIG_USB_HOST_IFX_FORCE_USB11),y)
+  EXTRA_CFLAGS  += -D__FORCE_USB11__
+endif
+ifeq ($(CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST),y)
+  EXTRA_CFLAGS  += -D__WITH_HS_ELECT_TST__
+endif
+ifeq ($(CONFIG_USB_HOST_IFX_WITH_ISO),y)
+  EXTRA_CFLAGS  += -D__EN_ISOC__
+endif
+#ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_ADJ),y)
+  EXTRA_CFLAGS  += -D__UNALIGNED_BUF_ADJ__
+#endif
+ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_CHK),y)
+  EXTRA_CFLAGS  += -D__UNALIGNED_BUF_CHK__
+endif
+ifeq ($(CONFIG_USB_HOST_IFX_COC),y)
+  EXTRA_CFLAGS  += -D__HOST_COC__
+endif
+
+# EXTRA_CFLAGS  += -D__IS_FIRST__
+# EXTRA_CFLAGS  += -D__IS_SECOND__
+
+# EXTRA_CFLAGS  += -D__EN_ISOC__
+# EXTRA_CFLAGS  += -D__EN_ISOC_SPLIT__
+# EXTRA_CFLAGS  += -D__EPQD_DESTROY_TIMEOUT__
+# EXTRA_CFLAGS  += -D__INNAKSTOP_CTRL__
+
+EXTRA_CFLAGS += -Dlinux -D__LINUX__
+EXTRA_CFLAGS += -D__IS_HOST__
+EXTRA_CFLAGS += -D__KERNEL__
+#EXTRA_CFLAGS += -D__DEBUG__
+#EXTRA_CFLAGS += -D__ENABLE_DUMP__
+
+EXTRA_CFLAGS += -D__DYN_SOF_INTR__
+EXTRA_CFLAGS += -D__UEIP__
+EXTRA_CFLAGS += -D__DO_OC_INT__
+EXTRA_CFLAGS += -D__INNAKSTOP_BULK__
+
+EXTRA_CFLAGS += -D__INTRNAKRETRY__
+EXTRA_CFLAGS += -D__INTRINCRETRY__
+
diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd.c
new file mode 100644 (file)
index 0000000..6d1551f
--- /dev/null
@@ -0,0 +1,2141 @@
+/*****************************************************************************
+ **   FILE NAME       : ifxhcd.c
+ **   PROJECT         : IFX USB sub-system V3
+ **   MODULES         : IFX USB sub-system Host and Device driver
+ **   SRC VERSION     : 3.2
+ **   DATE            : 1/Jan/2011
+ **   AUTHOR          : Chen, Howard
+ **   DESCRIPTION     : This file contains the structures, constants, and
+ **                     interfaces for the Host Contoller Driver (HCD).
+ **
+ **                     The Host Controller Driver (HCD) is responsible for
+ **                     translating requests from the USB Driver into the
+ **                     appropriate actions on the IFXUSB controller.
+ **                     It isolates the USBD from the specifics of the
+ **                     controller by providing an API to the USBD.
+ **   FUNCTIONS       :
+ **   COMPILER        : gcc
+ **   REFERENCE       : Synopsys DWC-OTG Driver 2.7
+ **   COPYRIGHT       :  Copyright (c) 2010
+ **                      LANTIQ DEUTSCHLAND GMBH,
+ **                      Am Campeon 3, 85579 Neubiberg, Germany
+ **
+ **    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.
+ **
+ **  Version Control Section  **
+ **   $Author$
+ **   $Date$
+ **   $Revisions$
+ **   $Log$       Revision history
+ *****************************************************************************/
+
+/*
+ * This file contains code fragments from Synopsys HS OTG Linux Software Driver.
+ * For this code the following notice is applicable:
+ *
+ * ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/*!
+  \file ifxhcd.c
+  \ingroup IFXUSB_DRIVER_V3
+  \brief This file contains the implementation of the HCD. In Linux,
+   the HCD implements the hc_driver API.
+*/
+
+#include <linux/version.h>
+#include "ifxusb_version.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <linux/device.h>
+
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+
+#include <linux/dma-mapping.h>
+
+
+#include "ifxusb_plat.h"
+#include "ifxusb_regs.h"
+#include "ifxusb_cif.h"
+#include "ifxhcd.h"
+
+#include <asm/irq.h>
+
+#ifdef __DEBUG__
+       static void dump_urb_info(struct urb *_urb, char* _fn_name);
+#if 0
+       static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd,
+                                     ifxhcd_epqh_t *_epqh);
+#endif
+#endif
+
+static void ifxhcd_complete_urb_sub(ifxhcd_urbd_t *_urbd)
+{
+       ifxhcd_hcd_t *ifxhcd;
+       struct urb *urb=NULL;
+
+       if (!list_empty(&_urbd->ql))
+       {
+               list_del_init(&_urbd->ql);
+               _urbd->epqh->urbd_count--;
+       }
+       else
+               IFX_ERROR("%s: urb(%p) not connect to any epqh\n",
+                         __func__,_urbd);
+
+       ifxhcd=_urbd->epqh->ifxhcd;
+       urb   =_urbd->urb;
+       if(!urb)
+               IFX_ERROR("%s: invalid urb\n",__func__);
+       else if(urb->hcpriv)
+       {
+               if(urb->hcpriv != _urbd)
+                       IFX_ERROR("%s: invalid"
+                                 " urb(%p)->hcpriv(%p) != _urbd(%p)\n",
+                                 __func__,
+                                 urb,
+                                 urb->hcpriv,
+                                 _urbd);
+               #if   defined(__UNALIGNED_BUF_ADJ__)
+                       if(_urbd->is_in &&
+//                        _urbd->using_aligned_buf &&
+                          _urbd->aligned_buf)
+                               memcpy(_urbd->xfer_buff,
+                                      _urbd->aligned_buf,
+                                      _urbd->xfer_len);
+                       if(_urbd->aligned_buf)
+                               ifxusb_free_buf_h(_urbd->aligned_buf);
+               #endif
+               urb->hcpriv = NULL;
+               #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+                       urb->status=_urbd->status;
+                       usb_hcd_giveback_urb(ifxhcd_to_syshcd(ifxhcd), urb);
+               #else
+                       usb_hcd_giveback_urb(ifxhcd_to_syshcd(ifxhcd), urb,
+                                            _urbd->status);
+               #endif
+       }
+       kfree(_urbd);
+}
+
+#ifdef __STRICT_ORDER__
+       static void ifxhcd_complete_urb_func(unsigned long data)
+       {
+               unsigned long             flags;
+               ifxhcd_urbd_t *urbd;
+               ifxhcd_epqh_t *epqh;
+               struct list_head *item;
+
+               int count=10;
+
+               epqh=((ifxhcd_epqh_t *)data);
+
+               while (!list_empty(&epqh->release_list) && count)
+               {
+                       item = epqh->release_list.next;
+                       urbd = list_entry(item, ifxhcd_urbd_t, ql);
+                       if (!urbd)
+                               IFX_ERROR("%s: invalid urbd\n",__func__);
+                       else if (!urbd->epqh)
+                               IFX_ERROR("%s: invalid epqd\n",__func__);
+                       else
+                       {
+                               ifxhcd_epqh_t *epqh2;
+                               epqh2=urbd->epqh;
+                               local_irq_save(flags);
+                               LOCK_URBD_LIST(epqh2);
+                               ifxhcd_complete_urb_sub(urbd);
+                               UNLOCK_URBD_LIST(epqh2);
+                               local_irq_restore (flags);
+                       }
+                       count--;
+               }
+               if(!list_empty(&epqh->release_list))
+                       tasklet_schedule(&epqh->complete_urb_sub);
+       }
+
+       /*!
+        \brief Sets the final status of an URB and returns it to the device
+         driver. Any required cleanup of the URB is performed.
+        */
+       void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd,
+                                ifxhcd_urbd_t *_urbd,
+                                int _status)
+       {
+               unsigned long             flags;
+
+               if(!_urbd)
+               {
+                       IFX_ERROR("%s: invalid urbd\n",__func__);
+                       return;
+               }
+               if (!_urbd->epqh)
+               {
+                       IFX_ERROR("%s: invalid epqh\n",__func__);
+                       return;
+               }
+
+               local_irq_save(flags);
+               LOCK_URBD_LIST(_urbd->epqh);
+               #ifdef __DEBUG__
+                       if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB))
+                       {
+                               IFX_PRINT("%s: ehqh %p _urbd %p, urb %p,"
+                                         " device %d, ep %d %s/%s, status=%d\n",
+                                         __func__,_urbd->epqh,
+                                         _urbd,_urbd->urb,
+                                         (_urbd->urb)?usb_pipedevice(_urbd->urb->pipe):-1,
+                                         (_urbd->urb)?usb_pipeendpoint(_urbd->urb->pipe):-1,
+                                         (_urbd->urb)?(usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT"):"--",
+                                         (_urbd->is_in) ? "IN" : "OUT",
+                                          _status);
+                               if ((_urbd->urb)&& _urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
+                               {
+                                       int i;
+                                       for (i = 0; i < _urbd->urb->number_of_packets; i++)
+                                               IFX_PRINT("  ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status);
+                               }
+                       }
+               #endif
+               _urbd->status = _status;
+
+               if(_urbd->phase!=URBD_FINISHING)
+               {
+                       if(_urbd->phase!=URBD_DEQUEUEING && _urbd->phase!=URBD_COMPLETING)
+                               printk(KERN_INFO "Warning: %s() Strange URBD PHASE %d\n",__func__,_urbd->phase);
+                       if(_urbd->urb)
+                       {
+                               if(   _urbd->status == 0
+                                  && _urbd->phase==URBD_COMPLETING
+                                  && in_irq())
+                               {
+                                       list_move_tail(&_urbd->ql,&_urbd->epqh->release_list);
+                                       if(!_urbd->epqh->complete_urb_sub.func)
+                                       {
+                                               _urbd->epqh->complete_urb_sub.next = NULL;
+                                               _urbd->epqh->complete_urb_sub.state = 0;
+                                               atomic_set( &_urbd->epqh->complete_urb_sub.count, 0);
+                                               _urbd->epqh->complete_urb_sub.func = ifxhcd_complete_urb_func;
+                                               _urbd->epqh->complete_urb_sub.data = (unsigned long)_urbd->epqh;
+                                       }
+                                       tasklet_schedule(&_urbd->epqh->complete_urb_sub);
+                               }
+                               else
+                               {
+                                       _urbd->phase=URBD_FINISHING;
+                                       ifxhcd_complete_urb_sub(_urbd);
+                               }
+                               UNLOCK_URBD_LIST(_urbd->epqh);
+                       }
+                       else
+                       {
+                               UNLOCK_URBD_LIST(_urbd->epqh);
+                               kfree(_urbd);
+                       }
+               }
+               else
+               {
+                       printk(KERN_INFO "Warning: %s() Double Completing \n",__func__);
+                       UNLOCK_URBD_LIST(_urbd->epqh);
+               }
+               
+               local_irq_restore (flags);
+       }
+#else
+       static void ifxhcd_complete_urb_func(unsigned long data)
+       {
+               unsigned long             flags;
+               ifxhcd_urbd_t *urbd;
+
+               urbd=((ifxhcd_urbd_t *)data);
+
+       //      local_irq_save(flags);
+               if (!urbd)
+                       IFX_ERROR("%s: invalid urbd\n",__func__);
+               else if (!urbd->epqh)
+                       IFX_ERROR("%s: invalid epqd\n",__func__);
+               else
+               {
+                       local_irq_save(flags);
+                       LOCK_URBD_LIST(urbd->epqh);
+                       ifxhcd_complete_urb_sub(urbd);
+                       UNLOCK_URBD_LIST(urbd->epqh);
+                       local_irq_restore (flags);
+               }
+       //      local_irq_restore (flags);
+       }
+
+
+       /*!
+        \brief Sets the final status of an URB and returns it to the device driver. Any
+         required cleanup of the URB is performed.
+        */
+       void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd,  int _status)
+       {
+               unsigned long             flags;
+
+               if(!_urbd)
+               {
+                       IFX_ERROR("%s: invalid urbd\n",__func__);
+                       return;
+               }
+               if (!_urbd->epqh)
+               {
+                       IFX_ERROR("%s: invalid epqh\n",__func__);
+                       return;
+               }
+
+               local_irq_save(flags);
+               LOCK_URBD_LIST(_urbd->epqh);
+               #ifdef __DEBUG__
+                       if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB))
+                       {
+                               IFX_PRINT("%s: ehqh %p _urbd %p, urb %p, device %d, ep %d %s/%s, status=%d\n",
+                                         __func__,_urbd->epqh, _urbd,_urbd->urb,
+                                         (_urbd->urb)?usb_pipedevice(_urbd->urb->pipe):-1,
+                                         (_urbd->urb)?usb_pipeendpoint(_urbd->urb->pipe):-1,
+                                         (_urbd->urb)?(usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT"):"--",
+                                         (_urbd->is_in) ? "IN" : "OUT",
+                                          _status);
+                               if ((_urbd->urb)&& _urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
+                               {
+                                       int i;
+                                       for (i = 0; i < _urbd->urb->number_of_packets; i++)
+                                               IFX_PRINT("  ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status);
+                               }
+                       }
+               #endif
+               _urbd->status = _status;
+
+               if(_urbd->phase!=URBD_FINISHING)
+               {
+                       if(_urbd->phase!=URBD_DEQUEUEING && _urbd->phase!=URBD_COMPLETING)
+                               printk(KERN_INFO "Warning: %s() Strange URBD PHASE %d\n",__func__,_urbd->phase);
+                       if(_urbd->urb)
+                       {
+                               if(   _urbd->status == 0
+                                  && _urbd->phase==URBD_COMPLETING
+                                  && in_irq())
+                               {
+                                       if(_urbd->complete_urb_sub.func)
+                                               printk(KERN_INFO "Warning: %s() URBD Tasklet is on already\n",__func__);
+                                       _urbd->phase=URBD_FINISHING;
+                                       _urbd->complete_urb_sub.next = NULL;
+                                       _urbd->complete_urb_sub.state = 0;
+                                       atomic_set( &_urbd->complete_urb_sub.count, 0);
+                                       _urbd->complete_urb_sub.func = ifxhcd_complete_urb_func;
+                                       _urbd->complete_urb_sub.data = (unsigned long)_urbd;
+                                       tasklet_schedule(&_urbd->complete_urb_sub);
+                               }
+                               else
+                               {
+                                       _urbd->phase=URBD_FINISHING;
+                                       ifxhcd_complete_urb_sub(_urbd);
+                               }
+                       }
+                       else
+                               kfree(_urbd);
+               }
+               else
+                       printk(KERN_INFO "Warning: %s() Double Completing \n",__func__);
+               UNLOCK_URBD_LIST(_urbd->epqh);
+               local_irq_restore (flags);
+       }
+#endif
+
+/*!
+ \brief Processes all the URBs in a single EPQHs. Completes them with
+        status and frees the URBD.
+ */
+static
+void kill_all_urbs_in_epqh(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh, int _status)
+{
+       struct list_head *item;
+       struct list_head *next;
+       ifxhcd_urbd_t    *urbd;
+
+       if(!_epqh)
+               return;
+
+       IFX_DEBUGPL(DBG_HCDV, "%s %p\n",__func__,_epqh);
+       LOCK_URBD_LIST(_epqh);
+       list_for_each(item, &_epqh->urbd_list)
+       {
+               urbd = list_entry(item, ifxhcd_urbd_t, ql);
+               if(   urbd->phase==URBD_IDLE
+                  || urbd->phase==URBD_ACTIVE
+//                || urbd->phase==URBD_STARTING
+                 )
+                       urbd->phase=URBD_DEQUEUEING;
+       }
+       list_for_each_safe(item, next, &_epqh->urbd_list)
+       {
+               urbd = list_entry(item, ifxhcd_urbd_t, ql);
+               if(urbd->phase==URBD_DEQUEUEING)
+               {
+                       urbd->urb->status = _status;
+                       urbd->phase = URBD_FINISHING;
+                       ifxhcd_complete_urb_sub(urbd);
+               }
+               else if(   urbd->phase==URBD_STARTED
+                       || urbd->phase==URBD_STARTING
+//                     || urbd->phase==URBD_ACTIVE
+                      )
+               {
+                       if(ifxhcd_hc_halt(&_ifxhcd->core_if, _epqh->hc, HC_XFER_URB_DEQUEUE))
+                       {
+                               urbd->urb->status = _status;
+                               urbd->phase=URBD_FINISHING;
+                               ifxhcd_complete_urb_sub(urbd);
+                       }
+               }
+               else
+                       IFX_ERROR("%s: invalid urb phase:%d \n",__func__,urbd->phase);
+       }
+       UNLOCK_URBD_LIST(_epqh);
+       IFX_DEBUGPL(DBG_HCDV, "%s %p finish\n",__func__,_epqh);
+}
+
+
+/*!
+ \brief Free all EPS in one Processes all the URBs in a single list of EPQHs. Completes them with
+        -ETIMEDOUT and frees the URBD.
+ */
+static
+void epqh_list_free_1(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list)
+{
+       ifxhcd_epqh_t    *epqh;
+       struct list_head *item;
+       if (!_ifxhcd)
+               return;
+       if (!_epqh_list)
+               return;
+
+       IFX_DEBUGPL(DBG_HCDV, "%s %p\n",__func__,_epqh_list);
+
+       item = _epqh_list->next;
+       while(item != _epqh_list && item != item->next)
+       {
+               epqh = list_entry(item, ifxhcd_epqh_t, ql);
+               epqh->phase=EPQH_DISABLING;
+               item = item->next;
+               kill_all_urbs_in_epqh(_ifxhcd, epqh, -ETIMEDOUT);
+               #ifdef __STRICT_ORDER__
+               if(list_empty(&epqh->urbd_list) && list_empty(&epqh->release_list))
+               #else
+               if(list_empty(&epqh->urbd_list))
+               #endif
+                       ifxhcd_epqh_free(epqh);
+       }
+       IFX_DEBUGPL(DBG_HCDV, "%s %p finish\n",__func__,_epqh_list);
+       /* Ensure there are no URBDs or URBs left. */
+}
+
+static
+void epqh_list_free_2(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list)
+{
+       ifxhcd_epqh_t    *epqh;
+       struct list_head *item;
+       struct list_head *next;
+       if (!_ifxhcd)
+               return;
+       if (!_epqh_list)
+               return;
+
+       IFX_DEBUGPL(DBG_HCDV, "%s %p\n",__func__,_epqh_list);
+       list_for_each_safe(item, next, _epqh_list)
+       {
+               epqh = list_entry(item, ifxhcd_epqh_t, ql);
+               if(item == item->next)
+               {
+                       ifxhcd_epqh_free(epqh);
+               }
+               else
+               {
+                       uint32_t count=0x80000;
+                       #ifdef __STRICT_ORDER__
+                       for(;(!list_empty(&epqh->urbd_list) || !list_empty(&epqh->release_list))&& count> 0; count--) udelay(1);
+                       #else
+                       for(;!list_empty(&epqh->urbd_list) && count> 0; count--) udelay(1);
+                       #endif
+                       if(!count)
+                               IFX_ERROR("%s: unable to clear urbd in epqh \n",__func__);
+                       ifxhcd_epqh_free(epqh);
+               }
+       }
+       IFX_DEBUGPL(DBG_HCDV, "%s %p finish\n",__func__,_epqh_list);
+       /* Ensure there are no URBDs or URBs left. */
+}
+
+static
+void epqh_list_free_all_sub(unsigned long data)
+{
+       ifxhcd_hcd_t *ifxhcd;
+
+       ifxhcd=(ifxhcd_hcd_t *)data;
+       epqh_list_free_1(ifxhcd, &ifxhcd->epqh_list_np  );
+       epqh_list_free_1(ifxhcd, &ifxhcd->epqh_list_intr);
+       #ifdef __EN_ISOC__
+               epqh_list_free_1(ifxhcd, &ifxhcd->epqh_list_isoc);
+       #endif
+
+       epqh_list_free_2(ifxhcd, &ifxhcd->epqh_list_np  );
+       epqh_list_free_2(ifxhcd, &ifxhcd->epqh_list_intr);
+       #ifdef __EN_ISOC__
+               epqh_list_free_2(ifxhcd, &ifxhcd->epqh_list_isoc);
+       #endif
+}
+
+static
+void epqh_list_free_all(ifxhcd_hcd_t *_ifxhcd)
+{
+       _ifxhcd->tasklet_free_epqh_list.next = NULL;
+       _ifxhcd->tasklet_free_epqh_list.state = 0;
+       atomic_set( &_ifxhcd->tasklet_free_epqh_list.count, 0);
+       _ifxhcd->tasklet_free_epqh_list.func=epqh_list_free_all_sub;
+       _ifxhcd->tasklet_free_epqh_list.data = (unsigned long)_ifxhcd;
+       tasklet_schedule(&_ifxhcd->tasklet_free_epqh_list);
+}
+
+
+/*!
+   \brief This function is called to handle the disconnection of host port.
+ */
+int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd)
+{
+       IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _ifxhcd);
+
+       _ifxhcd->disconnecting=1;
+       /* Set status flags for the hub driver. */
+       _ifxhcd->flags.b.port_connect_status_change = 1;
+       _ifxhcd->flags.b.port_connect_status = 0;
+
+       /*
+        * Shutdown any transfers in process by clearing the Tx FIFO Empty
+        * interrupt mask and status bits and disabling subsequent host
+        * channel interrupts.
+        */
+        {
+               gint_data_t intr = { .d32 = 0 };
+               intr.b.nptxfempty = 1;
+               intr.b.ptxfempty  = 1;
+               intr.b.hcintr     = 1;
+               ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintmsk, intr.d32, 0);
+               ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintsts, intr.d32, 0);
+       }
+
+       /* Respond with an error status to all URBs in the schedule. */
+       epqh_list_free_all(_ifxhcd);
+
+       /* Clean up any host channels that were in use. */
+       {
+               int               num_channels;
+               ifxhcd_hc_t      *channel;
+               ifxusb_hc_regs_t *hc_regs;
+               hcchar_data_t     hcchar;
+               int                   i;
+
+               num_channels = _ifxhcd->core_if.params.host_channels;
+
+               for (i = 0; i < num_channels; i++)
+               {
+                       channel = &_ifxhcd->ifxhc[i];
+                       hc_regs = _ifxhcd->core_if.hc_regs[i];
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       if (hcchar.b.chen)
+                               printk(KERN_INFO "Warning: %s() HC still enabled\n",__func__);
+                       ifxhcd_hc_cleanup(&_ifxhcd->core_if, channel);
+               }
+       }
+       IFX_DEBUGPL(DBG_HCDV, "%s(%p) finish\n", __func__, _ifxhcd);
+       return 1;
+}
+
+
+/*!
+   \brief Frees secondary storage associated with the ifxhcd_hcd structure contained
+          in the struct usb_hcd field.
+ */
+static void ifxhcd_freeextra(struct usb_hcd *_syshcd)
+{
+       ifxhcd_hcd_t    *ifxhcd = syshcd_to_ifxhcd(_syshcd);
+
+       IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD FREE\n");
+
+       /* Free memory for EPQH/URBD lists */
+       epqh_list_free_all(ifxhcd);
+
+       /* Free memory for the host channels. */
+       ifxusb_free_buf_h(ifxhcd->status_buf);
+       return;
+}
+
+/*!
+   \brief Initializes the HCD. This function allocates memory for and initializes the
+  static parts of the usb_hcd and ifxhcd_hcd structures. It also registers the
+  USB bus with the core and calls the hc_driver->start() function. It returns
+  a negative error on failure.
+ */
+int ifxhcd_init(ifxhcd_hcd_t *_ifxhcd)
+{
+       int retval = 0;
+       struct usb_hcd *syshcd = NULL;
+
+       IFX_DEBUGPL(DBG_HCD, "IFX USB HCD INIT\n");
+
+       INIT_EPQH_LIST_ALL(_ifxhcd);
+       INIT_EPQH_LIST(_ifxhcd);
+
+       init_timer(&_ifxhcd->autoprobe_timer);
+       init_timer(&_ifxhcd->host_probe_timer);
+       _ifxhcd->probe_sec = 5;
+       _ifxhcd->autoprobe_sec = 30;
+
+       _ifxhcd->hc_driver.description      = _ifxhcd->core_if.core_name;
+       _ifxhcd->hc_driver.product_desc     = "IFX USB Controller";
+       //_ifxhcd->hc_driver.hcd_priv_size    = sizeof(ifxhcd_hcd_t);
+       _ifxhcd->hc_driver.hcd_priv_size    = sizeof(unsigned long);
+       _ifxhcd->hc_driver.irq              = ifxhcd_irq;
+       _ifxhcd->hc_driver.flags            = HCD_MEMORY | HCD_USB2;
+       _ifxhcd->hc_driver.start            = ifxhcd_start;
+       _ifxhcd->hc_driver.stop             = ifxhcd_stop;
+       //_ifxhcd->hc_driver.reset          =
+       //_ifxhcd->hc_driver.suspend        =
+       //_ifxhcd->hc_driver.resume         =
+       _ifxhcd->hc_driver.urb_enqueue      = ifxhcd_urb_enqueue;
+       _ifxhcd->hc_driver.urb_dequeue      = ifxhcd_urb_dequeue;
+       _ifxhcd->hc_driver.endpoint_disable = ifxhcd_endpoint_disable;
+       _ifxhcd->hc_driver.get_frame_number = ifxhcd_get_frame_number;
+       _ifxhcd->hc_driver.hub_status_data  = ifxhcd_hub_status_data;
+       _ifxhcd->hc_driver.hub_control      = ifxhcd_hub_control;
+       //_ifxhcd->hc_driver.hub_suspend    =
+       //_ifxhcd->hc_driver.hub_resume     =
+       _ifxhcd->pkt_remaining_reload_hs=PKT_REMAINING_RELOAD_HS;
+       _ifxhcd->pkt_remaining_reload_fs=PKT_REMAINING_RELOAD_FS;
+       _ifxhcd->pkt_remaining_reload_ls=PKT_REMAINING_RELOAD_LS;
+       _ifxhcd->pkt_count_limit_bo         =8;
+       _ifxhcd->pkt_count_limit_bi         =8;
+
+       /* Allocate memory for and initialize the base HCD and  */
+       //syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->dev->bus_id);
+       syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->core_if.core_name);
+
+       if (syshcd == NULL)
+       {
+               retval = -ENOMEM;
+               goto error1;
+       }
+
+       syshcd->rsrc_start = (unsigned long)_ifxhcd->core_if.core_global_regs;
+       syshcd->regs       = (void *)_ifxhcd->core_if.core_global_regs;
+       syshcd->self.otg_port = 0;
+
+       //*((unsigned long *)(&(syshcd->hcd_priv)))=(unsigned long)_ifxhcd;
+       //*((unsigned long *)(&(syshcd->hcd_priv[0])))=(unsigned long)_ifxhcd;
+       syshcd->hcd_priv[0]=(unsigned long)_ifxhcd;
+       _ifxhcd->syshcd=syshcd;
+       INIT_LIST_HEAD(&_ifxhcd->epqh_list_all   );
+       INIT_LIST_HEAD(&_ifxhcd->epqh_list_np    );
+       INIT_LIST_HEAD(&_ifxhcd->epqh_list_intr  );
+       #ifdef __EN_ISOC__
+               INIT_LIST_HEAD(&_ifxhcd->epqh_list_isoc);
+       #endif
+
+       /*
+        * Create a host channel descriptor for each host channel implemented
+        * in the controller. Initialize the channel descriptor array.
+        */
+       {
+               int          num_channels = _ifxhcd->core_if.params.host_channels;
+               int i;
+               for (i = 0; i < num_channels; i++)
+               {
+                       _ifxhcd->ifxhc[i].hc_num = i;
+                       IFX_DEBUGPL(DBG_HCDV, "HCD Added channel #%d\n", i);
+               }
+       }
+
+       /* Set device flags indicating whether the HCD supports DMA. */
+       if(_ifxhcd->dev->dma_mask)
+               *(_ifxhcd->dev->dma_mask) = ~0;
+       _ifxhcd->dev->coherent_dma_mask = ~0;
+
+       /*
+        * 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 ifxusb_hcd_start method.
+        */
+       retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, 0
+                                                          |IRQF_DISABLED
+                                                          |IRQF_SHARED
+                                                          );
+       if (retval < 0)
+               goto error2;
+
+       /*
+        * Allocate space for storing data on status transactions. Normally no
+        * data is sent, but this space acts as a bit bucket. This must be
+        * done after usb_add_hcd since that function allocates the DMA buffer
+        * pool.
+        */
+       _ifxhcd->status_buf = ifxusb_alloc_buf_h(IFXHCD_STATUS_BUF_SIZE, 1);
+
+       if (_ifxhcd->status_buf)
+       {
+               IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->core_if.core_name, syshcd->self.busnum);
+               return 0;
+       }
+       IFX_ERROR("%s: status_buf allocation failed\n", __func__);
+
+       /* Error conditions */
+       usb_remove_hcd(syshcd);
+error2:
+       ifxhcd_freeextra(syshcd);
+       usb_put_hcd(syshcd);
+error1:
+       return retval;
+}
+
+/*!
+   \brief Removes the HCD.
+  Frees memory and resources associated with the HCD and deregisters the bus.
+ */
+void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd)
+{
+       struct usb_hcd *syshcd = ifxhcd_to_syshcd(_ifxhcd);
+
+       IFX_DEBUGPL(DBG_HCD, "IFX USB HCD REMOVE\n");
+
+       /* Turn off all interrupts */
+       ifxusb_wreg (&_ifxhcd->core_if.core_global_regs->gintmsk, 0);
+       ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gahbcfg, 1, 0);
+
+       usb_remove_hcd(syshcd);
+       ifxhcd_freeextra(syshcd);
+       usb_put_hcd(syshcd);
+
+       return;
+}
+
+
+/* =========================================================================
+ *  Linux HC Driver Functions
+ * ========================================================================= */
+
+/*!
+   \brief Initializes the IFXUSB controller and its root hub and prepares it for host
+ mode operation. Activates the root port. Returns 0 on success and a negative
+ error code on failure.
+ Called by USB stack.
+ */
+int ifxhcd_start(struct usb_hcd *_syshcd)
+{
+       ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd);
+       ifxusb_core_if_t *core_if = &ifxhcd->core_if;
+       struct usb_bus *bus;
+
+       IFX_DEBUGPL(DBG_HCD, "IFX USB HCD START\n");
+
+       bus = hcd_to_bus(_syshcd);
+
+       /* Initialize the bus state.  */
+       _syshcd->state = HC_STATE_RUNNING;
+
+       /* Initialize and connect root hub if one is not already attached */
+       if (bus->root_hub)
+       {
+               IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Has Root Hub\n");
+               /* Inform the HUB driver to resume. */
+               usb_hcd_resume_root_hub(_syshcd);
+       }
+
+       ifxhcd->flags.d32 = 0;
+
+       /* Put all channels in the free channel list and clean up channel states.*/
+       {
+               int num_channels = ifxhcd->core_if.params.host_channels;
+               int i;
+               for (i = 0; i < num_channels; i++)
+               {
+                       ifxhcd_hc_t      *channel;
+                       channel = &ifxhcd->ifxhc[i];
+                       ifxhcd_hc_cleanup(&ifxhcd->core_if, channel);
+               }
+       }
+       /* Initialize the USB core for host mode operation. */
+
+       ifxusb_host_enable_interrupts(core_if);
+       ifxusb_enable_global_interrupts_h(core_if);
+       ifxusb_phy_power_on_h (core_if);
+
+       ifxusb_vbus_init(core_if);
+
+       /* Turn on the vbus power. */
+       {
+               hprt0_data_t hprt0;
+               hprt0.d32 = ifxusb_read_hprt0(core_if);
+
+               IFX_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr);
+               if (hprt0.b.prtpwr == 0 )
+               {
+                       hprt0.b.prtpwr = 1;
+                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                       ifxusb_vbus_on(core_if);
+               }
+       }
+       return 0;
+}
+
+/*!
+   \brief Halts the IFXUSB  host mode operations in a clean manner. USB transfers are
+ stopped.
+ */
+       #if defined(__IS_AR10__)
+void           ifxusb_oc_int_free(int port);
+       #else
+void           ifxusb_oc_int_free(void);
+       #endif
+void ifxhcd_stop(struct usb_hcd *_syshcd)
+{
+       ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd);
+       hprt0_data_t  hprt0 = { .d32=0 };
+
+       IFX_DEBUGPL(DBG_HCD, "IFX USB HCD STOP\n");
+
+       /* Turn off all interrupts. */
+       ifxusb_disable_global_interrupts_h(&ifxhcd->core_if );
+       ifxusb_host_disable_interrupts(&ifxhcd->core_if );
+
+       /*
+        * The root hub should be disconnected before this function is called.
+        * The disconnect will clear the URBD lists (via ..._hcd_urb_dequeue)
+        * and the EPQH lists (via ..._hcd_endpoint_disable).
+        */
+
+       /* Turn off the vbus power */
+       IFX_PRINT("PortPower off\n");
+
+       ifxusb_vbus_off(&ifxhcd->core_if );
+       
+       
+       #if defined(__IS_AR10__)
+               ifxusb_oc_int_free(ifxhcd->core_if.core_no);
+       #else
+               ifxusb_oc_int_free();
+       #endif
+       
+
+       ifxusb_vbus_free(&ifxhcd->core_if );
+       hprt0.b.prtpwr = 0;
+       ifxusb_wreg(ifxhcd->core_if.hprt0, hprt0.d32);
+       return;
+}
+
+/*!
+   \brief Returns the current frame number
+ */
+int ifxhcd_get_frame_number(struct usb_hcd *_syshcd)
+{
+       ifxhcd_hcd_t    *ifxhcd = syshcd_to_ifxhcd(_syshcd);
+       hfnum_data_t hfnum;
+
+       hfnum.d32 = ifxusb_rreg(&ifxhcd->core_if.host_global_regs->hfnum);
+
+       return hfnum.b.frnum;
+}
+
+/*!
+   \brief Starts processing a USB transfer request specified by a USB Request Block
+  (URB). mem_flags indicates the type of memory allocation to use while
+  processing this URB.
+ */
+int ifxhcd_urb_enqueue( struct usb_hcd           *_syshcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+                        struct usb_host_endpoint *_sysep,
+#endif
+                        struct urb               *_urb,
+                        gfp_t                     _mem_flags)
+{
+       ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd);
+       ifxhcd_epqh_t *epqh = NULL;
+
+       #ifdef __DEBUG__
+               if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB))
+                       dump_urb_info(_urb, "ifxusb_hcd_urb_enqueue");
+       #endif //__DEBUG__
+
+       if (!ifxhcd->flags.b.port_connect_status)  /* No longer connected. */
+               return -ENODEV;
+
+       #if !defined(__EN_ISOC__)
+               if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS)
+               {
+                       IFX_ERROR("ISOC transfer not supported!!!\n");
+                       return -ENODEV;
+               }
+       #endif
+
+       if(_urb->hcpriv)
+       {
+               IFX_WARN("%s() Previous urb->hcpriv exist %p\n",__func__,_urb->hcpriv);
+       #if 1
+               return -ENOSPC;
+       #endif
+       }
+
+       epqh=ifxhcd_urbd_create (ifxhcd,_urb);
+       if (!epqh)
+       {
+               IFX_ERROR("IFXUSB HCD URB Enqueue failed creating URBD\n");
+               return -ENOSPC;
+       }
+       if(epqh->phase==EPQH_DISABLING )
+       {
+               IFX_ERROR("Enqueue to a DISABLING EP!!!\n");
+               return -ENODEV;
+       }
+
+       #ifdef __DYN_SOF_INTR__
+               ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF;
+       #endif
+       //enable_sof(ifxhcd);
+       {
+               gint_data_t gintsts;
+               gintsts.d32=0;
+               gintsts.b.sofintr = 1;
+               ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32);
+       }
+
+       if(epqh->phase==EPQH_IDLE || epqh->phase==EPQH_STDBY )
+       {
+               epqh->phase=EPQH_READY;
+               #ifdef __EPQD_DESTROY_TIMEOUT__
+                       del_timer(&epqh->destroy_timer);
+               #endif
+       }
+       select_eps(ifxhcd);
+       return 0;
+}
+
+/*!
+   \brief Aborts/cancels a USB transfer request. Always returns 0 to indicate
+  success.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb)
+#else
+int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb, int status)
+#endif
+{
+       ifxhcd_hcd_t  *ifxhcd;
+       struct usb_host_endpoint *sysep;
+       ifxhcd_urbd_t *urbd;
+       ifxhcd_epqh_t *epqh;
+
+       IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD URB Dequeue\n");
+       #if !defined(__EN_ISOC__)
+               if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS)
+                       return 0;
+       #endif
+
+       ifxhcd = syshcd_to_ifxhcd(_syshcd);
+
+       urbd = (ifxhcd_urbd_t *) _urb->hcpriv;
+       if(!urbd)
+       {
+               #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+                       _urb->status=-ETIMEDOUT;
+                       usb_hcd_giveback_urb(_syshcd, _urb);
+               #else
+//                     usb_hcd_giveback_urb(_syshcd, _urb,-ETIMEDOUT);
+                       usb_hcd_giveback_urb(_syshcd, _urb,status);
+               #endif
+               return 0;
+       }
+
+       sysep = ifxhcd_urb_to_endpoint(_urb);
+       if(sysep)
+       {
+               LOCK_EPQH_LIST_ALL(ifxhcd);
+               epqh = sysep_to_epqh(ifxhcd,sysep);
+               UNLOCK_EPQH_LIST_ALL(ifxhcd);
+               if(epqh!=urbd->epqh)
+                       IFX_ERROR("%s inconsistant epqh %p %p\n",__func__,epqh,urbd->epqh);
+       }
+       else
+               epqh = (ifxhcd_epqh_t *) urbd->epqh;
+       if(!ifxhcd->flags.b.port_connect_status || !epqh)
+       {
+               urbd->phase=URBD_DEQUEUEING;
+               ifxhcd_complete_urb(ifxhcd, urbd, -ENODEV);
+       }
+       else
+       {
+               LOCK_URBD_LIST(epqh);
+               if(   urbd->phase==URBD_IDLE
+                  || urbd->phase==URBD_ACTIVE
+//                || urbd->phase==URBD_STARTING
+                  )
+               {
+                       urbd->phase=URBD_DEQUEUEING;
+                       #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+                               ifxhcd_complete_urb(ifxhcd, urbd, -ETIMEDOUT);
+                       #else
+                               ifxhcd_complete_urb(ifxhcd, urbd, status);
+                       #endif
+               }
+               else if(   urbd->phase==URBD_STARTED
+                       || urbd->phase==URBD_STARTING
+//                     || urbd->phase==URBD_ACTIVE
+                      )
+               {
+                       if(ifxhcd_hc_halt(&ifxhcd->core_if, epqh->hc, HC_XFER_URB_DEQUEUE))
+                       {
+                               urbd->phase=URBD_DEQUEUEING;
+                               #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+                                       ifxhcd_complete_urb(ifxhcd, urbd, -ETIMEDOUT);
+                               #else
+                                       ifxhcd_complete_urb(ifxhcd, urbd, status);
+                               #endif
+                               ifxhcd_epqh_idle(epqh);
+                       }
+               }
+               UNLOCK_URBD_LIST(epqh);
+       }
+       return 0;
+}
+
+
+/*!
+   \brief Frees resources in the IFXUSB controller related to a given endpoint. Also
+  clears state in the HCD related to the endpoint. Any URBs for the endpoint
+  must already be dequeued.
+ */
+void ifxhcd_endpoint_disable( struct usb_hcd *_syshcd,
+                              struct usb_host_endpoint *_sysep)
+{
+       ifxhcd_hcd_t  *ifxhcd;
+       ifxhcd_epqh_t *epqh;
+
+       IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: _bEndpointAddress=0x%02x, "
+           "endpoint=%d\n", _sysep->desc.bEndpointAddress,
+                   ifxhcd_ep_addr_to_endpoint(_sysep->desc.bEndpointAddress));
+
+       ifxhcd = syshcd_to_ifxhcd(_syshcd);
+
+       LOCK_EPQH_LIST_ALL(ifxhcd);
+       epqh = sysep_to_epqh(ifxhcd,_sysep);
+       UNLOCK_EPQH_LIST_ALL(ifxhcd);
+
+       if (!epqh)
+       {
+               return;
+       }
+       else
+       {
+               if (epqh->sysep!=_sysep)
+               {
+                       IFX_ERROR("%s inconsistant sysep %p %p %p\n",__func__,epqh,epqh->sysep,_sysep);
+                       return;
+               }
+
+               epqh->phase=EPQH_DISABLING;
+               kill_all_urbs_in_epqh(ifxhcd, epqh, -ETIMEDOUT);
+               {
+                       uint32_t count=0x80000;
+                       for(;!list_empty(&epqh->urbd_list) && count> 0; count--) udelay(1);
+                       if(!count)
+                               IFX_ERROR("%s: unable to clear urbd in epqh \n",__func__);
+               }
+               ifxhcd_epqh_free(epqh);
+       }
+       IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: done\n");
+}
+
+
+/*!
+  \brief Handles host mode interrupts for the IFXUSB controller. Returns IRQ_NONE if
+ there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
+ interrupt.
+
+ This function is called by the USB core when an interrupt occurs
+ */
+irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd)
+{
+       ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd);
+       int32_t retval=0;
+
+       //mask_and_ack_ifx_irq (ifxhcd->core_if.irq);
+       retval = ifxhcd_handle_intr(ifxhcd);
+       return IRQ_RETVAL(retval);
+}
+
+
+
+/*!
+ \brief Creates Status Change bitmap for the root hub and root port. The bitmap is
+  returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
+  is the status change indicator for the single root port. Returns 1 if either
+  change indicator is 1, otherwise returns 0.
+ */
+int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf)
+{
+       ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd);
+
+       _buf[0] = 0;
+       _buf[0] |= (ifxhcd->flags.b.port_connect_status_change ||
+                   ifxhcd->flags.b.port_reset_change ||
+                   ifxhcd->flags.b.port_enable_change ||
+                   ifxhcd->flags.b.port_suspend_change ||
+                   ifxhcd->flags.b.port_over_current_change) << 1;
+
+       #ifdef __DEBUG__
+               if (_buf[0])
+               {
+                       IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD HUB STATUS DATA:"
+                                   " Root port status changed\n");
+                       IFX_DEBUGPL(DBG_HCDV, "  port_connect_status_change: %d\n",
+                                   ifxhcd->flags.b.port_connect_status_change);
+                       IFX_DEBUGPL(DBG_HCDV, "  port_reset_change: %d\n",
+                                   ifxhcd->flags.b.port_reset_change);
+                       IFX_DEBUGPL(DBG_HCDV, "  port_enable_change: %d\n",
+                                   ifxhcd->flags.b.port_enable_change);
+                       IFX_DEBUGPL(DBG_HCDV, "  port_suspend_change: %d\n",
+                                   ifxhcd->flags.b.port_suspend_change);
+                       IFX_DEBUGPL(DBG_HCDV, "  port_over_current_change: %d\n",
+                                   ifxhcd->flags.b.port_over_current_change);
+                       {
+                               hprt0_data_t hprt0;
+                               hprt0.d32 = ifxusb_rreg(ifxhcd->core_if.hprt0);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :%08X\n",hprt0.d32);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :connect: %d/%d\n",hprt0.b.prtconnsts,hprt0.b.prtconndet);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :enable: %d/%d\n",hprt0.b.prtena,hprt0.b.prtenchng);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :OC: %d/%d\n",hprt0.b.prtovrcurract,hprt0.b.prtovrcurrchng);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :rsume/suspend/reset: %d/%d/%d\n",hprt0.b.prtres,hprt0.b.prtsusp,hprt0.b.prtrst);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :port power: %d/\n",hprt0.b.prtpwr);
+                               IFX_DEBUGPL(DBG_HCDV, "  port reg :speed: %d/\n",hprt0.b.prtspd);
+                       }
+               }
+       #endif //__DEBUG__
+       return (_buf[0] != 0);
+}
+
+#ifdef __WITH_HS_ELECT_TST__
+       extern void do_setup(ifxusb_core_if_t *_core_if) ;
+       extern void do_in_ack(ifxusb_core_if_t *_core_if);
+#endif //__WITH_HS_ELECT_TST__
+
+/*!
+ \brief Handles hub class-specific requests.
+ */
+int ifxhcd_hub_control( struct usb_hcd *_syshcd,
+                        u16             _typeReq,
+                        u16             _wValue,
+                        u16             _wIndex,
+                        char           *_buf,
+                        u16             _wLength)
+{
+       int retval = 0;
+       ifxhcd_hcd_t              *ifxhcd  = syshcd_to_ifxhcd (_syshcd);
+       ifxusb_core_if_t          *core_if = &ifxhcd->core_if;
+       struct usb_hub_descriptor *desc;
+       hprt0_data_t               hprt0 = {.d32 = 0};
+
+       uint32_t port_status;
+
+       switch (_typeReq)
+       {
+               case ClearHubFeature:
+                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                "ClearHubFeature 0x%x\n", _wValue);
+                       switch (_wValue)
+                       {
+                               case C_HUB_LOCAL_POWER:
+                               case C_HUB_OVER_CURRENT:
+                                       /* Nothing required here */
+                                       break;
+                               default:
+                                       retval = -EINVAL;
+                                       IFX_ERROR ("IFXUSB HCD - "
+                                                  "ClearHubFeature request %xh unknown\n", _wValue);
+                       }
+                       break;
+               case ClearPortFeature:
+                       if (!_wIndex || _wIndex > 1)
+                               goto error;
+
+                       switch (_wValue)
+                       {
+                               case USB_PORT_FEAT_ENABLE:
+                                       IFX_DEBUGPL (DBG_ANY, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
+                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                       hprt0.b.prtena = 1;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       break;
+                               case USB_PORT_FEAT_SUSPEND:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
+                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                       hprt0.b.prtres = 1;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       /* Clear Resume bit */
+                                       mdelay (100);
+                                       hprt0.b.prtres = 0;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       break;
+                               case USB_PORT_FEAT_POWER:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_POWER\n");
+                                       #ifdef __IS_DUAL__
+                                               ifxusb_vbus_off(core_if);
+                                       #else
+                                               ifxusb_vbus_off(core_if);
+                                       #endif
+                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                       hprt0.b.prtpwr = 0;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       break;
+                               case USB_PORT_FEAT_INDICATOR:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
+                                       /* Port inidicator not supported */
+                                       break;
+                               case USB_PORT_FEAT_C_CONNECTION:
+                                       /* Clears drivers internal connect status change
+                                        * flag */
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
+                                       ifxhcd->flags.b.port_connect_status_change = 0;
+                                       break;
+                               case USB_PORT_FEAT_C_RESET:
+                                       /* Clears the driver's internal Port Reset Change
+                                        * flag */
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
+                                       ifxhcd->flags.b.port_reset_change = 0;
+                                       break;
+                               case USB_PORT_FEAT_C_ENABLE:
+                                       /* Clears the driver's internal Port
+                                        * Enable/Disable Change flag */
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
+                                       ifxhcd->flags.b.port_enable_change = 0;
+                                       break;
+                               case USB_PORT_FEAT_C_SUSPEND:
+                                       /* Clears the driver's internal Port Suspend
+                                        * Change flag, which is set when resume signaling on
+                                        * the host port is complete */
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
+                                       ifxhcd->flags.b.port_suspend_change = 0;
+                                       break;
+                               case USB_PORT_FEAT_C_OVER_CURRENT:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
+                                       ifxhcd->flags.b.port_over_current_change = 0;
+                                       break;
+                               default:
+                                       retval = -EINVAL;
+                                       IFX_ERROR ("IFXUSB HCD - "
+                                                "ClearPortFeature request %xh "
+                                                "unknown or unsupported\n", _wValue);
+                       }
+                       break;
+               case GetHubDescriptor:
+                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                "GetHubDescriptor\n");
+                       desc = (struct usb_hub_descriptor *)_buf;
+                       desc->bDescLength = 9;
+                       desc->bDescriptorType = 0x29;
+                       desc->bNbrPorts = 1;
+                       desc->wHubCharacteristics = 0x08;
+                       desc->bPwrOn2PwrGood = 1;
+                       desc->bHubContrCurrent = 0;
+
+                       desc->u.hs.DeviceRemovable[0] = 0;
+                       desc->u.hs.DeviceRemovable[1] = 1;
+                       /*desc->bitmap[0] = 0;
+                       desc->bitmap[1] = 0xff;*/
+                       break;
+               case GetHubStatus:
+                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                "GetHubStatus\n");
+                       memset (_buf, 0, 4);
+                       break;
+               case GetPortStatus:
+                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                "GetPortStatus\n");
+                       if (!_wIndex || _wIndex > 1)
+                               goto error;
+                       port_status = 0;
+                       if (ifxhcd->flags.b.port_connect_status_change)
+                               port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+                       if (ifxhcd->flags.b.port_enable_change)
+                               port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
+                       if (ifxhcd->flags.b.port_suspend_change)
+                               port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+                       if (ifxhcd->flags.b.port_reset_change)
+                               port_status |= (1 << USB_PORT_FEAT_C_RESET);
+                       if (ifxhcd->flags.b.port_over_current_change)
+                       {
+                               IFX_ERROR("Device Not Supported\n");
+                               port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+                       }
+                       if (!ifxhcd->flags.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.
+                                */
+                               *((u32 *) _buf) = cpu_to_le32(port_status);
+                               break;
+                       }
+
+                       hprt0.d32 = ifxusb_rreg(core_if->hprt0);
+                       IFX_DEBUGPL(DBG_HCDV, "  HPRT0: 0x%08x\n", hprt0.d32);
+                       if (hprt0.b.prtconnsts)
+                               port_status |= (1 << USB_PORT_FEAT_CONNECTION);
+                       if (hprt0.b.prtena)
+                       {
+                               ifxhcd->disconnecting=0;
+                               port_status |= (1 << USB_PORT_FEAT_ENABLE);
+                       }
+                       if (hprt0.b.prtsusp)
+                               port_status |= (1 << USB_PORT_FEAT_SUSPEND);
+                       if (hprt0.b.prtovrcurract)
+                               port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
+                       if (hprt0.b.prtrst)
+                               port_status |= (1 << USB_PORT_FEAT_RESET);
+                       if (hprt0.b.prtpwr)
+                               port_status |= (1 << USB_PORT_FEAT_POWER);
+/*                     if      (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED)
+                               port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
+                       else*/ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED)
+                               port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
+                       if (hprt0.b.prttstctl)
+                               port_status |= (1 << USB_PORT_FEAT_TEST);
+                       /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+                       *((u32 *) _buf) = cpu_to_le32(port_status);
+                       break;
+               case SetHubFeature:
+                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                "SetHubFeature\n");
+                       /* No HUB features supported */
+                       break;
+               case SetPortFeature:
+                       if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1))
+                               goto error;
+                       /*
+                        * 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.
+                        */
+                       if (!ifxhcd->flags.b.port_connect_status)
+                               break;
+                       switch (_wValue)
+                       {
+                               case USB_PORT_FEAT_SUSPEND:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
+                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                       hprt0.b.prtsusp = 1;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       //IFX_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32);
+                                       /* Suspend the Phy Clock */
+                                       {
+                                               pcgcctl_data_t pcgcctl = {.d32=0};
+                                               pcgcctl.b.stoppclk = 1;
+                                               ifxusb_wreg(core_if->pcgcctl, pcgcctl.d32);
+                                       }
+                                       break;
+                               case USB_PORT_FEAT_POWER:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                            "SetPortFeature - USB_PORT_FEAT_POWER\n");
+                                       ifxusb_vbus_on (core_if);
+                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                       hprt0.b.prtpwr = 1;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       break;
+                               case USB_PORT_FEAT_RESET:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "SetPortFeature - USB_PORT_FEAT_RESET\n");
+                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                       hprt0.b.prtrst = 1;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
+                                       MDELAY (60);
+                                       hprt0.b.prtrst = 0;
+                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                       break;
+                       #ifdef __WITH_HS_ELECT_TST__
+                               case USB_PORT_FEAT_TEST:
+                                       {
+                                               uint32_t t;
+                                               gint_data_t gintmsk;
+                                               t = (_wIndex >> 8); /* MSB wIndex USB */
+                                               IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                            "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t);
+                                               warn("USB_PORT_FEAT_TEST %d\n", t);
+                                               if (t < 6)
+                                               {
+                                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                                       hprt0.b.prttstctl = t;
+                                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                               }
+                                               else if (t == 6)  /* HS_HOST_PORT_SUSPEND_RESUME */
+                                               {
+                                                       /* Save current interrupt mask */
+                                                       gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk);
+
+                                                       /* Disable all interrupts while we muck with
+                                                        * the hardware directly
+                                                        */
+                                                       ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0);
+
+                                                       /* 15 second delay per the test spec */
+                                                       mdelay(15000);
+
+                                                       /* Drive suspend on the root port */
+                                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                                       hprt0.b.prtsusp = 1;
+                                                       hprt0.b.prtres = 0;
+                                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+
+                                                       /* 15 second delay per the test spec */
+                                                       mdelay(15000);
+
+                                                       /* Drive resume on the root port */
+                                                       hprt0.d32 = ifxusb_read_hprt0 (core_if);
+                                                       hprt0.b.prtsusp = 0;
+                                                       hprt0.b.prtres = 1;
+                                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+                                                       mdelay(100);
+
+                                                       /* Clear the resume bit */
+                                                       hprt0.b.prtres = 0;
+                                                       ifxusb_wreg(core_if->hprt0, hprt0.d32);
+
+                                                       /* Restore interrupts */
+                                                       ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32);
+                                               }
+                                               else if (t == 7)  /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
+                                               {
+                                                       /* Save current interrupt mask */
+                                                       gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk);
+
+                                                       /* Disable all interrupts while we muck with
+                                                        * the hardware directly
+                                                        */
+                                                       ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0);
+
+                                                       /* 15 second delay per the test spec */
+                                                       mdelay(15000);
+
+                                                       /* Send the Setup packet */
+                                                       do_setup(core_if);
+
+                                                       /* 15 second delay so nothing else happens for awhile */
+                                                       mdelay(15000);
+
+                                                       /* Restore interrupts */
+                                                       ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32);
+                                               }
+
+                                               else if (t == 8)  /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
+                                               {
+                                                       /* Save current interrupt mask */
+                                                       gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk);
+
+                                                       /* Disable all interrupts while we muck with
+                                                        * the hardware directly
+                                                        */
+                                                       ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0);
+
+                                                       /* Send the Setup packet */
+                                                       do_setup(core_if);
+
+                                                       /* 15 second delay so nothing else happens for awhile */
+                                                       mdelay(15000);
+
+                                                       /* Send the In and Ack packets */
+                                                       do_in_ack(core_if);
+
+                                                       /* 15 second delay so nothing else happens for awhile */
+                                                       mdelay(15000);
+
+                                                       /* Restore interrupts */
+                                                       ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32);
+                                               }
+                                       }
+                                       break;
+                       #endif //__WITH_HS_ELECT_TST__
+                               case USB_PORT_FEAT_INDICATOR:
+                                       IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - "
+                                                    "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
+                                       /* Not supported */
+                                       break;
+                               default:
+                                       retval = -EINVAL;
+                                       IFX_ERROR ("IFXUSB HCD - "
+                                                  "SetPortFeature request %xh "
+                                                  "unknown or unsupported\n", _wValue);
+                       }
+                       break;
+               default:
+               error:
+                       retval = -EINVAL;
+                       IFX_WARN ("IFXUSB HCD - "
+                                 "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
+                                 _typeReq, _wIndex, _wValue);
+       }
+       return retval;
+}
+
+
+
+
+/*!
+   \brief This function trigger a data transfer for a host channel and
+  starts the transfer.
+
+  For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+  register along with a packet count of 1 and the channel is enabled. This
+  causes a single PING transaction to occur. Other fields in HCTSIZ are
+  simply set to 0 since no data transfer occurs in this case.
+
+  For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+  all the information required to perform the subsequent data transfer. In
+  addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+  controller performs the entire PING protocol, then starts the data
+  transfer.
+  \param _core_if        Pointer of core_if structure
+  \param _ifxhc Information needed to initialize the host channel. The xfer_len
+  value may be reduced to accommodate the max widths of the XferSize and
+  PktCnt fields in the HCTSIZn register. The multi_count value may be changed
+  to reflect the final xfer_len value.
+ */
+void ifxhcd_hc_start(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc)
+{
+       ifxusb_core_if_t *core_if = &_ifxhcd->core_if;
+       uint32_t max_hc_xfer_size = core_if->params.max_transfer_size;
+       uint16_t max_hc_pkt_count = core_if->params.max_packet_count;
+       ifxusb_hc_regs_t *hc_regs = core_if->hc_regs[_ifxhc->hc_num];
+       hfnum_data_t hfnum;
+
+       hprt0_data_t hprt0;
+
+       if(_ifxhc->epqh->urbd->phase==URBD_DEQUEUEING)
+               return;
+
+       hprt0.d32 = ifxusb_read_hprt0(core_if);
+
+       if(_ifxhcd->pkt_remaining==0)
+               return;
+
+#if 0
+       if(_ifxhc->phase!=HC_WAITING)
+               printk(KERN_INFO "%s() line %d: _ifxhc->phase!=HC_WAITING :%d\n",__func__,__LINE__,_ifxhc->phase);
+       if(_ifxhc->epqh->urbd->phase==URBD_IDLE      ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_IDLE\n",__func__,__LINE__);
+//     if(_ifxhc->epqh->urbd->phase==URBD_ACTIVE    ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_ACTIVE\n",__func__,__LINE__);
+       if(_ifxhc->epqh->urbd->phase==URBD_STARTING  ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_STARTING\n",__func__,__LINE__);
+       if(_ifxhc->epqh->urbd->phase==URBD_STARTED   ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_STARTED\n",__func__,__LINE__);
+       if(_ifxhc->epqh->urbd->phase==URBD_COMPLETING) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_COMPLETING\n",__func__,__LINE__);
+       if(_ifxhc->epqh->urbd->phase==URBD_DEQUEUEING) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_DEQUEUEING\n",__func__,__LINE__);
+       if(_ifxhc->epqh->urbd->phase==URBD_FINISHING ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_FINISHING\n",__func__,__LINE__);
+#endif
+
+       if      (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED)
+       {
+               if (_ifxhc->split)
+               {
+                       if(max_hc_pkt_count > _ifxhcd->pkt_remaining)
+                               max_hc_pkt_count = _ifxhcd->pkt_remaining;
+               }
+               else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)
+               {
+                       if( _ifxhc->is_in && _ifxhcd->pkt_count_limit_bi && max_hc_pkt_count > _ifxhcd->pkt_count_limit_bi)
+                               max_hc_pkt_count = _ifxhcd->pkt_count_limit_bi;
+                       if(!_ifxhc->is_in && _ifxhcd->pkt_count_limit_bo && max_hc_pkt_count > _ifxhcd->pkt_count_limit_bo)
+                               max_hc_pkt_count = _ifxhcd->pkt_count_limit_bo;
+                       if(max_hc_pkt_count*8 > _ifxhcd->pkt_remaining)
+                               max_hc_pkt_count = _ifxhcd->pkt_remaining/8;
+               }
+               else
+               {
+                       if(max_hc_pkt_count > _ifxhcd->pkt_remaining)
+                               max_hc_pkt_count = _ifxhcd->pkt_remaining;
+               }
+       }
+       else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED)
+       {
+               if(max_hc_pkt_count > _ifxhcd->pkt_remaining)
+                       max_hc_pkt_count = _ifxhcd->pkt_remaining;
+       }
+       else
+       {
+               if(max_hc_pkt_count > _ifxhcd->pkt_remaining)
+                       max_hc_pkt_count = _ifxhcd->pkt_remaining;
+       }
+
+       if(max_hc_pkt_count==0)
+               return;
+
+       if(max_hc_pkt_count * _ifxhc->mps <  max_hc_xfer_size)
+               max_hc_xfer_size = max_hc_pkt_count * _ifxhc->mps;
+
+       _ifxhc->epqh->urbd->phase=URBD_STARTING;
+
+       if(_ifxhc->is_in || _ifxhc->speed != IFXUSB_EP_SPEED_HIGH || _ifxhc->xfer_len==0)
+               _ifxhc->epqh->do_ping=0;
+       if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
+               _ifxhc->epqh->do_ping=0;
+       if(_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL && _ifxhc->control_phase != IFXHCD_CONTROL_DATA  )
+               _ifxhc->epqh->do_ping=0;
+
+       if (_ifxhc->split > 0)
+       {
+               _ifxhc->start_pkt_count = 1;
+               if(!_ifxhc->is_in && _ifxhc->split>1) // OUT CSPLIT
+                       _ifxhc->xfer_len = 0;
+               if (_ifxhc->xfer_len > _ifxhc->mps)
+                       _ifxhc->xfer_len = _ifxhc->mps;
+               if (_ifxhc->xfer_len > 188)
+                       _ifxhc->xfer_len = 188;
+       }
+       else if(_ifxhc->is_in)
+       {
+               _ifxhc->short_rw = 0;
+               if (_ifxhc->xfer_len > 0)
+               {
+                       if (_ifxhc->xfer_len > max_hc_xfer_size)
+                               _ifxhc->xfer_len = max_hc_xfer_size - _ifxhc->mps + 1;
+                       _ifxhc->start_pkt_count = (_ifxhc->xfer_len + _ifxhc->mps - 1) / _ifxhc->mps;
+                       if (_ifxhc->start_pkt_count > max_hc_pkt_count)
+                               _ifxhc->start_pkt_count = max_hc_pkt_count;
+               }
+               else /* Need 1 packet for transfer length of 0. */
+                       _ifxhc->start_pkt_count = 1;
+               _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps;
+       }
+       else //non-split out
+       {
+               if (_ifxhc->xfer_len == 0)
+               {
+                       if(_ifxhc->short_rw==0)
+                               printk(KERN_INFO "Info: %s() line %d: ZLP write without short_rw set! xfer_count:%d/%d \n",__func__,__LINE__,
+                                       _ifxhc->xfer_count,
+                                       _ifxhc->epqh->urbd->xfer_len);
+                       _ifxhc->start_pkt_count = 1;
+               }
+               else
+               {
+                       if (_ifxhc->xfer_len > max_hc_xfer_size)
+                       {
+                               _ifxhc->start_pkt_count = (max_hc_xfer_size / _ifxhc->mps);
+                               _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps;
+                       }
+                       else
+                       {
+                               _ifxhc->start_pkt_count = (_ifxhc->xfer_len+_ifxhc->mps-1)  / _ifxhc->mps;
+//                             if(_ifxhc->start_pkt_count * _ifxhc->mps == _ifxhc->xfer_len )
+//                                     _ifxhc->start_pkt_count += _ifxhc->short_rw;
+                       }
+               }
+       }
+
+       if      (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED)
+       {
+               if (_ifxhc->split)
+               {
+                       if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count)
+                               _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count;
+                       else
+                               _ifxhcd->pkt_remaining  = 0;
+               }
+               else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)
+               {
+                       if( _ifxhcd->pkt_remaining*8 > _ifxhc->start_pkt_count)
+                               _ifxhcd->pkt_remaining -= (_ifxhc->start_pkt_count*8);
+                       else
+                               _ifxhcd->pkt_remaining  = 0;
+               }
+               else
+               {
+                       if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count)
+                               _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count;
+                       else
+                               _ifxhcd->pkt_remaining  = 0;
+               }
+       }
+       else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED)
+       {
+               if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count)
+                       _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count;
+               else
+                       _ifxhcd->pkt_remaining  = 0;
+       }
+       else
+       {
+               if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count)
+                       _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count;
+               else
+                       _ifxhcd->pkt_remaining  = 0;
+       }
+
+       #ifdef __EN_ISOC__
+               if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
+               {
+                       /* Set up the initial PID for the transfer. */
+                       #if 1
+                               _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
+                       #else
+                               if (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH)
+                               {
+                                       if (_ifxhc->is_in)
+                                       {
+                                               if      (_ifxhc->multi_count == 1)
+                                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
+                                               else if (_ifxhc->multi_count == 2)
+                                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
+                                               else
+                                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA2;
+                                       }
+                                       else
+                                       {
+                                               if (_ifxhc->multi_count == 1)
+                                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
+                                               else
+                                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_MDATA;
+                                       }
+                               }
+                               else
+                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
+                       #endif
+               }
+       #endif
+
+       IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _ifxhc->hc_num);
+       {
+               hctsiz_data_t hctsiz= { .d32=0 };
+
+               hctsiz.b.dopng = _ifxhc->epqh->do_ping;
+               _ifxhc->epqh->do_ping=0;
+
+               if(_ifxhc->is_in || _ifxhc->speed != IFXUSB_EP_SPEED_HIGH || _ifxhc->xfer_len==0)
+                       hctsiz.b.dopng = 0;
+               if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
+                       hctsiz.b.dopng = 0;
+               if(_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL && _ifxhc->control_phase != IFXHCD_CONTROL_DATA  )
+                       hctsiz.b.dopng = 0;
+
+               hctsiz.b.xfersize = _ifxhc->xfer_len;
+               hctsiz.b.pktcnt   = _ifxhc->start_pkt_count;
+               hctsiz.b.pid      = _ifxhc->data_pid_start;
+               ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
+
+               IFX_DEBUGPL(DBG_HCDV, "  Xfer Size: %d\n", hctsiz.b.xfersize);
+               IFX_DEBUGPL(DBG_HCDV, "  Num Pkts: %d\n" , hctsiz.b.pktcnt);
+               IFX_DEBUGPL(DBG_HCDV, "  Start PID: %d\n", hctsiz.b.pid);
+       }
+       IFX_DEBUGPL(DBG_HCDV, "  DMA: 0x%08x\n", (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count )));
+       ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count )));
+
+       /* Start the split */
+       if (_ifxhc->split>0)
+       {
+               hcsplt_data_t hcsplt;
+               hcsplt.d32 = ifxusb_rreg (&hc_regs->hcsplt);
+               hcsplt.b.spltena = 1;
+               if (_ifxhc->split>1)
+                       hcsplt.b.compsplt = 1;
+               else
+                       hcsplt.b.compsplt = 0;
+
+               #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
+                       if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
+                               hcsplt.b.xactpos = _ifxhc->isoc_xact_pos;
+                       else
+               #endif
+               hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL;// if not ISO
+               ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32);
+               IFX_DEBUGPL(DBG_HCDV, "  SPLIT: XACT_POS:0x%08x\n", hcsplt.d32);
+       }
+
+       {
+               hcchar_data_t hcchar;
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+//             hcchar.b.multicnt = _ifxhc->multi_count;
+               hcchar.b.multicnt = 1;
+
+               if (_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
+               {
+                       hfnum.d32 = ifxusb_rreg(&core_if->host_global_regs->hfnum);
+                       /* 1 if _next_ frame is odd, 0 if it's even */
+                       hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
+               }
+
+               #ifdef __DEBUG__
+                       _ifxhc->start_hcchar_val = hcchar.d32;
+                       if (hcchar.b.chdis)
+                               IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+                                        __func__, _ifxhc->hc_num, hcchar.d32);
+               #endif
+
+               /* Set host channel enable after all other setup is complete. */
+               hcchar.b.chen  = 1;
+               hcchar.b.chdis = 0;
+               hcchar.b.epdir =  _ifxhc->is_in;
+               _ifxhc->hcchar=hcchar.d32;
+       }
+
+       IFX_DEBUGPL(DBG_HCDV, "  HCCHART: 0x%08x\n", _ifxhc->hcchar);
+
+       _ifxhc->phase=HC_STARTING;
+}
+
+/*!
+   \brief Attempts to halt a host channel. This function should only be called
+  to abort a transfer in DMA mode. Under normal circumstances in DMA mode, the
+  controller halts the channel when the transfer is complete or a condition
+  occurs that requires application intervention.
+
+  In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+  HCCHARn register. The controller ensures there is space in the request
+  queue before submitting the halt request.
+
+  Some time may elapse before the core flushes any posted requests for this
+  host channel and halts. The Channel Halted interrupt handler completes the
+  deactivation of the host channel.
+ */
+int ifxhcd_hc_halt(ifxusb_core_if_t *_core_if,
+                    ifxhcd_hc_t *_ifxhc,
+                    ifxhcd_halt_status_e _halt_status)
+{
+       hcchar_data_t   hcchar;
+       ifxusb_hc_regs_t           *hc_regs;
+       hc_regs          = _core_if->hc_regs[_ifxhc->hc_num];
+
+       WARN_ON(_halt_status == HC_XFER_NO_HALT_STATUS);
+
+       {
+               hprt0_data_t hprt0;
+               hprt0.d32 = ifxusb_rreg(_core_if->hprt0);
+               if(hprt0.b.prtena == 0)
+                       return -1;
+       }
+
+       if (_halt_status == HC_XFER_URB_DEQUEUE ||
+           _halt_status == HC_XFER_AHB_ERR)
+       {
+               /*
+                * Disable all channel interrupts except Ch Halted. The URBD
+                * and EPQH state associated with this transfer has been cleared
+                * (in the case of URB_DEQUEUE), so the channel needs to be
+                * shut down carefully to prevent crashes.
+                */
+               hcint_data_t hcintmsk;
+               hcintmsk.d32 = 0;
+               hcintmsk.b.chhltd = 1;
+               ifxusb_wreg(&hc_regs->hcintmsk, hcintmsk.d32);
+
+               /*
+                * Make sure no other interrupts besides halt are currently
+                * pending. Handling another interrupt could cause a crash due
+                * to the URBD and EPQH state.
+                */
+               ifxusb_wreg(&hc_regs->hcint, ~hcintmsk.d32);
+
+               /*
+                * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+                * even if the channel was already halted for some other
+                * reason.
+                */
+               _ifxhc->halt_status = _halt_status;
+       }
+
+       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+       if (hcchar.b.chen == 0)
+       {
+               /*
+                * The channel is either already halted or it hasn't
+                * started yet. In DMA mode, the transfer may halt if
+                * it finishes normally or a condition occurs that
+                * requires driver intervention. Don't want to halt
+                * the channel again. In either Slave or DMA mode,
+                * it's possible that the transfer has been assigned
+                * to a channel, but not started yet when an URB is
+                * dequeued. Don't want to halt a channel that hasn't
+                * started yet.
+                */
+               _ifxhc->phase=HC_IDLE;
+               return -1;
+       }
+
+       if (_ifxhc->phase==HC_STOPPING)
+       {
+               /*
+                * A halt has already been issued for this channel. This might
+                * happen when a transfer is aborted by a higher level in
+                * the stack.
+                */
+               #ifdef __DEBUG__
+                       IFX_PRINT("*** %s: Channel %d, double halt a channel***\n",
+                                 __func__, _ifxhc->hc_num);
+               #endif
+               return 0;
+       }
+       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+       hcchar.b.chen = 1;
+       hcchar.b.chdis = 1;
+
+       ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+
+       _ifxhc->halt_status = _halt_status;
+       _ifxhc->phase=HC_STOPPING;
+
+       IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n" , __func__, _ifxhc->hc_num);
+       IFX_DEBUGPL(DBG_HCDV, "  hcchar: 0x%08x\n"   , hcchar.d32);
+       IFX_DEBUGPL(DBG_HCDV, "  halt_status: %d\n"  , _ifxhc->halt_status);
+
+       return 0;
+}
+
+/*!
+   \brief Clears a host channel.
+ */
+void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc)
+{
+       ifxusb_hc_regs_t *hc_regs;
+
+       _ifxhc->phase=HC_IDLE;
+       _ifxhc->epqh=0;
+
+       /*
+        * Clear channel interrupt enables and any unhandled channel interrupt
+        * conditions.
+        */
+       hc_regs = _core_if->hc_regs[_ifxhc->hc_num];
+       ifxusb_wreg(&hc_regs->hcintmsk, 0);
+       ifxusb_wreg(&hc_regs->hcint, 0xFFFFFFFF);
+
+       #ifdef __DEBUG__
+               {
+                       hcchar_data_t hcchar;
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       if (hcchar.b.chdis)
+                               IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", __func__, _ifxhc->hc_num, hcchar.d32);
+               }
+       #endif
+}
+
+
+
+
+
+#ifdef __DEBUG__
+       static void dump_urb_info(struct urb *_urb, char* _fn_name)
+       {
+               IFX_PRINT("%s, urb %p\n"          , _fn_name, _urb);
+               IFX_PRINT("  Device address: %d\n", usb_pipedevice(_urb->pipe));
+               IFX_PRINT("  Endpoint: %d, %s\n"  , usb_pipeendpoint(_urb->pipe),
+                                                   (usb_pipein(_urb->pipe) ? "IN" : "OUT"));
+               IFX_PRINT("  Endpoint type: %s\n",
+                   ({  char *pipetype;
+                       switch (usb_pipetype(_urb->pipe)) {
+                               case PIPE_CONTROL:     pipetype = "CONTROL"; break;
+                               case PIPE_BULK:        pipetype = "BULK"; break;
+                               case PIPE_INTERRUPT:   pipetype = "INTERRUPT"; break;
+                               case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break;
+                               default:               pipetype = "UNKNOWN"; break;
+                       };
+                       pipetype;
+                   }));
+               IFX_PRINT("  Speed: %s\n",
+                   ({  char *speed;
+                       switch (_urb->dev->speed) {
+                               case USB_SPEED_HIGH: speed = "HIGH"; break;
+                               case USB_SPEED_FULL: speed = "FULL"; break;
+                               case USB_SPEED_LOW:  speed = "LOW"; break;
+                               default:             speed = "UNKNOWN"; break;
+                       };
+                       speed;
+                   }));
+               IFX_PRINT("  Max packet size: %d\n",
+                         usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe)));
+               IFX_PRINT("  Data buffer length: %d\n", _urb->transfer_buffer_length);
+               IFX_PRINT("  Transfer buffer: %p, Transfer DMA: %p\n",
+                         _urb->transfer_buffer, (void *)_urb->transfer_dma);
+               IFX_PRINT("  Setup buffer: %p, Setup DMA: %p\n",
+                         _urb->setup_packet, (void *)_urb->setup_dma);
+               IFX_PRINT("  Interval: %d\n", _urb->interval);
+               if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS)
+               {
+                       int i;
+                       for (i = 0; i < _urb->number_of_packets;  i++)
+                       {
+                               IFX_PRINT("  ISO Desc %d:\n", i);
+                               IFX_PRINT("    offset: %d, length %d\n",
+                                   _urb->iso_frame_desc[i].offset,
+                                   _urb->iso_frame_desc[i].length);
+                       }
+               }
+       }
+
+#if 0
+       static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh)
+       {
+               if (_epqh->hc != NULL)
+               {
+                       ifxhcd_hc_t      *hc = _epqh->hc;
+                       struct list_head *item;
+                       ifxhcd_epqh_t      *epqh_item;
+
+                       ifxusb_hc_regs_t *hc_regs;
+
+                       hcchar_data_t  hcchar;
+                       hcsplt_data_t  hcsplt;
+                       hctsiz_data_t  hctsiz;
+                       uint32_t       hcdma;
+
+                       hc_regs = _ifxhcd->core_if.hc_regs[hc->hc_num];
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       hcsplt.d32 = ifxusb_rreg(&hc_regs->hcsplt);
+                       hctsiz.d32 = ifxusb_rreg(&hc_regs->hctsiz);
+                       hcdma      = ifxusb_rreg(&hc_regs->hcdma);
+
+                       IFX_PRINT("  Assigned to channel %d:\n"       , hc->hc_num);
+                       IFX_PRINT("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
+                       IFX_PRINT("    hctsiz 0x%08x, hcdma 0x%08x\n" , hctsiz.d32, hcdma);
+                       IFX_PRINT("    dev_addr: %d, ep_num: %d, is_in: %d\n",
+                          hc->dev_addr, hc->ep_num, hc->is_in);
+                       IFX_PRINT("    ep_type: %d\n"        , hc->ep_type);
+                       IFX_PRINT("    max_packet_size: %d\n", hc->mps);
+                       IFX_PRINT("    data_pid_start: %d\n" , hc->data_pid_start);
+                       IFX_PRINT("    halt_status: %d\n"    , hc->halt_status);
+                       IFX_PRINT("    xfer_buff: %p\n"      , hc->xfer_buff);
+                       IFX_PRINT("    xfer_len: %d\n"       , hc->xfer_len);
+                       IFX_PRINT("    epqh: %p\n"           , hc->epqh);
+                       IFX_PRINT("  NP :\n");
+                       list_for_each(item, &_ifxhcd->epqh_list_np)
+                       {
+                               epqh_item = list_entry(item, ifxhcd_epqh_t, ql);
+                               IFX_PRINT("    %p\n", epqh_item);
+                       }
+                       IFX_PRINT("  INTR :\n");
+                       list_for_each(item, &_ifxhcd->epqh_list_intr)
+                       {
+                               epqh_item = list_entry(item, ifxhcd_epqh_t, ql);
+                               IFX_PRINT("    %p\n", epqh_item);
+                       }
+                       #ifdef __EN_ISOC__
+                               IFX_PRINT("  ISOC:\n");
+                               list_for_each(item, &_ifxhcd->epqh_list_isoc)
+                               {
+                                       epqh_item = list_entry(item, ifxhcd_epqh_t, ql);
+                                       IFX_PRINT("    %p\n", epqh_item);
+                               }
+                       #endif
+               }
+       }
+#endif
+#endif //__DEBUG__
+
+
+/*!
+   \brief This function writes a packet into the Tx FIFO associated with the Host
+  Channel. For a channel associated with a non-periodic EP, the non-periodic
+  Tx FIFO is written. For a channel associated with a periodic EP, the
+  periodic Tx FIFO is written. This function should only be called in Slave
+  mode.
+
+  Upon return the xfer_buff and xfer_count fields in _hc are incremented by
+  then number of bytes written to the Tx FIFO.
+ */
+
+#ifdef __ENABLE_DUMP__
+       void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd)
+       {
+               int num_channels;
+               int i;
+               num_channels = _ifxhcd->core_if.params.host_channels;
+               IFX_PRINT("\n");
+               IFX_PRINT("************************************************************\n");
+               IFX_PRINT("HCD State:\n");
+               IFX_PRINT("  Num channels: %d\n", num_channels);
+               for (i = 0; i < num_channels; i++) {
+                       ifxhcd_hc_t *hc = &_ifxhcd->ifxhc[i];
+                       IFX_PRINT("  Channel %d:\n", hc->hc_num);
+                       IFX_PRINT("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+                                 hc->dev_addr, hc->ep_num, hc->is_in);
+                       IFX_PRINT("    speed: %d\n"          , hc->speed);
+                       IFX_PRINT("    ep_type: %d\n"        , hc->ep_type);
+                       IFX_PRINT("    mps: %d\n", hc->mps);
+                       IFX_PRINT("    data_pid_start: %d\n" , hc->data_pid_start);
+                       IFX_PRINT("    xfer_buff: %p\n"      , hc->xfer_buff);
+                       IFX_PRINT("    xfer_len: %d\n"       , hc->xfer_len);
+                       IFX_PRINT("    xfer_count: %d\n"     , hc->xfer_count);
+                       IFX_PRINT("    halt_status: %d\n"    , hc->halt_status);
+                       IFX_PRINT("    split: %d\n"          , hc->split);
+                       IFX_PRINT("    hub_addr: %d\n"       , hc->hub_addr);
+                       IFX_PRINT("    port_addr: %d\n"      , hc->port_addr);
+                       #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
+                               IFX_PRINT("    isoc_xact_pos: %d\n"       , hc->isoc_xact_pos);
+                       #endif
+
+                       IFX_PRINT("    epqh: %p\n"           , hc->epqh);
+                       IFX_PRINT("    short_rw: %d\n"       , hc->short_rw);
+                       IFX_PRINT("    control_phase: %d\n"  , hc->control_phase);
+                       if(hc->epqh)
+                       {
+                               IFX_PRINT("    do_ping: %d\n"        , hc->epqh->do_ping);
+                       }
+                       IFX_PRINT("    start_pkt_count: %d\n"       , hc->start_pkt_count);
+               }
+               IFX_PRINT("************************************************************\n");
+               IFX_PRINT("\n");
+       }
+#endif //__ENABLE_DUMP__
+
diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd.h b/package/platform/lantiq/ltq-hcd/src/ifxhcd.h
new file mode 100644 (file)
index 0000000..243c5f5
--- /dev/null
@@ -0,0 +1,758 @@
+/*****************************************************************************
+ **   FILE NAME       : ifxhcd.h
+ **   PROJECT         : IFX USB sub-system V3
+ **   MODULES         : IFX USB sub-system Host and Device driver
+ **   SRC VERSION     : 3.2
+ **   DATE            : 1/Jan/2011
+ **   AUTHOR          : Chen, Howard
+ **   DESCRIPTION     : This file contains the structures, constants, and interfaces for
+ **                     the Host Contoller Driver (HCD).
+ **
+ **                     The Host Controller Driver (HCD) is responsible for translating requests
+ **                     from the USB Driver into the appropriate actions on the IFXUSB controller.
+ **                     It isolates the USBD from the specifics of the controller by providing an
+ **                     API to the USBD.
+ **   FUNCTIONS       :
+ **   COMPILER        : gcc
+ **   REFERENCE       : Synopsys DWC-OTG Driver 2.7
+ **   COPYRIGHT       :  Copyright (c) 2010
+ **                      LANTIQ DEUTSCHLAND GMBH,
+ **                      Am Campeon 3, 85579 Neubiberg, Germany
+ **
+ **    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.
+ **
+ **  Version Control Section  **
+ **   $Author$
+ **   $Date$
+ **   $Revisions$
+ **   $Log$       Revision history
+ *****************************************************************************/
+
+/*
+ * This file contains code fragments from Synopsys HS OTG Linux Software Driver.
+ * For this code the following notice is applicable:
+ *
+ * ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/*!
+  \defgroup IFXUSB_HCD HCD Interface
+  \ingroup IFXUSB_DRIVER_V3
+  \brief  The Host Controller Driver (HCD) is responsible for translating requests
+ from the USB Driver into the appropriate actions on the IFXUSB controller.
+ It isolates the USBD from the specifics of the controller by providing an
+ API to the USBD.
+ */
+
+
+/*!
+  \file ifxhcd.h
+  \ingroup IFXUSB_DRIVER_V3
+  \brief This file contains the structures, constants, and interfaces for
+ the Host Contoller Driver (HCD).
+ */
+
+#if !defined(__IFXHCD_H__)
+#define __IFXHCD_H__
+
+
+#define __STRICT_ORDER__
+
+
+#include <linux/list.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+
+#include "ifxusb_cif.h"
+#include "ifxusb_plat.h"
+
+
+#undef __INNAKSTOP__
+#if !defined(__INNAKSTOP__) && defined(__INNAKSTOP_CTRL__)
+       #define __INNAKSTOP__ 1
+#endif
+#if !defined(__INNAKSTOP__) && defined(__INNAKSTOP_BULK__)
+       #define __INNAKSTOP__ 1
+#endif
+
+#undef __PINGSTOP__
+#if !defined(__PINGSTOP__) && defined(__PINGSTOP_CTRL__)
+       #define __PINGSTOP__ 1
+#endif
+#if !defined(__PINGSTOP__) && defined(__PINGSTOP_BULK__)
+       #define __PINGSTOP__ 1
+#endif
+
+#undef __NAKSTOP__
+#if defined(__INNAKSTOP__) || defined(__PINGSTOP__)
+       #define __NAKSTOP__ 1
+#endif
+
+
+/* Phases for control transfers.*/
+typedef enum ifxhcd_epqh_phase {
+       EPQH_IDLE=0,
+       EPQH_DISABLING,
+//     EPQH_COMPLETING,
+       EPQH_STDBY,
+       EPQH_READY,
+       EPQH_ACTIVE
+} ifxhcd_epqh_phase_e;
+
+/* Phases for control transfers.*/
+typedef enum ifxhcd_urbd_phase {
+       URBD_IDLE=0,
+       URBD_ACTIVE,
+       URBD_STARTING,
+       URBD_STARTED,
+       URBD_FINISHING,    //URB_Complete already scheduled
+       URBD_COMPLETING,   //To URB_Complete, it's normal finish
+       URBD_DEQUEUEING,   //To URB_Complete, it's abnormal finish
+} ifxhcd_urbd_phase_e;
+
+/* Phases for control transfers.*/
+typedef enum ifxhcd_hc_phase {
+       HC_IDLE=0,
+       HC_ASSIGNED,
+       HC_WAITING,
+       HC_STARTING,
+       HC_STARTED,
+       HC_STOPPING,
+       HC_STOPPED,
+} ifxhcd_hc_phase_e;
+
+/*!
+  \addtogroup IFXUSB_HCD
+ */
+/*@{*/
+
+/*! \typedef  ifxhcd_control_phase_e
+       \brief Phases for control transfers.
+*/
+
+typedef enum ifxhcd_control_phase {
+       IFXHCD_CONTROL_SETUP,
+       IFXHCD_CONTROL_DATA,
+       IFXHCD_CONTROL_STATUS
+} ifxhcd_control_phase_e;
+
+/*! \typedef  ifxhcd_halt_status_e
+       \brief Reasons for halting a host channel.
+*/
+typedef enum ifxhcd_halt_status
+{
+       HC_XFER_NO_HALT_STATUS,         // Initial
+       HC_XFER_COMPLETE,               // Xact complete without error, upward
+       HC_XFER_URB_COMPLETE,           // Xfer complete without error, short upward
+       HC_XFER_STALL,                  // HC stopped abnormally, upward/downward
+       HC_XFER_XACT_ERR,               // HC stopped abnormally, upward
+       HC_XFER_FRAME_OVERRUN,          // HC stopped abnormally, upward
+       HC_XFER_BABBLE_ERR,             // HC stopped abnormally, upward
+       HC_XFER_AHB_ERR,                // HC stopped abnormally, upward
+       HC_XFER_DATA_TOGGLE_ERR,
+       HC_XFER_URB_DEQUEUE,            // HC stopper manually, downward
+       HC_XFER_NO_URB,                 // HC stopper manually, downward
+       HC_XFER_NO_EPQH,                // HC stopper manually, downward
+       #ifdef __NAKSTOP__
+               HC_XFER_NAK,                // HC stopped by nak monitor, downward
+       #endif
+       #if defined(__INTRNAKRETRY__) || defined(__INTRINCRETRY__)
+               HC_XFER_INTR_NAK_RETRY,     // HC stopped by nak monitor, downward
+       #endif
+} ifxhcd_halt_status_e;
+
+struct ifxhcd_urbd;
+struct ifxhcd_hc ;
+struct ifxhcd_epqh ;
+struct ifxhcd_hcd;
+
+/*! typedef ifxhcd_urbd_t
+ \brief A URB Descriptor (URBD) holds the state of a bulk, control,
+  interrupt, or isochronous transfer. A single URBD is created for each URB
+  (of one of these types) submitted to the HCD. The transfer associated with
+  a URBD may require one or multiple transactions.
+
+  A URBD is linked to a EP Queue Head, which is entered in either the
+  isoc, intr or non-periodic schedule for execution. When a URBD is chosen for
+  execution, some or all of its transactions may be executed. After
+  execution, the state of the URBD is updated. The URBD may be retired if all
+  its transactions are complete or if an error occurred. Otherwise, it
+  remains in the schedule so more transactions can be executed later.
+ */
+typedef struct ifxhcd_urbd {
+       ifxhcd_urbd_phase_e       phase;
+       struct list_head          ql;               // Hook for EPQH->urbd_list
+       struct urb               *urb;              /*!< URB for this transfer */
+                                                   //struct urb {
+                                                   //  struct list_head urb_list;
+                                                   //  struct list_head anchor_list;
+                                                   //  struct usb_anchor * anchor;
+                                                   //  struct usb_device * dev;
+                                                   //  struct usb_host_endpoint * ep;
+                                                   //  unsigned int pipe;
+                                                   //  int status;
+                                                   //  unsigned int transfer_flags;
+                                                   //  void * transfer_buffer;
+                                                   //  dma_addr_t transfer_dma;
+                                                   //  u32 transfer_buffer_length;
+                                                   //  u32 actual_length;
+                                                   //  unsigned char * setup_packet;
+                                                   //  dma_addr_t setup_dma;
+                                                   //  int start_frame;
+                                                   //  int number_of_packets;
+                                                   //  int interval;
+                                                   //  int error_count;
+                                                   //  void * context;
+                                                   //  usb_complete_t complete;
+                                                   //  struct usb_iso_packet_descriptor iso_frame_desc[0];
+                                                   //};
+                                                   //urb_list         For use by current owner of the URB.
+                                                   //anchor_list      membership in the list of an anchor
+                                                   //anchor           to anchor URBs to a common mooring
+                                                   //dev              Identifies the USB device to perform the request.
+                                                   //ep               Points to the endpoint's data structure. Will
+                                                   //                 eventually replace pipe.
+                                                   //pipe             Holds endpoint number, direction, type, and more.
+                                                   //                 Create these values with the eight macros available; u
+                                                   //                 sb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is
+                                                   //                  "ctrl", "bulk", "int" or "iso". For example
+                                                   //                 usb_sndbulkpipe or usb_rcvintpipe. Endpoint numbers
+                                                   //                 range from zero to fifteen. Note that "in" endpoint two
+                                                   //                 is a different endpoint (and pipe) from "out" endpoint
+                                                   //                 two. The current configuration controls the existence,
+                                                   //                 type, and maximum packet size of any given endpoint.
+                                                   //status           This is read in non-iso completion functions to get
+                                                   //                 the status of the particular request. ISO requests
+                                                   //                 only use it to tell whether the URB was unlinked;
+                                                   //                 detailed status for each frame is in the fields of
+                                                   //                 the iso_frame-desc.
+                                                   //transfer_flags   A variety of flags may be used to affect how URB
+                                                   //                 submission, unlinking, or operation are handled.
+                                                   //                 Different kinds of URB can use different flags.
+                                                   //                      URB_SHORT_NOT_OK
+                                                   //                      URB_ISO_ASAP
+                                                   //                      URB_NO_TRANSFER_DMA_MAP
+                                                   //                      URB_NO_SETUP_DMA_MAP
+                                                   //                      URB_NO_FSBR
+                                                   //                      URB_ZERO_PACKET
+                                                   //                      URB_NO_INTERRUPT
+                                                   //transfer_buffer  This identifies the buffer to (or from) which the I/O
+                                                   //                 request will be performed (unless URB_NO_TRANSFER_DMA_MAP
+                                                   //                 is set). This buffer must be suitable for DMA; allocate it
+                                                   //                 with kmalloc or equivalent. For transfers to "in"
+                                                   //                 endpoints, contents of this buffer will be modified. This
+                                                   //                 buffer is used for the data stage of control transfers.
+                                                   //transfer_dma     When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, the
+                                                   //                 device driver is saying that it provided this DMA address,
+                                                   //                 which the host controller driver should use in preference
+                                                   //                 to the transfer_buffer.
+                                                   //transfer_buffer_length How big is transfer_buffer. The transfer may be broken
+                                                   //                 up into chunks according to the current maximum packet size
+                                                   //                 for the endpoint, which is a function of the configuration
+                                                   //                 and is encoded in the pipe. When the length is zero, neither
+                                                   //                 transfer_buffer nor transfer_dma is used.
+                                                   //actual_length    This is read in non-iso completion functions, and it tells
+                                                   //                 how many bytes (out of transfer_buffer_length) were transferred.
+                                                   //                 It will normally be the same as requested, unless either an error
+                                                   //                 was reported or a short read was performed. The URB_SHORT_NOT_OK
+                                                   //                 transfer flag may be used to make such short reads be reported
+                                                   //                 as errors.
+                                                   //setup_packet     Only used for control transfers, this points to eight bytes of
+                                                   //                 setup data. Control transfers always start by sending this data
+                                                   //                 to the device. Then transfer_buffer is read or written, if needed.
+                                                   //setup_dma        For control transfers with URB_NO_SETUP_DMA_MAP set, the device
+                                                   //                 driver has provided this DMA address for the setup packet. The
+                                                   //                 host controller driver should use this in preference to setup_packet.
+                                                   //start_frame      Returns the initial frame for isochronous transfers.
+                                                   //number_of_packets Lists the number of ISO transfer buffers.
+                                                   //interval         Specifies the polling interval for interrupt or isochronous transfers.
+                                                   //                 The units are frames (milliseconds) for for full and low speed devices,
+                                                   //                 and microframes (1/8 millisecond) for highspeed ones.
+                                                   //error_count      Returns the number of ISO transfers that reported errors.
+                                                   //context          For use in completion functions. This normally points to request-specific
+                                                   //                 driver context.
+                                                   //complete         Completion handler. This URB is passed as the parameter to the completion
+                                                   //                 function. The completion function may then do what it likes with the URB,
+                                                   //                 including resubmitting or freeing it.
+                                                   //iso_frame_desc[0] Used to provide arrays of ISO transfer buffers and to collect the transfer
+                                                   //                 status for each buffer.
+
+       struct ifxhcd_epqh       *epqh;
+                                                // Actual data portion, not SETUP or STATUS in case of CTRL XFER
+                                                // DMA adjusted
+       uint8_t                  *setup_buff;       /*!< Pointer to the entire transfer buffer. (CPU accessable)*/
+       uint8_t                  *xfer_buff;        /*!< Pointer to the entire transfer buffer. (CPU accessable)*/
+       uint32_t                  xfer_len;         /*!< Total number of bytes to transfer in this xfer. */
+
+       #if   defined(__UNALIGNED_BUF_ADJ__)
+//             uint8_t using_aligned_setup;
+               uint8_t *aligned_setup;
+//             uint8_t using_aligned_buf;
+               uint8_t *aligned_buf;
+               unsigned aligned_buf_len : 19;
+       #endif
+       #if   defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__)
+               unsigned aligned_checked :  1;
+       #endif
+       unsigned     is_in           :1;
+       #ifndef __STRICT_ORDER__
+               struct tasklet_struct  complete_urb_sub;
+       #endif
+
+                                 // For ALL XFER
+       uint8_t                   error_count;    /*!< Holds the number of bus errors that have occurred for a transaction
+                                                      within this transfer.
+                                                  */
+                                 // For ISOC XFER only
+       #ifdef __EN_ISOC__
+               int                   isoc_frame_index; /*!< Index of the next frame descriptor for an isochronous transfer. A
+                                                            frame descriptor describes the buffer position and length of the
+                                                            data to be transferred in the next scheduled (micro)frame of an
+                                                            isochronous transfer. It also holds status for that transaction.
+                                                            The frame index starts at 0.
+                                                        */
+       #endif
+       int status;
+} ifxhcd_urbd_t;
+
+/*! typedef ifxhcd_epqh_t
+ \brief A EP Queue Head (EPQH) holds the static characteristics of an endpoint and
+ maintains a list of transfers (URBDs) for that endpoint. A EPQH structure may
+ be entered in either the isoc, intr or non-periodic schedule.
+ */
+
+typedef struct ifxhcd_epqh {
+       struct ifxhcd_hcd    *ifxhcd;
+       struct usb_host_endpoint *sysep;
+       uint8_t devno;
+
+       ifxhcd_epqh_phase_e  phase;
+       struct list_head     ql_all;
+       struct list_head     ql;                // Hook for EP Queues
+       struct list_head     urbd_list;         /*!< List of URBDs for this EPQH. */
+       #ifdef __STRICT_ORDER__
+               struct list_head     release_list;
+               struct tasklet_struct  complete_urb_sub;
+       #endif
+       struct ifxhcd_hc    *hc;                /*!< Host channel currently processing transfers for this EPQH. */
+       struct ifxhcd_urbd  *urbd;              /*!< URBD currently assigned to a host channel for this EPQH. */
+       uint8_t              ep_type;           /*!< Endpoint type. One of the following values:
+                                                    - IFXUSB_EP_TYPE_CTRL
+                                                    - IFXUSB_EP_TYPE_ISOC
+                                                    - IFXUSB_EP_TYPE_BULK
+                                                    - IFXUSB_EP_TYPE_INTR
+                                                */
+       uint16_t             mps;               /*!< wMaxPacketSize Field of Endpoint Descriptor. */
+       #ifdef __EPQD_DESTROY_TIMEOUT__
+               struct timer_list destroy_timer;
+       #endif
+
+       unsigned need_split     : 1 ;
+       unsigned do_ping        : 1 ; /*!< Set to 1 to indicate that a PING request should be issued on this
+                                         channel. If 0, process normally.
+                                     */
+       unsigned pause          : 1;
+       unsigned period_do      : 1;
+       uint16_t             interval;          /*!< Interval between transfers in (micro)frames. (for INTR)*/
+       uint16_t             period_counter;    /*!< Interval between transfers in (micro)frames. */
+
+       #ifdef __EN_ISOC__
+               struct tasklet_struct  tasklet_next_isoc;
+               uint8_t               isoc_now;
+               uint32_t              isoc_start_frame;
+                                 // For SPLITed ISOC XFER only
+               #ifdef __EN_ISOC_SPLIT__
+                       uint8_t           isoc_split_pos;   /*!< Position of the ISOC split on full/low speed */
+                       uint16_t          isoc_split_offset;/*!< Position of the ISOC split in the buffer for the current frame */
+               #endif
+       #endif
+       spinlock_t      urbd_list_lock;
+       int urbd_count;
+} ifxhcd_epqh_t;
+
+
+/*! typedef ifxhcd_hc_t
+ \brief Host channel descriptor. This structure represents the state of a single
+ host channel when acting in host mode. It contains the data items needed to
+ transfer packets to an endpoint via a host channel.
+ */
+typedef struct ifxhcd_hc
+{
+       struct ifxhcd_epqh *epqh        ; /*!< EP Queue Head for the transfer being processed by this channel. */
+       uint8_t  hc_num                 ; /*!< Host channel number used for register address lookup */
+       uint8_t *xfer_buff              ; /*!< Pointer to the entire transfer buffer. */
+       uint32_t xfer_count             ; /*!< Number of bytes transferred so far. The offset of the begin of the buf */
+       uint32_t xfer_len               ; /*!< Total number of bytes to transfer in this xfer. */
+       uint16_t start_pkt_count        ; /*!< Packet count at start of transfer. Used to calculate the actual xfer size*/
+       ifxhcd_halt_status_e halt_status; /*!< Reason for halting the host channel. */
+       ifxhcd_hc_phase_e  phase;
+
+       unsigned dev_addr       : 7; /*!< Device to access */
+       unsigned ep_num         : 4; /*!< EP to access */
+       unsigned is_in          : 1; /*!< EP direction. 0: OUT, 1: IN */
+       unsigned speed          : 2; /*!< EP speed. */
+       unsigned ep_type        : 2; /*!< Endpoint type. */
+       unsigned mps            :11; /*!< Max packet size in bytes */
+       unsigned data_pid_start : 2; /*!< PID for initial transaction. */
+       unsigned short_rw       : 1; /*!< When Tx, means termination needed.
+                                         When Rx, indicate Short Read  */
+       /* Split settings for the host channel */
+       unsigned split          : 2; /*!< Split: 0-Non Split, 1-SSPLIT, 2&3 CSPLIT */
+
+       unsigned sof_delay      :16;
+       unsigned erron          : 1;
+
+       #ifdef __NAKSTOP__
+               unsigned stop_on            : 1;
+//             unsigned wait_for_sof_quick : 1;
+       #endif
+
+       ifxhcd_control_phase_e    control_phase;  /*!< Current phase for control transfers (Setup, Data, or Status). */
+       uint32_t ssplit_out_xfer_count; /*!< How many bytes transferred during SSPLIT OUT */
+       #ifdef __DEBUG__
+               uint32_t          start_hcchar_val;
+       #endif
+       uint32_t hcchar;
+
+       /* Split settings for the host channel */
+       uint8_t hub_addr;          /*!< Address of high speed hub */
+       uint8_t port_addr;         /*!< Port of the low/full speed device */
+       #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
+               uint8_t isoc_xact_pos;          /*!< Split transaction position */
+       #endif
+} ifxhcd_hc_t;
+
+
+/*! typedef ifxhcd_hcd_t
+ \brief This structure holds the state of the HCD, including the non-periodic and
+ periodic schedules.
+ */
+typedef struct ifxhcd_hcd
+{
+       struct device *dev;
+       struct hc_driver hc_driver;
+       ifxusb_core_if_t core_if;   /*!< Pointer to the core interface structure. */
+       struct usb_hcd *syshcd;
+
+       volatile union
+       {
+               uint32_t d32;
+               struct
+               {
+                       unsigned port_connect_status_change : 1;
+                       unsigned port_connect_status        : 1;
+                       unsigned port_reset_change          : 1;
+                       unsigned port_enable_change         : 1;
+                       unsigned port_suspend_change        : 1;
+                       unsigned port_over_current_change   : 1;
+                       unsigned reserved                   : 27;
+               } b;
+       } flags; /*!< Internal HCD Flags */
+
+       struct ifxhcd_hc ifxhc[MAX_EPS_CHANNELS];         /*!< Array of pointers to the host channel descriptors. Allows accessing
+                                                              a host channel descriptor given the host channel number. This is
+                                                              useful in interrupt handlers.
+                                                          */
+       uint8_t   *status_buf;                            /*!< Buffer to use for any data received during the status phase of a
+                                                              control transfer. Normally no data is transferred during the status
+                                                              phase. This buffer is used as a bit bucket.
+                                                          */
+               #define IFXHCD_STATUS_BUF_SIZE 64             /*!< buffer size of status phase in CTRL xfer */
+
+       struct list_head epqh_list_all;
+       struct list_head epqh_list_np;
+       struct list_head epqh_list_intr;
+       #ifdef __EN_ISOC__
+               struct list_head epqh_list_isoc;
+       #endif
+
+       uint32_t lastframe;
+
+       uint16_t pkt_remaining;
+       uint16_t pkt_remaining_reload;
+       uint16_t pkt_remaining_reload_hs;
+       uint16_t pkt_remaining_reload_fs;
+       uint16_t pkt_remaining_reload_ls;
+               #define PKT_REMAINING_RELOAD_HS  88
+               #define PKT_REMAINING_RELOAD_FS  10
+               #define PKT_REMAINING_RELOAD_LS  20
+       #ifdef __EN_ISOC__
+               uint8_t isoc_ep_count;
+       #endif
+
+       spinlock_t      epqh_list_lock;
+       spinlock_t      epqh_list_all_lock;
+
+       struct timer_list host_probe_timer;
+       struct timer_list autoprobe_timer;
+
+       unsigned        power_status;
+       int             probe_sec;
+       int             autoprobe_sec;
+       #ifdef __DYN_SOF_INTR__
+               uint32_t dyn_sof_count;
+               #define DYN_SOF_COUNT_DEF 40000
+       #endif
+       struct tasklet_struct  tasklet_select_eps;        /*!<  Tasket to do a reset */
+       struct tasklet_struct  tasklet_free_epqh_list ;        /*!<  Tasket to do a reset */
+       unsigned disconnecting     : 1 ;
+
+       uint8_t              pkt_count_limit_bo;
+       uint8_t              pkt_count_limit_bi;
+} ifxhcd_hcd_t;
+
+/* Gets the ifxhcd_hcd from a struct usb_hcd */
+static inline ifxhcd_hcd_t *syshcd_to_ifxhcd(struct usb_hcd *syshcd)
+{
+       return (ifxhcd_hcd_t *)(syshcd->hcd_priv[0]);
+}
+
+/* Gets the struct usb_hcd that contains a ifxhcd_hcd_t. */
+static inline struct usb_hcd *ifxhcd_to_syshcd(ifxhcd_hcd_t *ifxhcd)
+{
+       return (struct usb_hcd *)(ifxhcd->syshcd);
+}
+
+
+extern ifxhcd_epqh_t * sysep_to_epqh(ifxhcd_hcd_t *_ifxhcd, struct usb_host_endpoint *_sysep);
+
+/* HCD Create/Destroy Functions */
+       extern int  ifxhcd_init  (ifxhcd_hcd_t *_ifxhcd);
+       extern void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd);
+
+/*Linux HC Driver API Functions */
+
+extern int  ifxhcd_start(struct usb_hcd *hcd);
+extern void ifxhcd_stop (struct usb_hcd *hcd);
+extern int  ifxhcd_get_frame_number(struct usb_hcd *hcd);
+
+
+/*!
+   \brief This function does the setup for a data transfer for a host channel and
+  starts the transfer. May be called in either Slave mode or DMA mode. In
+  Slave mode, the caller must ensure that there is sufficient space in the
+  request queue and Tx Data FIFO.
+
+  For an OUT transfer in Slave mode, it loads a data packet into the
+  appropriate FIFO. If necessary, additional data packets will be loaded in
+  the Host ISR.
+
+  For an IN transfer in Slave mode, a data packet is requested. The data
+  packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
+  additional data packets are requested in the Host ISR.
+
+  For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+  register along with a packet count of 1 and the channel is enabled. This
+  causes a single PING transaction to occur. Other fields in HCTSIZ are
+  simply set to 0 since no data transfer occurs in this case.
+
+  For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+  all the information required to perform the subsequent data transfer. In
+  addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+  controller performs the entire PING protocol, then starts the data
+  transfer.
+
+  @param _ifxhc Information needed to initialize the host channel. The xfer_len
+  value may be reduced to accommodate the max widths of the XferSize and
+  PktCnt fields in the HCTSIZn register. The multi_count value may be changed
+  to reflect the final xfer_len value.
+ */
+extern void ifxhcd_hc_start(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep, struct urb *_urb, gfp_t mem_flags);
+extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb);
+#else
+extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct urb *_urb, gfp_t mem_flags);
+extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb, int status);
+#endif
+extern irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd);
+
+extern void ifxhcd_endpoint_disable(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep);
+
+extern int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf);
+extern int ifxhcd_hub_control( struct usb_hcd *_syshcd,
+                               u16             _typeReq,
+                               u16             _wValue,
+                               u16             _wIndex,
+                               char           *_buf,
+                               u16             _wLength);
+
+/*@}*/
+
+/*! \brief Transaction Execution Functions */
+/*@{*/
+extern void                      ifxhcd_complete_urb       (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd,  int _status);
+
+/*!
+   \brief Clears the transfer state for a host channel. This function is normally
+  called after a transfer is done and the host channel is being released.
+ */
+extern void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc);
+
+/*!
+   \brief Attempts to halt a host channel. This function should only be called in
+  Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
+  normal circumstances in DMA mode, the controller halts the channel when the
+  transfer is complete or a condition occurs that requires application
+  intervention.
+
+  In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+  HCCHARn register. The controller ensures there is space in the request
+  queue before submitting the halt request.
+
+  Some time may elapse before the core flushes any posted requests for this
+  host channel and halts. The Channel Halted interrupt handler completes the
+  deactivation of the host channel.
+ */
+extern int ifxhcd_hc_halt(ifxusb_core_if_t *_core_if,
+                    ifxhcd_hc_t *_ifxhc,
+                    ifxhcd_halt_status_e _halt_status);
+
+/*!
+   \brief Prepares a host channel for transferring packets to/from a specific
+  endpoint. The HCCHARn register is set up with the characteristics specified
+  in _ifxhc. Host channel interrupts that may need to be serviced while this
+  transfer is in progress are enabled.
+ */
+extern void ifxhcd_hc_init(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc);
+
+/*!
+   \brief This function is called to handle the disconnection of host port.
+ */
+int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd);
+/*@}*/
+
+/*!  \brief Interrupt Handler Functions */
+/*@{*/
+extern irqreturn_t ifxhcd_oc_irq(int _irq, void *_dev);
+
+extern int32_t ifxhcd_handle_oc_intr(ifxhcd_hcd_t *_ifxhcd);
+extern int32_t ifxhcd_handle_intr   (ifxhcd_hcd_t *_ifxhcd);
+/*@}*/
+
+
+/*! \brief Schedule Queue Functions */
+/*@{*/
+extern void           ifxhcd_epqh_free   (ifxhcd_epqh_t *_epqh);
+extern void           select_eps      (ifxhcd_hcd_t *_ifxhcd);
+extern void           ifxhcd_epqh_idle(ifxhcd_epqh_t *_epqh);
+extern void           ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh);
+extern ifxhcd_epqh_t *ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb);
+/*@}*/
+
+/*! \brief Gets the usb_host_endpoint associated with an URB. */
+static inline struct usb_host_endpoint *ifxhcd_urb_to_endpoint(struct urb *_urb)
+{
+       struct usb_device *dev = _urb->dev;
+       int    ep_num = usb_pipeendpoint(_urb->pipe);
+
+       return (usb_pipein(_urb->pipe))?(dev->ep_in[ep_num]):(dev->ep_out[ep_num]);
+}
+
+/*!
+ * \brief Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
+ * qualified with its direction (possible 32 endpoints per device).
+ */
+#define ifxhcd_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
+                                                       ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
+
+
+
+/*! Internal debug function */
+void         ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd);
+
+/*@}*//*IFXUSB_HCD*/
+
+extern struct usb_device *usb_alloc_dev  (struct usb_device *parent, struct usb_bus *, unsigned port);
+extern int                usb_add_hcd    (struct usb_hcd *syshcd, unsigned int irqnum, unsigned long irqflags);
+extern void               usb_remove_hcd (struct usb_hcd *syshcd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+extern struct usb_hcd    *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name);
+#else
+extern struct usb_hcd    *usb_create_hcd (const struct hc_driver *driver, struct device *dev, const char *bus_name);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+extern void               usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb);
+#else
+extern void               usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb,int status);
+#endif
+
+extern void               usb_put_hcd       (struct usb_hcd *syshcd);
+extern long               usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount);
+extern char *syserr(int errno);
+
+
+
+static inline void INIT_EPQH_LIST_ALL(ifxhcd_hcd_t   *_ifxhcd)
+{
+       spin_lock_init(&_ifxhcd->epqh_list_all_lock);
+}
+static inline void LOCK_EPQH_LIST_ALL(ifxhcd_hcd_t   *_ifxhcd)
+{
+       spin_lock(&_ifxhcd->epqh_list_all_lock);
+}
+static inline void UNLOCK_EPQH_LIST_ALL(ifxhcd_hcd_t *_ifxhcd)
+{
+       spin_unlock(&_ifxhcd->epqh_list_all_lock);
+}
+
+static inline void INIT_EPQH_LIST(ifxhcd_hcd_t   *_ifxhcd)
+{
+       spin_lock_init(&_ifxhcd->epqh_list_lock);
+}
+static inline void LOCK_EPQH_LIST(ifxhcd_hcd_t   *_ifxhcd)
+{
+       spin_lock(&_ifxhcd->epqh_list_lock);
+}
+static inline void UNLOCK_EPQH_LIST(ifxhcd_hcd_t *_ifxhcd)
+{
+       spin_unlock(&_ifxhcd->epqh_list_lock);
+}
+
+static inline void INIT_URBD_LIST(ifxhcd_epqh_t    *_epqh)
+{
+       spin_lock_init(&_epqh->urbd_list_lock);
+}
+static inline void LOCK_URBD_LIST(ifxhcd_epqh_t    *_epqh)
+{
+       spin_lock(&_epqh->urbd_list_lock);
+}
+static inline void UNLOCK_URBD_LIST(ifxhcd_epqh_t  *_epqh)
+{
+       spin_unlock(&_epqh->urbd_list_lock);
+}
+
+#endif // __IFXHCD_H__
+
diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c
new file mode 100644 (file)
index 0000000..a7d18dd
--- /dev/null
@@ -0,0 +1,599 @@
+/*****************************************************************************
+ **   FILE NAME       : ifxhcd_es.c
+ **   PROJECT         : IFX USB sub-system V3
+ **   MODULES         : IFX USB sub-system Host and Device driver
+ **   SRC VERSION     : 1.0
+ **   DATE            : 1/Jan/2009
+ **   AUTHOR          : Chen, Howard
+ **   DESCRIPTION     : The file contain function to enable host mode USB-IF Electrical Test function.
+ **   FUNCTIONS       :
+ **   COMPILER        : gcc
+ **   REFERENCE       : Synopsys DWC-OTG Driver 2.7
+ **   COPYRIGHT       :  Copyright (c) 2010
+ **                      LANTIQ DEUTSCHLAND GMBH,
+ **                      Am Campeon 3, 85579 Neubiberg, Germany
+ **
+ **    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.
+ **
+ **  Version Control Section  **
+ **   $Author$
+ **   $Date$
+ **   $Revisions$
+ **   $Log$       Revision history
+ *****************************************************************************/
+
+/*
+ * This file contains code fragments from Synopsys HS OTG Linux Software Driver.
+ * For this code the following notice is applicable:
+ *
+ * ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/*!
+ \file ifxhcd_es.c
+ \ingroup IFXUSB_DRIVER_V3
+ \brief The file contain function to enable host mode USB-IF Electrical Test function.
+*/
+
+#include <linux/version.h>
+#include "ifxusb_version.h"
+
+#include <linux/kernel.h>
+
+#include <linux/errno.h>
+
+#include <linux/dma-mapping.h>
+
+#include "ifxusb_plat.h"
+#include "ifxusb_regs.h"
+#include "ifxusb_cif.h"
+#include "ifxhcd.h"
+
+
+#ifdef __WITH_HS_ELECT_TST__
+       /*
+        * Quick and dirty hack to implement the HS Electrical Test
+        * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
+        *
+        * This code was copied from our userspace app "hset". It sends a
+        * Get Device Descriptor control sequence in two parts, first the
+        * Setup packet by itself, followed some time later by the In and
+        * Ack packets. Rather than trying to figure out how to add this
+        * functionality to the normal driver code, we just hijack the
+        * hardware, using these two function to drive the hardware
+        * directly.
+        */
+
+
+       void do_setup(ifxusb_core_if_t *_core_if)
+       {
+
+               ifxusb_core_global_regs_t *global_regs    = _core_if->core_global_regs;
+               ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs;
+               ifxusb_hc_regs_t          *hc_regs        = _core_if->hc_regs[0];
+               uint32_t                  *data_fifo      = _core_if->data_fifo[0];
+
+               gint_data_t    gintsts;
+               hctsiz_data_t  hctsiz;
+               hcchar_data_t  hcchar;
+               haint_data_t   haint;
+               hcint_data_t   hcint;
+
+
+               /* Enable HAINTs */
+               ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001);
+
+               /* Enable HCINTs */
+               ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+               /* Read HAINT */
+               haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+               //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+               /* Read HCINT */
+               hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+               //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+               /* Read HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+               /* Clear HCINT */
+               ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+               /* Clear HAINT */
+               ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+               /* Clear GINTSTS */
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+               /*
+                * Send Setup packet (Get Device Descriptor)
+                */
+
+               /* Make sure channel is disabled */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               if (hcchar.b.chen) {
+                       //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32);
+                       hcchar.b.chdis = 1;
+       //              hcchar.b.chen = 1;
+                       ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+                       //sleep(1);
+                       mdelay(1000);
+
+                       /* Read GINTSTS */
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+                       //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+                       /* Read HAINT */
+                       haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+                       //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+                       /* Read HCINT */
+                       hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+                       //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+                       /* Read HCCHAR */
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+                       /* Clear HCINT */
+                       ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+                       /* Clear HAINT */
+                       ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+                       /* Clear GINTSTS */
+                       ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       //if (hcchar.b.chen) {
+                       //      fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32);
+                       //}
+               }
+
+               /* Set HCTSIZ */
+               hctsiz.d32 = 0;
+               hctsiz.b.xfersize = 8;
+               hctsiz.b.pktcnt = 1;
+               hctsiz.b.pid = IFXUSB_HC_PID_SETUP;
+               ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
+
+               /* Set HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL;
+               hcchar.b.epdir = 0;
+               hcchar.b.epnum = 0;
+               hcchar.b.mps = 8;
+               hcchar.b.chen = 1;
+               ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+
+               /* Fill FIFO with Setup data for Get Device Descriptor */
+               ifxusb_wreg(data_fifo++, 0x01000680);
+               ifxusb_wreg(data_fifo++, 0x00080000);
+
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Wait for host channel interrupt */
+               do {
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               } while (gintsts.b.hcintr == 0);
+
+               //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Disable HCINTs */
+               ifxusb_wreg(&hc_regs->hcintmsk, 0x0000);
+
+               /* Disable HAINTs */
+               ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000);
+
+               /* Read HAINT */
+               haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+               //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+               /* Read HCINT */
+               hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+               //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+               /* Read HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+               /* Clear HCINT */
+               ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+               /* Clear HAINT */
+               ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+               /* Clear GINTSTS */
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+       }
+
+       void do_in_ack(ifxusb_core_if_t *_core_if)
+       {
+
+               ifxusb_core_global_regs_t *global_regs    = _core_if->core_global_regs;
+               ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs;
+               ifxusb_hc_regs_t          *hc_regs        = _core_if->hc_regs[0];
+               uint32_t                  *data_fifo      = _core_if->data_fifo[0];
+
+               gint_data_t        gintsts;
+               hctsiz_data_t      hctsiz;
+               hcchar_data_t      hcchar;
+               haint_data_t       haint;
+               hcint_data_t       hcint;
+               grxsts_data_t      grxsts;
+
+               /* Enable HAINTs */
+               ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001);
+
+               /* Enable HCINTs */
+               ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+               /* Read HAINT */
+               haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+               //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+               /* Read HCINT */
+               hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+               //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+               /* Read HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+               /* Clear HCINT */
+               ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+               /* Clear HAINT */
+               ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+               /* Clear GINTSTS */
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+               /*
+                * Receive Control In packet
+                */
+
+               /* Make sure channel is disabled */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               if (hcchar.b.chen) {
+                       //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32);
+                       hcchar.b.chdis = 1;
+                       hcchar.b.chen = 1;
+                       ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+                       //sleep(1);
+                       mdelay(1000);
+
+                       /* Read GINTSTS */
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+                       //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+                       /* Read HAINT */
+                       haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+                       //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+                       /* Read HCINT */
+                       hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+                       //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+                       /* Read HCCHAR */
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+                       /* Clear HCINT */
+                       ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+                       /* Clear HAINT */
+                       ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+                       /* Clear GINTSTS */
+                       ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       //if (hcchar.b.chen) {
+                       //      fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32);
+                       //}
+               }
+
+               /* Set HCTSIZ */
+               hctsiz.d32 = 0;
+               hctsiz.b.xfersize = 8;
+               hctsiz.b.pktcnt = 1;
+               hctsiz.b.pid = IFXUSB_HC_PID_DATA1;
+               ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
+
+               /* Set HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL;
+               hcchar.b.epdir = 1;
+               hcchar.b.epnum = 0;
+               hcchar.b.mps = 8;
+               hcchar.b.chen = 1;
+               ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Wait for receive status queue interrupt */
+               do {
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               } while (gintsts.b.rxstsqlvl == 0);
+
+               //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Read RXSTS */
+               grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp);
+               //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32);
+
+               /* Clear RXSTSQLVL in GINTSTS */
+               gintsts.d32 = 0;
+               gintsts.b.rxstsqlvl = 1;
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               switch (grxsts.hb.pktsts) {
+                       case IFXUSB_HSTS_DATA_UPDT:
+                               /* Read the data into the host buffer */
+                               if (grxsts.hb.bcnt > 0) {
+                                       int i;
+                                       int word_count = (grxsts.hb.bcnt + 3) / 4;
+
+                                       for (i = 0; i < word_count; i++) {
+                                               (void)ifxusb_rreg(data_fifo++);
+                                       }
+                               }
+
+                               //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.hb.bcnt);
+                               break;
+
+                       default:
+                               //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n");
+                               break;
+               }
+
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Wait for receive status queue interrupt */
+               do {
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               } while (gintsts.b.rxstsqlvl == 0);
+
+               //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Read RXSTS */
+               grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp);
+               //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32);
+
+               /* Clear RXSTSQLVL in GINTSTS */
+               gintsts.d32 = 0;
+               gintsts.b.rxstsqlvl = 1;
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               switch (grxsts.hb.pktsts) {
+                       case IFXUSB_HSTS_XFER_COMP:
+                               break;
+
+                       default:
+                               //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n");
+                               break;
+               }
+
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Wait for host channel interrupt */
+               do {
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               } while (gintsts.b.hcintr == 0);
+
+               //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Read HAINT */
+               haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+               //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+               /* Read HCINT */
+               hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+               //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+               /* Read HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+               /* Clear HCINT */
+               ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+               /* Clear HAINT */
+               ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+               /* Clear GINTSTS */
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+       //      usleep(100000);
+       //      mdelay(100);
+               mdelay(1);
+
+               /*
+                * Send handshake packet
+                */
+
+               /* Read HAINT */
+               haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+               //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+               /* Read HCINT */
+               hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+               //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+               /* Read HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+               /* Clear HCINT */
+               ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+               /* Clear HAINT */
+               ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+               /* Clear GINTSTS */
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+               /* Make sure channel is disabled */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               if (hcchar.b.chen) {
+                       //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32);
+                       hcchar.b.chdis = 1;
+                       hcchar.b.chen = 1;
+                       ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+                       //sleep(1);
+                       mdelay(1000);
+
+                       /* Read GINTSTS */
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+                       //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+
+                       /* Read HAINT */
+                       haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+                       //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+                       /* Read HCINT */
+                       hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+                       //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+                       /* Read HCCHAR */
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+                       /* Clear HCINT */
+                       ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+                       /* Clear HAINT */
+                       ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+                       /* Clear GINTSTS */
+                       ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+                       hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+                       //if (hcchar.b.chen) {
+                       //      fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32);
+                       //}
+               }
+
+               /* Set HCTSIZ */
+               hctsiz.d32 = 0;
+               hctsiz.b.xfersize = 0;
+               hctsiz.b.pktcnt = 1;
+               hctsiz.b.pid = IFXUSB_HC_PID_DATA1;
+               ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
+
+               /* Set HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL;
+               hcchar.b.epdir = 0;
+               hcchar.b.epnum = 0;
+               hcchar.b.mps = 8;
+               hcchar.b.chen = 1;
+               ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
+
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Wait for host channel interrupt */
+               do {
+                       gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               } while (gintsts.b.hcintr == 0);
+
+               //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32);
+
+               /* Disable HCINTs */
+               ifxusb_wreg(&hc_regs->hcintmsk, 0x0000);
+
+               /* Disable HAINTs */
+               ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000);
+
+               /* Read HAINT */
+               haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
+               //fprintf(stderr, "HAINT: %08x\n", haint.d32);
+
+               /* Read HCINT */
+               hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
+               //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
+
+               /* Read HCCHAR */
+               hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
+               //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
+
+               /* Clear HCINT */
+               ifxusb_wreg(&hc_regs->hcint, hcint.d32);
+
+               /* Clear HAINT */
+               ifxusb_wreg(&hc_global_regs->haint, haint.d32);
+
+               /* Clear GINTSTS */
+               ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
+
+               /* Read GINTSTS */
+               gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
+               //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
+       }
+#endif //__WITH_HS_ELECT_TST__
+
diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c
new file mode 100644 (file)
index 0000000..27885bb
--- /dev/null
@@ -0,0 +1,4844 @@
+/*****************************************************************************
+ **   FILE NAME       : ifxhcd_intr.c
+ **   PROJECT         : IFX USB sub-system V3
+ **   MODULES         : IFX USB sub-system Host and Device driver
+ **   SRC VERSION     : 3.2
+ **   DATE            : 1/Jan/2011
+ **   AUTHOR          : Chen, Howard
+ **   DESCRIPTION     : This file contains the implementation of the HCD Interrupt handlers.
+ **   FUNCTIONS       :
+ **   COMPILER        : gcc
+ **   REFERENCE       : Synopsys DWC-OTG Driver 2.7
+ **   COPYRIGHT       :  Copyright (c) 2010
+ **                      LANTIQ DEUTSCHLAND GMBH,
+ **                      Am Campeon 3, 85579 Neubiberg, Germany
+ **
+ **    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.
+ **
+ **  Version Control Section  **
+ **   $Author$
+ **   $Date$
+ **   $Revisions$
+ **   $Log$       Revision history
+ *****************************************************************************/
+
+/*
+ * This file contains code fragments from Synopsys HS OTG Linux Software Driver.
+ * For this code the following notice is applicable:
+ *
+ * ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/*!
+ \file ifxhcd_intr.c
+ \ingroup IFXUSB_DRIVER_V3
+ \brief This file contains the implementation of the HCD Interrupt handlers.
+*/
+
+
+#include <linux/version.h>
+#include "ifxusb_version.h"
+
+#include "ifxusb_plat.h"
+#include "ifxusb_regs.h"
+#include "ifxusb_cif.h"
+
+#include "ifxhcd.h"
+
+/* Macro used to clear one channel interrupt */
+#define clear_hc_int(_hc_regs_,_intr_) \
+       do { \
+               hcint_data_t hcint_clear = {.d32 = 0}; \
+               hcint_clear.b._intr_ = 1; \
+               ifxusb_wreg(&((_hc_regs_)->hcint), hcint_clear.d32); \
+       } while (0)
+
+/*
+ * Macro used to disable one channel interrupt. Channel interrupts are
+ * disabled when the channel is halted or released by the interrupt handler.
+ * There is no need to handle further interrupts of that type until the
+ * channel is re-assigned. In fact, subsequent handling may cause crashes
+ * because the channel structures are cleaned up when the channel is released.
+ */
+#define disable_hc_int(_hc_regs_,_intr_) \
+       do { \
+               hcint_data_t hcintmsk = {.d32 = 0}; \
+               hcintmsk.b._intr_ = 1; \
+               ifxusb_mreg(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \
+       } while (0)
+
+#define enable_hc_int(_hc_regs_,_intr_) \
+       do { \
+               hcint_data_t hcintmsk = {.d32 = 0}; \
+               hcintmsk.b._intr_ = 1; \
+               ifxusb_mreg(&((_hc_regs_)->hcintmsk),0, hcintmsk.d32); \
+       } while (0)
+
+/*
+ * Save the starting data toggle for the next transfer. The data toggle is
+ * saved in the QH for non-control transfers and it's saved in the QTD for
+ * control transfers.
+ */
+uint8_t read_data_toggle(ifxusb_hc_regs_t *_hc_regs)
+{
+       hctsiz_data_t hctsiz;
+       hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz);
+       return(hctsiz.b.pid);
+}
+
+
+static void release_channel_dump(ifxhcd_hc_t      *ifxhc,
+                               struct urb       *urb,
+                               ifxhcd_epqh_t    *epqh,
+                               ifxhcd_urbd_t    *urbd,
+                               ifxhcd_halt_status_e  halt_status)
+{
+       #ifdef __DEBUG__
+               printk(KERN_INFO);
+               switch (halt_status)
+               {
+                       case HC_XFER_NO_HALT_STATUS:
+                               printk("HC_XFER_NO_HALT_STATUS");break;
+                       case HC_XFER_URB_COMPLETE:
+                               printk("HC_XFER_URB_COMPLETE");break;
+                       case HC_XFER_AHB_ERR:
+                               printk("HC_XFER_AHB_ERR");break;
+                       case HC_XFER_STALL:
+                               printk("HC_XFER_STALL");break;
+                       case HC_XFER_BABBLE_ERR:
+                               printk("HC_XFER_BABBLE_ERR");break;
+                       case HC_XFER_XACT_ERR:
+                               printk("HC_XFER_XACT_ERR");break;
+                       case HC_XFER_URB_DEQUEUE:
+                               printk("HC_XFER_URB_DEQUEUE");break;
+                       case HC_XFER_FRAME_OVERRUN:
+                               printk("HC_XFER_FRAME_OVERRUN");break;
+                       case HC_XFER_DATA_TOGGLE_ERR:
+                               printk("HC_XFER_DATA_TOGGLE_ERR");break;
+               #ifdef __NAKSTOP__
+                       case HC_XFER_NAK:
+                               printk("HC_XFER_NAK");break;
+               #endif
+                       case HC_XFER_COMPLETE:
+                               printk("HC_XFER_COMPLETE");break;
+                       default:
+                               printk("KNOWN");break;
+               }
+               if(ifxhc)
+                       printk("Ch %d %s%s S%d " , ifxhc->hc_num
+                               ,(ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)?"CTRL-":
+                                  ((ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)?"BULK-":
+                                    ((ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)?"INTR-":
+                                      ((ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)?"ISOC-":"????"
+                                      )
+                                    )
+                                  )
+                               ,(ifxhc->is_in)?"IN":"OUT"
+                               ,(ifxhc->split)
+                               );
+               else
+                       printk(" [NULL HC] ");
+               printk("urb=%p epqh=%p urbd=%p\n",urb,epqh,urbd);
+
+               if(urb)
+               {
+                       printk(KERN_INFO "  Device address: %d\n", usb_pipedevice(urb->pipe));
+                       printk(KERN_INFO "  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
+                                   (usb_pipein(urb->pipe) ? "IN" : "OUT"));
+                       printk(KERN_INFO "  Endpoint type: %s\n",
+                                   ({char *pipetype;
+                                   switch (usb_pipetype(urb->pipe)) {
+                                           case PIPE_CONTROL: pipetype = "CTRL"; break;
+                                           case PIPE_BULK: pipetype = "BULK"; break;
+                                           case PIPE_INTERRUPT: pipetype = "INTR"; break;
+                                           case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break;
+                                           default: pipetype = "????"; break;
+                                   }; pipetype;}));
+                       printk(KERN_INFO "  Speed: %s\n",
+                                   ({char *speed;
+                                   switch (urb->dev->speed) {
+                                           case USB_SPEED_HIGH: speed = "HS"; break;
+                                           case USB_SPEED_FULL: speed = "FS"; break;
+                                           case USB_SPEED_LOW: speed = "LS"; break;
+                                       default: speed = "????"; break;
+                                   }; speed;}));
+                       printk(KERN_INFO "  Max packet size: %d\n",
+                                   usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
+                       printk(KERN_INFO "  Data buffer length: %d/%d\n",urb->actual_length, urb->transfer_buffer_length);
+                       printk(KERN_INFO "  Transfer buffer: %p, Transfer DMA: %p\n",
+                                   urb->transfer_buffer, (void *)urb->transfer_dma);
+                       printk(KERN_INFO "  Setup buffer: %p, Setup DMA: %p\n",
+                                   urb->setup_packet, (void *)urb->setup_dma);
+                       printk(KERN_INFO "  Interval: %d\n", urb->interval);
+               }
+               if(urbd)
+               {
+                       switch (urbd->status)
+                       {
+                               case HC_XFER_NO_HALT_STATUS:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_NO_HALT_STATUS\n");break;
+                               case HC_XFER_URB_COMPLETE:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_URB_COMPLETE\n");break;
+                               case HC_XFER_AHB_ERR:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_AHB_ERR\n");break;
+                               case HC_XFER_STALL:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_STALL\n");break;
+                               case HC_XFER_BABBLE_ERR:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_BABBLE_ERR\n");break;
+                               case HC_XFER_XACT_ERR:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_XACT_ERR\n");break;
+                               case HC_XFER_URB_DEQUEUE:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_URB_DEQUEUE\n");break;
+                               case HC_XFER_FRAME_OVERRUN:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_FRAME_OVERRUN\n");break;
+                               case HC_XFER_DATA_TOGGLE_ERR:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_DATA_TOGGLE_ERR\n");break;
+                               case HC_XFER_COMPLETE:
+                                       printk(KERN_INFO "  STATUS:HC_XFER_COMPLETE\n");break;
+                               default:
+                                       printk(KERN_INFO "  STATUS:UNKKNOWN %d\n",urbd->status);break;
+                       }
+               }
+       #endif
+}
+
+/*!
+        \fn    static void release_channel(ifxhcd_hcd_t          *_ifxhcd,
+                            ifxhcd_hc_t           *_ifxhc,
+                            ifxhcd_halt_status_e  _halt_status)
+        \brief Release the halted channel.
+        \param _ifxhcd Pointer to the sate of HCD structure
+        \param _ifxhc Pointer to host channel descriptor
+        \param _halt_status Halt satus
+        \return None
+        \ingroup  IFXUSB_HCD
+ */
+
+static void release_channel(ifxhcd_hcd_t          *_ifxhcd,
+                            ifxhcd_hc_t           *_ifxhc,
+                            ifxhcd_halt_status_e  _halt_status)
+{
+       ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num];
+       struct urb       *urb     = NULL;
+       ifxhcd_epqh_t    *epqh    = NULL;
+       ifxhcd_urbd_t    *urbd    = NULL;
+
+       IFX_DEBUGPL(DBG_HCDV, "  %s: channel %d, halt_status %d\n",
+                   __func__, _ifxhc->hc_num, _halt_status);
+
+       epqh=_ifxhc->epqh;
+
+       if(!epqh)
+       {
+               if(_halt_status!=HC_XFER_NO_EPQH)
+                       IFX_ERROR("%s epqh=null\n",__func__);
+       }
+       else
+       {
+               urbd=epqh->urbd;
+               if(!urbd)
+                       IFX_ERROR("%s urbd=null\n",__func__);
+               else
+               {
+                       urb=urbd->urb;
+                       if(!urb)
+                       {
+                               if(_halt_status!=HC_XFER_NO_URB)
+                                       IFX_ERROR("%s urb =null\n",__func__);
+                       }
+                       else
+                       {
+                               if      (read_data_toggle(hc_regs) == IFXUSB_HCTSIZ_DATA0)
+                                       usb_settoggle (urb->dev,usb_pipeendpoint (urb->pipe), (_ifxhc->is_in)?0:1,0);
+                               else if (read_data_toggle(hc_regs) == IFXUSB_HCTSIZ_DATA1)
+                                       usb_settoggle (urb->dev,usb_pipeendpoint (urb->pipe), (_ifxhc->is_in)?0:1,1);
+                       }
+               }
+       }
+
+       switch (_halt_status)
+       {
+               case HC_XFER_NO_HALT_STATUS:
+                       IFX_ERROR("%s: No halt_status, channel %d\n", __func__, _ifxhc->hc_num);
+//                     return;
+                       break;
+               case HC_XFER_COMPLETE:
+                       IFX_ERROR("%s: Inavalid halt_status HC_XFER_COMPLETE, channel %d\n", __func__, _ifxhc->hc_num);
+//                     return;
+                       break;
+               case HC_XFER_NO_URB:
+                       break;
+               case HC_XFER_NO_EPQH:
+                       break;
+               case HC_XFER_URB_DEQUEUE:
+               case HC_XFER_AHB_ERR:
+               case HC_XFER_XACT_ERR:
+               case HC_XFER_FRAME_OVERRUN:
+                       if(urbd && urb)
+                       {
+                               urbd->phase=URBD_DEQUEUEING;
+                               ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status);
+                       }
+                       else
+                       {
+                               IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb);
+                               release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+                       }
+                       break;
+               case HC_XFER_URB_COMPLETE:
+                       if(urbd && urb)
+                       {
+                               urbd->phase=URBD_COMPLETING;
+                               ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status);
+                       }
+                       else
+                       {
+                               IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb);
+                               release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+                       }
+                       break;
+               case HC_XFER_STALL:
+                       if(urbd)
+                       {
+                               urbd->phase=URBD_DEQUEUEING;
+                               ifxhcd_complete_urb(_ifxhcd, urbd, -EPIPE);
+                       }
+                       else
+                       {
+                               IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb);
+                               release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+                       }
+                       if(epqh && urb && urb->dev && urb->pipe)
+                               usb_settoggle(urb->dev, usb_pipeendpoint (urb->pipe), !usb_pipein(urb->pipe), IFXUSB_HC_PID_DATA0);
+                       break;
+               case HC_XFER_BABBLE_ERR:
+               case HC_XFER_DATA_TOGGLE_ERR:
+                       if(urbd)
+                       {
+                               urbd->phase=URBD_DEQUEUEING;
+                               ifxhcd_complete_urb(_ifxhcd, urbd, -EOVERFLOW);
+                       }
+                       else
+                       {
+                               IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb);
+                               release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+                       }
+                       break;
+       #ifdef __NAKSTOP__
+               case HC_XFER_NAK:
+                       if (_ifxhc->is_in)
+                       {
+                               if(urbd && urb)
+                               {
+                                       urbd->phase=URBD_COMPLETING;
+                                       ifxhcd_complete_urb(_ifxhcd, urbd, 0);
+                               }
+                               else
+                               {
+                                       IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb);
+                                       release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+                               }
+                       }
+                       else
+                       {
+                               IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb);
+                               release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+                       }
+                       break;
+       #endif
+       #if defined(__INTRNAKRETRY__) || defined(__INTRINCRETRY__)
+               case HC_XFER_INTR_NAK_RETRY:
+                       epqh->phase=EPQH_READY;
+                       urbd->phase=URBD_IDLE;
+                       ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc);
+                       select_eps(_ifxhcd);
+                       return;
+                       break;
+                       
+       #endif
+       }
+       if(epqh)
+       {
+               ifxhcd_epqh_idle(epqh);
+       }
+       else if(_halt_status!=HC_XFER_NO_EPQH)
+       {
+               IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh);
+               release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status);
+       }
+       ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc);
+       select_eps(_ifxhcd);
+}
+
+/*
+ * Updates the state of the URB after a Transfer Complete interrupt on the
+ * host channel. Updates the actual_length field of the URB based on the
+ * number of bytes transferred via the host channel. Sets the URB status
+ * if the data transfer is finished.
+ *
+ * @return 1 if the data transfer specified by the URB is completely finished,
+ * 0 otherwise.
+ */
+static int update_urb_state_xfer_comp(ifxhcd_hc_t       *_ifxhc,
+                                      ifxusb_hc_regs_t  *_hc_regs,
+                                      struct urb        *_urb,
+                                      ifxhcd_urbd_t      *_urbd)
+{
+       int xfer_done  = 0;
+
+       #ifdef __EN_ISOC__
+       if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_ISOC)
+       {
+               struct usb_iso_packet_descriptor *frame_desc;
+               frame_desc            = &_urb->iso_frame_desc[_urbd->isoc_frame_index];
+               if (_ifxhc->is_in)
+               {
+                       hctsiz_data_t hctsiz;
+                       hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz);
+                       frame_desc->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                       if ((hctsiz.b.xfersize != 0) || (frame_desc->actual_length >= _urbd->xfer_len))
+                       {
+                               xfer_done = 1;
+                               frame_desc->status = 0;
+                               #if 0
+                                       if (frame_desc->actual_length < frame_desc->length && _urb->transfer_flags & URB_SHORT_NOT_OK)
+                                               frame_desc->status = -EREMOTEIO;
+                               #endif
+                       }
+               }
+               else
+               {
+                       if (_ifxhc->split)
+                               frame_desc->actual_length +=  _ifxhc->ssplit_out_xfer_count;
+                       else
+                               frame_desc->actual_length +=  _ifxhc->xfer_len;
+                       if (frame_desc->actual_length >= _urbd->xfer_len)
+                       {
+                               xfer_done = 1;
+                               frame_desc->status = 0;
+                       }
+               }
+       }
+       else
+       #endif
+       if (_ifxhc->is_in)
+       {
+               hctsiz_data_t hctsiz;
+               hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz);
+               _urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+#ifdef __INTRINCRETRY__
+               if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_INTR)
+               {
+                       if(_ifxhc->xfer_len != hctsiz.b.xfersize)
+                       {
+                               xfer_done = 1;
+                               _urbd->status = 0;
+                       }
+               }
+               else 
+#endif
+               if ((hctsiz.b.xfersize != 0) || (_urb->actual_length >= _urb->transfer_buffer_length))
+               {
+                       xfer_done = 1;
+                       _urbd->status = 0;
+                       if(_urb->transfer_flags & URB_SHORT_NOT_OK)
+                       {
+                               if (_urb->actual_length < _urb->transfer_buffer_length)
+                                       _urbd->status = -EREMOTEIO;
+                       }
+               }
+       }
+       else if(_urb->transfer_buffer_length%_ifxhc->mps) // OUT without ZLP
+       {
+               if (_ifxhc->split)
+                       _urb->actual_length +=  _ifxhc->ssplit_out_xfer_count;
+               else
+                       _urb->actual_length +=  _ifxhc->xfer_len;
+               if (_urb->actual_length >= _urb->transfer_buffer_length)
+               {
+                       xfer_done = 1;
+                       _urbd->status = 0;
+               }
+       }
+       else if (_urb->actual_length >= _urb->transfer_buffer_length) //OUT with ZLP
+       {
+               xfer_done = 1;
+               _urbd->status = 0;
+       }
+       else //OUT without ZLP, unfinished
+       {
+               if (_ifxhc->split)
+                       _urb->actual_length +=  _ifxhc->ssplit_out_xfer_count;
+               else
+                       _urb->actual_length +=  _ifxhc->xfer_len;
+               if (!_ifxhc->short_rw && _urb->actual_length >= _urb->transfer_buffer_length)
+               {
+                       xfer_done = 1;
+                       _urbd->status = 0;
+               }
+       }
+
+       #ifdef __DEBUG__
+               {
+                       hctsiz_data_t   hctsiz;
+                       hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz);
+                       IFX_DEBUGPL(DBG_HCDV, "IFXUSB: %s: %s, channel %d\n",
+                                   __func__, (_ifxhc->is_in ? "IN" : "OUT"), _ifxhc->hc_num);
+                       IFX_DEBUGPL(DBG_HCDV, "  hc->xfer_len %d\n", _ifxhc->xfer_len);
+                       IFX_DEBUGPL(DBG_HCDV, "  hctsiz.xfersize %d\n", hctsiz.b.xfersize);
+                       #ifdef __EN_ISOC__
+                       if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_ISOC)
+                       {
+                               IFX_DEBUGPL(DBG_HCDV, "  descritor # %d\n", _urbd->isoc_frame_index);
+                               IFX_DEBUGPL(DBG_HCDV, "  buffer_length %d\n",
+                                       _urb->iso_frame_desc[_urbd->isoc_frame_index].length);
+                               IFX_DEBUGPL(DBG_HCDV, "  actual_length %d\n", _urb->iso_frame_desc[_urbd->isoc_frame_index].actual_length);
+                       }
+                       else
+                       #endif
+                       {
+                               IFX_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+                                           _urb->transfer_buffer_length);
+                               IFX_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n", _urb->actual_length);
+                       }
+               }
+       #endif
+       return xfer_done;
+}
+
+#ifdef __EN_ISOC__
+       static void next_isoc_sub(unsigned long data)
+       {
+               ifxhcd_urbd_t *urbd;
+               ifxhcd_hcd_t *ifxhcd;
+
+               urbd=((ifxhcd_urbd_t *)data);
+               ifxhcd=urbd->epqh->ifxhcd;
+
+               if (!urbd->epqh)
+                       IFX_ERROR("%s: invalid epqd\n",__func__);
+               #if   defined(__UNALIGNED_BUF_ADJ__)
+               else
+               {
+                       if( urbd->aligned_checked   &&
+//                         urbd->using_aligned_buf &&
+                           urbd->xfer_buff &&
+                           urbd->is_in)
+                       {
+                               uint8_t *buf;
+
+                               buf=urbd->xfer_buff;
+                               buf+=urbd->urb->iso_frame_desc[urbd->isoc_frame_index].offset;
+                               memcpy(buf,urbd->aligned_buf,urbd->urb->iso_frame_desc[urbd->isoc_frame_index].length);
+                       }
+//                     urbd->using_aligned_buf=0;
+//                     urbd->using_aligned_setup=0;
+               }
+               #endif
+
+               urbd->isoc_frame_index++;
+               if(urbd->isoc_frame_index>=urbd->urb->number_of_packets)
+                       release_channel(ifxhcd,urbd->epqh->hc,HC_XFER_URB_COMPLETE);
+               else
+                       init_hc(urbd->epqh);
+       }
+#endif
+
+/*!
+        \fn    static void complete_channel(ifxhcd_hcd_t        *_ifxhcd,
+                            ifxhcd_hc_t          *_ifxhc,
+                            ifxhcd_urbd_t        *_urbd)
+        \brief Complete the transaction on the channel.
+        \param _ifxhcd Pointer to the sate of HCD structure
+        \param _ifxhc Pointer to host channel descriptor
+        \param _urbd Pointer to URB descriptor
+        \return None
+        \ingroup  IFXUSB_HCD
+ */
+static void complete_channel(ifxhcd_hcd_t        *_ifxhcd,
+                            ifxhcd_hc_t          *_ifxhc,
+                            ifxhcd_urbd_t        *_urbd)
+{
+       ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num];
+       struct urb    *urb  = NULL;
+       ifxhcd_epqh_t *epqh = NULL;
+       int urb_xfer_done;
+
+       IFX_DEBUGPL(DBG_HCD, "--Complete Channel %d : \n", _ifxhc->hc_num);
+
+       if(!_urbd)
+       {
+               IFX_ERROR("ERROR %s():%d urbd=%p\n",__func__,__LINE__,_urbd);
+               return;
+       }
+
+       urb  = _urbd->urb;
+       epqh = _urbd->epqh;
+
+       if(!epqh)
+       {
+               release_channel(_ifxhcd,_ifxhc,HC_XFER_NO_EPQH);
+               return;
+       }
+       if(!urb || (unsigned long)urb->hcpriv!=(unsigned long)_urbd)
+       {
+               release_channel(_ifxhcd,_ifxhc,HC_XFER_NO_URB);
+               return;
+       }
+
+       if (_ifxhc->split)
+               _ifxhc->split = 1;
+
+       switch (epqh->ep_type)
+       {
+               case IFXUSB_EP_TYPE_CTRL:
+                       switch (_ifxhc->control_phase)
+                       {
+                               case IFXHCD_CONTROL_SETUP:
+                                       if (_urbd->xfer_len > 0)
+                                       {
+                                               _ifxhc->control_phase = IFXHCD_CONTROL_DATA;
+                                               IFX_DEBUGPL(DBG_HCDV, "  Control setup transaction done Data Stage now\n");
+                                               _ifxhc->is_in         = _urbd->is_in;
+                                               _ifxhc->xfer_len      = _urbd->xfer_len;
+                                               #if   defined(__UNALIGNED_BUF_ADJ__)
+                                                       if(_urbd->aligned_buf)
+                                                               _ifxhc->xfer_buff      = _urbd->aligned_buf;
+                                                       else
+                                               #endif
+                                                               _ifxhc->xfer_buff      = _urbd->xfer_buff;
+                                               #ifdef __NAKSTOP__
+                                               if(!_ifxhc->split)
+                                               {
+                                                       #ifdef __INNAKSTOP_CTRL__
+                                                       if(_ifxhc->is_in)
+                                                               _ifxhc->stop_on=1;
+                                                       #endif
+                                                       #ifdef __PINGSTOP_CTRL__
+                                                       if(!_ifxhc->is_in)
+                                                               _ifxhc->stop_on=1;
+                                                       #endif
+                                               }
+                                               #endif
+                                       }
+                                       else
+                                       {
+                                               IFX_DEBUGPL(DBG_HCDV, "  Control setup transaction done Status Stage now\n");
+                                               _ifxhc->control_phase = IFXHCD_CONTROL_STATUS;
+                                               _ifxhc->is_in          = 1;
+                                               _ifxhc->xfer_len       = 0;
+                                               _ifxhc->xfer_buff      = _ifxhcd->status_buf;
+                                               #ifdef __NAKSTOP__
+                                                       _ifxhc->stop_on=0;
+                                               #endif
+                                       }
+                                       if(_ifxhc->is_in)
+                                               _ifxhc->short_rw       =0;
+                                       else
+                                               _ifxhc->short_rw       =(urb->transfer_flags & URB_ZERO_PACKET)?1:0;
+                                       _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
+                                       _ifxhc->xfer_count     = 0;
+                                       _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                                       _ifxhc->phase=HC_WAITING;
+                                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       break;
+                               case IFXHCD_CONTROL_DATA:
+                                       urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd);
+                                       if (urb_xfer_done)
+                                       {
+                                               _ifxhc->control_phase  = IFXHCD_CONTROL_STATUS;
+                                               IFX_DEBUGPL(DBG_HCDV, "  Control data transaction done Status Stage now\n");
+                                               _ifxhc->is_in          = (_urbd->is_in)?0:1;
+                                               _ifxhc->xfer_len       = 0;
+                                               _ifxhc->xfer_count     = 0;
+                                               _ifxhc->xfer_buff      = _ifxhcd->status_buf;
+                                               _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                                               _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
+                                               if(_ifxhc->is_in)
+                                                       _ifxhc->short_rw       =0;
+                                               else
+                                                       _ifxhc->short_rw       =1;
+                                               #ifdef __NAKSTOP__
+                                                       _ifxhc->stop_on=0;
+                                               #endif
+                                       }
+                                       else // continue
+                                       {
+                                               IFX_DEBUGPL(DBG_HCDV, "  Control data transaction continue\n");
+                                               _ifxhc->xfer_len       = _urbd->xfer_len - urb->actual_length;
+                                               _ifxhc->xfer_count     = urb->actual_length;
+                                               _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                                               _ifxhc->data_pid_start = read_data_toggle(hc_regs);
+                                       }
+                                       _ifxhc->phase=HC_WAITING;
+                                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       break;
+                               case IFXHCD_CONTROL_STATUS:
+                                       IFX_DEBUGPL(DBG_HCDV, "  Control status transaction done\n");
+                                       if (_urbd->status == -EINPROGRESS)
+                                               _urbd->status = 0;
+                                       release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE);
+                                       break;
+                       }
+                       break;
+               case IFXUSB_EP_TYPE_BULK:
+                       IFX_DEBUGPL(DBG_HCDV, "  Bulk transfer complete\n");
+                       urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd);
+                       if (urb_xfer_done)
+                               release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE);
+                       else
+                       {
+                               _ifxhc->xfer_len       = _urbd->xfer_len - urb->actual_length;
+                               _ifxhc->xfer_count     = urb->actual_length;
+                               _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                               _ifxhc->data_pid_start = read_data_toggle(hc_regs);
+                               _ifxhc->phase=HC_WAITING;
+                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                       }
+                       break;
+               case IFXUSB_EP_TYPE_INTR:
+                       urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd);
+                       
+                       #ifdef __INTRINCRETRY__
+                       if(!urb_xfer_done)
+                       release_channel(_ifxhcd,_ifxhc,HC_XFER_INTR_NAK_RETRY);
+                       else
+                       #endif
+                       release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE);
+                       break;
+               case IFXUSB_EP_TYPE_ISOC:
+                       #ifdef __EN_ISOC__
+                               urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd);
+                               if (urb_xfer_done)
+                               {
+                                       #if   defined(__UNALIGNED_BUF_ADJ__)
+                                       if(in_irq())
+                                       {
+                                               if(!epqh->tasklet_next_isoc.func)
+                                               {
+                                                       epqh->tasklet_next_isoc.next = NULL;
+                                                       epqh->tasklet_next_isoc.state = 0;
+                                                       atomic_set( &epqh->tasklet_next_isoc.count, 0);
+                                                       epqh->tasklet_next_isoc.func = next_isoc_sub;
+                                                       epqh->tasklet_next_isoc.data = (unsigned long)_urbd;
+                                               }
+                                               tasklet_schedule(&epqh->tasklet_next_isoc);
+                                       }
+                                       else
+                                       #endif
+                                       {
+                                               next_isoc_sub((unsigned long)_urbd);
+                                       }
+                               }
+                               else
+                               {
+                                       struct usb_iso_packet_descriptor *frame_desc;
+                                       frame_desc            = &urb->iso_frame_desc[_urbd->isoc_frame_index];
+                                       _ifxhc->xfer_len       = _urbd->xfer_len - frame_desc->actual_length;
+                                       _ifxhc->xfer_count     = frame_desc->actual_length;
+                                       _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                                       _ifxhc->data_pid_start = read_data_toggle(hc_regs);
+                                       _ifxhc->phase=HC_WAITING;
+                                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                               }
+                       #endif
+                       break;
+       }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_ctrl_rx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                        ifxhcd_hc_t       *_ifxhc,
+                                        ifxusb_hc_regs_t  *_hc_regs,
+                                        ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       #ifdef __INNAKSTOP_CTRL__
+       if (_ifxhc->halt_status == HC_XFER_NAK)
+       {
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       u32 actual_length;
+                       actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize);
+
+                       if(_urbd->xfer_len && actual_length >= _urbd->xfer_len)
+                       {
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       }
+                       else
+                       {
+                               _ifxhc->xfer_count        =
+                               _urbd->urb->actual_length = actual_length;
+                               _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                               _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                               _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                               _ifxhc->phase=HC_WAITING;
+                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                       }
+               }
+               else
+               {
+                       printk(KERN_INFO "Warning: %s() %d Invalid CTRL Phase:%d\n",__func__,__LINE__,_ifxhc->control_phase);
+                       release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status);
+               }
+               return 1;
+       }
+       #endif
+
+       if (hcint.b.xfercomp || hcint.d32 == 0x02)
+       {
+               _urbd->error_count     =0;
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else if (hcint.b.stall)
+       {
+               _urbd->error_count     =0;
+               // ZLP shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               #if 0
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+                               _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               }
+               return 1;
+       }
+       else if (hcint.b.bblerr)
+       {
+               _urbd->error_count     =0;
+
+               // ZLP shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               #if 0
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+                               _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               }
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               #if 1
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       #if 1
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       #else
+                               u32 actual_length;
+                               actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                               if(actual_length >= _urbd->xfer_len)
+                               {
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->error_count++;
+                                       _ifxhc->xfer_count        =
+                                       _urbd->urb->actual_length = actual_length;
+                                       _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                       if (_urbd->error_count >= 3)
+                                       {
+                                               _urbd->error_count     =0;
+                                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                                       }
+                                       else
+                                       {
+                                               _ifxhc->erron=1;
+                                               _ifxhc->phase=HC_WAITING;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               }
+                       #endif
+               }
+               else
+               {
+                       _urbd->error_count     =0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               #if 0
+                       #if 1
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       #else
+                               u32 actual_length;
+                               actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                               if(actual_length>=_urbd->xfer_len)
+                               {
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->urb->actual_length = actual_length;
+                                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                       _urbd->error_count     =0;
+                                       release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+                               }
+                       #endif
+               #else
+                       if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+                               _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               #endif
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+//             if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else
+       {
+               _urbd->error_count     =0;
+               IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X  %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status);
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               return 1;
+       }
+
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_ctrl_tx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                        ifxhcd_hc_t       *_ifxhc,
+                                        ifxusb_hc_regs_t  *_hc_regs,
+                                        ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       #ifdef __PINGSTOP_CTRL__
+       if (_ifxhc->halt_status == HC_XFER_NAK)
+       {
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       u32 actual_length;
+                       actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+
+                       if(_urbd->xfer_len && actual_length >= _urbd->xfer_len)
+                       {
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       }
+                       else
+                       {
+                               _ifxhc->xfer_count        =
+                               _urbd->urb->actual_length = actual_length;
+                               _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                               _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                               _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                               _ifxhc->phase=HC_WAITING;
+                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                       }
+               }
+               else
+               {
+                       printk(KERN_INFO "Warning: %s() %d Invalid CTRL Phase:%d\n",__func__,__LINE__,_ifxhc->control_phase);
+                       release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status);
+               }
+               return 1;
+       }
+       #endif
+
+
+       if (hcint.b.xfercomp || hcint.d32 == 0x02)
+       {
+               _urbd->error_count     =0;
+               if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak)
+               {
+                       // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr
+                       // Solution:   NoSplit: Resend at next SOF
+                       //             Split  : Resend at next SOF with SSPLIT
+                       if(hcint.b.nyet)
+                               _ifxhc->epqh->do_ping=1;
+
+                       _ifxhc->xfer_len       = 0;
+                       _ifxhc->xfer_count     = 0;
+                       _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               else
+               {
+                       if(hcint.b.nyet)
+                               _ifxhc->epqh->do_ping=1;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               return 1;
+       }
+       else if (hcint.b.stall)
+       {
+               _urbd->error_count     =0;
+
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+                       {
+                               _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+//                             if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+                       }
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               }
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else if(_ifxhc->control_phase == IFXHCD_CONTROL_SETUP)
+               {
+                       _urbd->error_count     =0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               else if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       #if 0
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       #else
+                               u32 actual_length;
+                               actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+                               if(actual_length>=_urbd->xfer_len)
+                               {
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->error_count++;
+                                       _ifxhc->xfer_count        =
+                                       _urbd->urb->actual_length = actual_length;
+                                       _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                       if (_urbd->error_count >= 3)
+                                       {
+                                               _urbd->error_count     =0;
+                                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                                       }
+                                       else
+                                       {
+                                               _ifxhc->erron=1;
+                                               _ifxhc->phase=HC_WAITING;
+                                               _ifxhc->epqh->do_ping=1;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               }
+                       #endif
+               }
+               else
+               {
+                       _urbd->error_count     =0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               return 1;
+       }
+       else if(hcint.b.bblerr     )
+       {
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               }
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.nak || hcint.b.nyet)
+       {
+               #ifdef __PINGSTOP_CTRL__
+                       _urbd->error_count     =0;
+                       IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               #else
+                       // ZLP shortcut
+                       #if 1
+                       if(hctsiz.b.pktcnt==0)
+                       {
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       }
+                       else
+                       #endif
+                       if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS)
+                       {
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       }
+                       else if(_ifxhc->control_phase == IFXHCD_CONTROL_SETUP)
+                       {
+                               _urbd->error_count     =0;
+                               IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__);
+                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                       }
+                       else if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+                       {
+                               #if 0
+                                       _ifxhc->epqh->do_ping=1;
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               #else
+                                       u32 actual_length;
+                                       _ifxhc->epqh->do_ping=1;
+                                       actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+                                       if(actual_length>=_urbd->xfer_len)
+                                       {
+                                               _urbd->error_count     =0;
+                                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                                       }
+                                       else
+                                       {
+                                               _ifxhc->xfer_count        =
+                                               _urbd->urb->actual_length = actual_length;
+                                               _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                                               _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                               _ifxhc->erron=1;
+                                               _ifxhc->epqh->do_ping=1;
+                                               _ifxhc->phase=HC_WAITING;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               #endif
+                       }
+               #endif
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               }
+               _urbd->error_count     =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+               if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
+               {
+                       _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               }
+               _urbd->error_count     =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else
+       {
+               _urbd->error_count     =0;
+               IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X  %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status);
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               return 1;
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_bulk_rx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                        ifxhcd_hc_t       *_ifxhc,
+                                        ifxusb_hc_regs_t  *_hc_regs,
+                                        ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       #ifdef __INNAKSTOP_BULK__
+       if(_ifxhc->halt_status == HC_XFER_NAK)
+       {
+               u32 actual_length;
+               actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize);
+
+               if(
+                  (_urbd->xfer_len && actual_length>=_urbd->xfer_len)
+                  || hctsiz.b.pktcnt==0
+                  || (hctsiz.b.xfersize % _ifxhc->mps)>0
+                 )
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               {
+                       _urbd->urb->actual_length = actual_length;
+                       _ifxhc->xfer_len          = _urbd->xfer_len - _urbd->urb->actual_length;
+                       _ifxhc->xfer_count        = _urbd->urb->actual_length;
+                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                       _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               return 1;
+       }
+       #endif
+
+       if (hcint.b.xfercomp || hcint.d32 == 0x02)
+       {
+               _urbd->error_count     =0;
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else if (hcint.b.stall)
+       {
+               _urbd->error_count     =0;
+               // ZLP shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               }
+               return 1;
+       }
+       else if (hcint.b.bblerr)
+       {
+               _urbd->error_count     =0;
+
+               // ZLP shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               }
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               {
+                       #if 0
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       #else
+                               u32 actual_length;
+                               actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                               if(actual_length >= _urbd->xfer_len)
+                               {
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->error_count++;
+                                       _ifxhc->xfer_count        =
+                                       _urbd->urb->actual_length = actual_length;
+                                       _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                       if (_urbd->error_count >= 3)
+                                       {
+                                               _urbd->error_count     =0;
+                                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                                       }
+                                       else
+                                       {
+                                               _ifxhc->erron=1;
+                                               _ifxhc->phase=HC_WAITING;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               }
+                       #endif
+               }
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               #if 0
+                       #if 1
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       #else
+                               u32 actual_length;
+                               actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                               if(actual_length >= _urbd->xfer_len)
+                               {
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->urb->actual_length = actual_length;
+                                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                       _urbd->error_count     =0;
+                                       release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+                               }
+                       #endif
+               #else
+                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+//                     if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               #endif
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+//             if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else
+       {
+               _urbd->error_count     =0;
+               IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d sz:%d/%d/%d/%d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status , hctsiz.b.xfersize, _ifxhc->xfer_len-_ifxhc->xfer_len,_ifxhc->xfer_len,_urbd->xfer_len);
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               return 1;
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_bulk_tx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                        ifxhcd_hc_t       *_ifxhc,
+                                        ifxusb_hc_regs_t  *_hc_regs,
+                                        ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+       int out_nak_enh = 0;
+
+       if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH)
+               out_nak_enh = 1;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       #ifdef __PINGSTOP_BULK__
+       if (_ifxhc->halt_status == HC_XFER_NAK)
+       {
+               u32 actual_length;
+               actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+
+               if(_urbd->xfer_len && actual_length >= _urbd->xfer_len)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               {
+                       _ifxhc->xfer_count        =
+                       _urbd->urb->actual_length = actual_length;
+                       _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                       _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               return 1;
+       }
+       #endif
+
+       if (hcint.b.xfercomp || hcint.d32 == 0x02)
+       {
+               _urbd->error_count     =0;
+               if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak)
+               {
+                       // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr
+                       // Solution:   NoSplit: Resend at next SOF
+                       //             Split  : Resend at next SOF with SSPLIT
+                       if(hcint.b.nyet)
+                               _ifxhc->epqh->do_ping=1;
+
+                       _ifxhc->xfer_len       = 0;
+                       _ifxhc->xfer_count     = 0;
+                       _ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               else
+               {
+                       if(hcint.b.nyet)
+                               _ifxhc->epqh->do_ping=1;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               return 1;
+       }
+       else if (hcint.b.stall)
+       {
+               _urbd->error_count     =0;
+
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+                       if(_urbd->urb->actual_length>_urbd->xfer_len) _urbd->urb->actual_length=_urbd->xfer_len;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               }
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               {
+                       #if 0
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       #else
+                               u32 actual_length;
+                               actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+                               if(actual_length >= _urbd->xfer_len)
+                               {
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->error_count++;
+                                       _ifxhc->xfer_count        =
+                                       _urbd->urb->actual_length = actual_length;
+                                       _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                                       _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                       if (_urbd->error_count >= 3)
+                                       {
+                                               _urbd->error_count     =0;
+                                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                                       }
+                                       else
+                                       {
+                                               _ifxhc->erron=1;
+                                               _ifxhc->phase=HC_WAITING;
+                                               _ifxhc->epqh->do_ping=1;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               }
+                       #endif
+               }
+               return 1;
+       }
+       else if(hcint.b.bblerr     )
+       {
+               _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+               if(_urbd->urb->actual_length>_urbd->xfer_len) _urbd->urb->actual_length=_urbd->xfer_len;
+               IFX_ERROR("ERROR %s():%d invalid packet babble\n",__func__,__LINE__);
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.nak || hcint.b.nyet)
+       {
+               #ifdef __PINGSTOP_BULK__
+                       _urbd->error_count     =0;
+                       IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               #else
+                       // ZLP shortcut
+                       #if 1
+                       if(hctsiz.b.pktcnt==0)
+                       {
+                               _urbd->error_count     =0;
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       }
+                       else
+                       #endif
+                       {
+                               #if 0
+                                       _ifxhc->epqh->do_ping=1;
+                                       _urbd->error_count     =0;
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               #else
+                                       u32 actual_length;
+                                       _ifxhc->epqh->do_ping=1;
+                                       actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+                                       if(actual_length>=_urbd->xfer_len)
+                                       {
+                                               _urbd->error_count     =0;
+                                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                                       }
+                                       else
+                                       {
+                                               _ifxhc->xfer_count        =
+                                               _urbd->urb->actual_length = actual_length;
+                                               _ifxhc->xfer_len          = _urbd->xfer_len - actual_length;
+                                               _ifxhc->data_pid_start    = read_data_toggle(_hc_regs);
+                                               _ifxhc->erron=1;
+                                               _ifxhc->epqh->do_ping=1;
+                                               _ifxhc->phase=HC_WAITING;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               #endif
+                       }
+               #endif
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+//             if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               _urbd->error_count     =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+               _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+//             if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len;
+               _urbd->error_count     =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else
+       {
+               _urbd->error_count     =0;
+               IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X  %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status);
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               return 1;
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_intr_rx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                    ifxhcd_hc_t       *_ifxhc,
+                                    ifxusb_hc_regs_t  *_hc_regs,
+                                    ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       if (hcint.b.xfercomp || hcint.d32 == 0x02)
+       {
+               _urbd->error_count   =0;
+               //restart INTR immediately
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else if (hcint.b.stall)
+       {
+               _urbd->error_count   =0;
+
+               // Don't care shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               }
+               return 1;
+       }
+       else if (hcint.b.bblerr)
+       {
+               _urbd->error_count   =0;
+
+               // Don't care shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               }
+               return 1;
+       }
+       else if (hcint.b.datatglerr || hcint.b.frmovrun)
+       {
+               _urbd->error_count   =0;
+               //restart INTR immediately
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               {
+                       _urbd->error_count++;
+                       if(_urbd->error_count>=3)
+                       {
+                               _urbd->error_count     =0;
+                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                       }
+                       else
+                       {
+                               _ifxhc->phase=HC_WAITING;
+                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                       }
+               }
+               return 1;
+       }
+       else if(hcint.b.nyet   )
+       {
+               return 1;
+       }
+       else if (hcint.b.nak)
+       {
+               
+               #ifdef __INTRNAKRETRY__
+               if(hctsiz.b.pktcnt)
+               {
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_INTR_NAK_RETRY);
+                       return 1;
+               }
+               #endif
+               _urbd->error_count   =0;
+               //restart INTR immediately
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else
+       {
+               _urbd->error_count   =0;
+               //restart INTR immediately
+               #if 0
+               if(hctsiz.b.pktcnt>0)
+               {
+                       // TODO Re-initialize Channel (in next b_interval - 1 uF/F)
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               else
+               #endif
+               {
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               return 1;
+       }
+
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_intr_tx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                    ifxhcd_hc_t       *_ifxhc,
+                                    ifxusb_hc_regs_t  *_hc_regs,
+                                    ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+       int out_nak_enh = 0;
+
+       if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH)
+               out_nak_enh = 1;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+       if (hcint.b.xfercomp || hcint.d32 == 0x02)
+       {
+               disable_hc_int(_hc_regs,ack);
+               disable_hc_int(_hc_regs,nak);
+               disable_hc_int(_hc_regs,nyet);
+               _urbd->error_count   =0;
+               //restart INTR immediately
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else if (hcint.b.stall)
+       {
+               disable_hc_int(_hc_regs,ack);
+               disable_hc_int(_hc_regs,nyet);
+               disable_hc_int(_hc_regs,nak);
+               _urbd->error_count   =0;
+
+               // Don't care shortcut
+               #if 0
+               if(hctsiz.b.pktcnt==0)
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               else
+               #endif
+               {
+                       if(_ifxhc->xfer_len!=0)// !_ifxhc->is_in
+                               _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps);
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               }
+               return 1;
+       }
+       else if(hcint.b.nak || hcint.b.frmovrun )
+       {
+               disable_hc_int(_hc_regs,ack);
+               disable_hc_int(_hc_regs,nyet);
+               disable_hc_int(_hc_regs,nak);
+               _urbd->error_count   =0;
+               //restart INTR immediately
+               complete_channel(_ifxhcd, _ifxhc, _urbd);
+               return 1;
+       }
+       else if(hcint.b.xacterr    )
+       {
+               // ZLP shortcut
+               #if 1
+               if(hctsiz.b.pktcnt==0)
+               {
+                       _urbd->error_count     =0;
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+               }
+               else
+               #endif
+               {
+                       _urbd->error_count++;
+                       if(_urbd->error_count>=3)
+                       {
+                               _urbd->error_count     =0;
+                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                       }
+                       else
+                       {
+                               _ifxhc->phase=HC_WAITING;
+                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                       }
+               }
+               return 1;
+       }
+       else if(hcint.b.bblerr     )
+       {
+               _urbd->error_count     =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               _urbd->error_count     =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               return 1;
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_isoc_rx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                    ifxhcd_hc_t       *_ifxhc,
+                                    ifxusb_hc_regs_t  *_hc_regs,
+                                    ifxhcd_urbd_t     *_urbd)
+{
+       #ifdef __EN_ISOC__
+               hcint_data_t  hcint;
+               hcint_data_t  hcintmsk;
+               hctsiz_data_t hctsiz;
+
+               hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+               hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+               hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+               if (hcint.b.xfercomp || hcint.b.frmovrun || hcint.d32 == 0x02)
+               {
+                       _urbd->error_count=0;
+                       disable_hc_int(_hc_regs,ack);
+                       disable_hc_int(_hc_regs,nak);
+                       disable_hc_int(_hc_regs,nyet);
+                       if (hcint.b.xfercomp)
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       else
+                               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               }
+               else if (hcint.b.xacterr || hcint.b.bblerr)
+               {
+                       #ifndef VR9Skip
+                               if(hctsiz.b.pktcnt==0)
+                               {
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                                       _ifxhc->xfer_len           = _urbd->xfer_len - _urbd->urb->actual_length;
+                                       _ifxhc->xfer_count         = _urbd->urb->actual_length;
+                                       _ifxhc->data_pid_start = read_data_toggle(_hc_regs);
+                                       _urbd->error_count++;
+                                       if(_urbd->error_count>=3)
+                                       {
+                                               _urbd->error_count=0;
+                                               if (hcint.b.bblerr)
+                                                       release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+                                               else if (hcint.b.xacterr)
+                                                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                                       }
+                                       else
+                                       {
+                                               enable_hc_int(_hc_regs,ack);
+                                               enable_hc_int(_hc_regs,nak);
+                                               enable_hc_int(_hc_regs,nyet);
+                                               _ifxhc->phase=HC_WAITING;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               }
+                       #endif
+               }
+               else if(hcint.b.datatglerr )
+               {
+                       return 1;
+               }
+               else if(hcint.b.stall      )
+               {
+                       return 1;
+               }
+       #endif
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_isoc_tx_nonsplit(ifxhcd_hcd_t      *_ifxhcd,
+                                    ifxhcd_hc_t       *_ifxhc,
+                                    ifxusb_hc_regs_t  *_hc_regs,
+                                    ifxhcd_urbd_t     *_urbd)
+{
+       #ifdef __EN_ISOC__
+               hcint_data_t  hcint;
+               hcint_data_t  hcintmsk;
+               hctsiz_data_t hctsiz;
+               int out_nak_enh = 0;
+
+               if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH)
+                       out_nak_enh = 1;
+
+               hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+               hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+               hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+               if (hcint.b.xfercomp || hcint.d32 == 0x02)
+               {
+                       _urbd->error_count=0;
+                       disable_hc_int(_hc_regs,ack);
+                       disable_hc_int(_hc_regs,nak);
+                       disable_hc_int(_hc_regs,nyet);
+                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                       return 1;
+               }
+               else if (hcint.b.frmovrun)
+               {
+                       #ifndef VR9Skip
+                               _urbd->error_count=0;
+                               disable_hc_int(_hc_regs,ack);
+                               disable_hc_int(_hc_regs,nak);
+                               disable_hc_int(_hc_regs,nyet);
+                               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+                       #endif
+               }
+               else if(hcint.b.datatglerr )
+               {
+                       return 1;
+               }
+               else if(hcint.b.bblerr     )
+               {
+                       #ifndef VR9Skip
+                               if(hctsiz.b.pktcnt==0)
+                               {
+                                       complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               }
+                               else
+                               {
+                                       _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
+                                       _ifxhc->xfer_len           = _urbd->xfer_len - _urbd->urb->actual_length;
+                                       _ifxhc->xfer_count         = _urbd->urb->actual_length;
+                                       _ifxhc->data_pid_start = read_data_toggle(_hc_regs);
+                                       _urbd->error_count++;
+                                       if(_urbd->error_count>=3)
+                                       {
+                                               _urbd->error_count=0;
+                                               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+                                       }
+                                       else
+                                       {
+                                               enable_hc_int(_hc_regs,ack);
+                                               enable_hc_int(_hc_regs,nak);
+                                               enable_hc_int(_hc_regs,nyet);
+                                               _ifxhc->phase=HC_WAITING;
+                                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                                       }
+                               }
+                       #endif
+               }
+               else if(hcint.b.xacterr    )
+               {
+                       if(hctsiz.b.pktcnt==0)
+                       {
+                               complete_channel(_ifxhcd, _ifxhc, _urbd);
+                               return 1;
+                       }
+                       _urbd->error_count++;
+                       if(_urbd->error_count>=3)
+                       {
+                               _urbd->error_count=0;
+                               release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+                       }
+                       else
+                       {
+                               _ifxhc->phase=HC_WAITING;
+                               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+                       }
+                       return 1;
+               }
+               else if(hcint.b.stall      )
+               {
+                       return 1;
+               }
+       #endif
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_ctrl_rx_ssplit(ifxhcd_hcd_t      *_ifxhcd,
+                                      ifxhcd_hc_t       *_ifxhc,
+                                      ifxusb_hc_regs_t  *_hc_regs,
+                                      ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       if (hcint.b.ack)
+       {
+               _urbd->error_count=0;
+               _ifxhc->split=2;
+               _ifxhc->data_pid_start = read_data_toggle(_hc_regs);
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if (hcint.b.nak)
+       {
+               _urbd->error_count     = 0;
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               _urbd->error_count++;
+               if(_urbd->error_count>=3)
+               {
+                       _urbd->error_count=0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               else
+               {
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               return 1;
+       }
+       else if(hcint.b.bblerr     )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.stall      )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else if(hcint.b.nyet   )
+       {
+       }
+       else if(hcint.b.xfercomp   )
+       {
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_ctrl_tx_ssplit(ifxhcd_hcd_t      *_ifxhcd,
+                                      ifxhcd_hc_t       *_ifxhc,
+                                      ifxusb_hc_regs_t  *_hc_regs,
+                                      ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+       int out_nak_enh = 0;
+
+       if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH)
+               out_nak_enh = 1;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       if     (hcint.b.ack )
+       {
+               _urbd->error_count=0;
+               if (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP)
+                       _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len;
+               _ifxhc->split=2;
+               _ifxhc->data_pid_start =read_data_toggle(_hc_regs);
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if(hcint.b.nyet)
+       {
+               _urbd->error_count=0;
+               if (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP)
+                       _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len;
+               _ifxhc->split=2;
+               _ifxhc->data_pid_start =read_data_toggle(_hc_regs);
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if(hcint.b.nak        )
+       {
+               _urbd->error_count    =0;
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if(hcint.b.xacterr    )
+       {
+               _urbd->error_count++;
+               if(_urbd->error_count>=3)
+               {
+                       _urbd->error_count=0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               else
+               {
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.bblerr     )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.stall      )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else if(hcint.b.xfercomp   )
+       {
+               printk(KERN_INFO "Warning: %s() %d CTRL OUT SPLIT1 COMPLETE\n",__func__,__LINE__);
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_bulk_rx_ssplit(ifxhcd_hcd_t      *_ifxhcd,
+                                      ifxhcd_hc_t       *_ifxhc,
+                                      ifxusb_hc_regs_t  *_hc_regs,
+                                      ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       if (hcint.b.ack)
+       {
+               _urbd->error_count=0;
+               _ifxhc->split=2;
+               _ifxhc->data_pid_start = read_data_toggle(_hc_regs);
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if (hcint.b.nak)
+       {
+               _urbd->error_count     = 0;
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if (hcint.b.xacterr)
+       {
+               _urbd->error_count++;
+               if(_urbd->error_count>=3)
+               {
+                       _urbd->error_count=0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               else
+               {
+                       _ifxhc->phase=HC_WAITING;
+                       ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               }
+               return 1;
+       }
+       else if(hcint.b.bblerr     )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.stall      )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
+               return 1;
+       }
+       else if(hcint.b.datatglerr )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR);
+               return 1;
+       }
+       else if(hcint.b.frmovrun   )
+       {
+               _urbd->error_count   =0;
+               release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
+               return 1;
+       }
+       else if(hcint.b.nyet   )
+       {
+       }
+       else if(hcint.b.xfercomp   )
+       {
+       }
+       return 0;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int32_t chhltd_bulk_tx_ssplit(ifxhcd_hcd_t      *_ifxhcd,
+                                      ifxhcd_hc_t       *_ifxhc,
+                                      ifxusb_hc_regs_t  *_hc_regs,
+                                      ifxhcd_urbd_t     *_urbd)
+{
+       hcint_data_t  hcint;
+       hcint_data_t  hcintmsk;
+       hctsiz_data_t hctsiz;
+       int out_nak_enh = 0;
+
+       if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH)
+               out_nak_enh = 1;
+
+       hcint.d32    = ifxusb_rreg(&_hc_regs->hcint);
+       hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk);
+       hctsiz.d32   = ifxusb_rreg(&_hc_regs->hctsiz);
+       disable_hc_int(_hc_regs,ack);
+       disable_hc_int(_hc_regs,nak);
+       disable_hc_int(_hc_regs,nyet);
+
+       if     (hcint.b.ack )
+       {
+               _urbd->error_count=0;
+               _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len;
+               _ifxhc->split=2;
+               _ifxhc->data_pid_start =read_data_toggle(_hc_regs);
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if(hcint.b.nyet)
+       {
+               _urbd->error_count=0;
+               _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len;
+               _ifxhc->split=2;
+               _ifxhc->data_pid_start =read_data_toggle(_hc_regs);
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if(hcint.b.nak        )
+       {
+               _urbd->error_count    =0;
+               _ifxhc->phase=HC_WAITING;
+               ifxhcd_hc_start(_ifxhcd, _ifxhc);
+               return 1;
+       }
+       else if(hcint.b.xacterr    )
+       {
+               _urbd->error_count++;
+               if(_urbd->error_count>=3)
+               {
+                       _urbd->error_count=0;
+                       release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
+               }
+               else
+               {
+                       _ifxhc->phase=HC_WAITING;
+