/*****************************************************************************
 **   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;
			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 BULK OUT SPLIT1 COMPLETE\n",__func__,__LINE__);
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_intr_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)
	{
		hcchar_data_t 	hcchar;
		hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar);
		_urbd->error_count=hcchar.b.multicnt;
		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      )
	{
		_urbd->error_count   =0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		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.frmovrun   )
	{
		_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.xfercomp   )
	{
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_intr_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.frmovrun   )
	{
		_urbd->error_count   =0;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.xacterr    )
	{
		hcchar_data_t 	hcchar;
		hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar);
		_urbd->error_count=hcchar.b.multicnt;
		if(_urbd->error_count>=3)
		{
			_urbd->error_count=0;
			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);
		}
		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.xfercomp   )
	{
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_isoc_rx_ssplit(ifxhcd_hcd_t      *_ifxhcd,
                                   ifxhcd_hc_t       *_ifxhc,
                                   ifxusb_hc_regs_t  *_hc_regs,
                                   ifxhcd_urbd_t     *_urbd)
{
	#if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
		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.ack )
		{
			Do Complete Split
		}
		else if(hcint.b.frmovrun   )
		{
			Rewind Buffer Pointers
			Retry Start Split (in next b_interval V 1 uF)
		}
		else if(hcint.b.datatglerr )
		{
			//warning
		}
		else if(hcint.b.bblerr     )
		{
			//warning
		}
		else if(hcint.b.xacterr    )
		{
			//warning
		}
		else if(hcint.b.stall      )
		{
			//warning
		}
		else if(hcint.b.nak        )
		{
			//warning
		}
		else if(hcint.b.xfercomp   )
		{
			//warning
		}
		else if(hcint.b.nyet)
		{
			//warning
		}
	#endif
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_isoc_tx_ssplit(ifxhcd_hcd_t      *_ifxhcd,
                                   ifxhcd_hc_t       *_ifxhc,
                                   ifxusb_hc_regs_t  *_hc_regs,
                                   ifxhcd_urbd_t     *_urbd)
{
	#if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
		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.ack )
		{
			//Do Next Start Split (in next b_interval V 1 uF)
		}
		else if(hcint.b.frmovrun   )
		{
			//Do Next Transaction in next frame.
		}
		else if(hcint.b.datatglerr )
		{
			//warning
		}
		else if(hcint.b.bblerr     )
		{
			//warning
		}
		else if(hcint.b.xacterr    )
		{
			//warning
		}
		else if(hcint.b.stall      )
		{
			//warning
		}
		else if(hcint.b.nak        )
		{
			//warning
		}
		else if(hcint.b.xfercomp   )
		{
			//warning
		}
		else if(hcint.b.nyet)
		{
			//warning
		}
	#endif
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_ctrl_rx_csplit(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)
	{
		_urbd->error_count   =0;
		_ifxhc->split=1;
		complete_channel(_ifxhcd, _ifxhc, _urbd);
		return 1;
	}
	else if (hcint.b.nak)
	{
		_ifxhc->split          = 1;
		if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
		{
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
		}
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.nyet)
	{
		_urbd->error_count=0;
		_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.stall || hcint.b.bblerr )
	{
		_urbd->error_count=0;
		if     (hcint.b.stall)
			release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		else if(hcint.b.bblerr )
			release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
		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->split=1;
			if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
			{
				_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
				_ifxhc->xfer_count     = _urbd->urb->actual_length;
			}
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
		}
		return 1;
	}
	else if(hcint.b.datatglerr )
	{
		if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0)
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
		else
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
		_ifxhc->split=1;
		if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
		{
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
		}
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.frmovrun   )
	{
		_urbd->error_count=0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
		return 1;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_ctrl_tx_csplit(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.xfercomp   )
	{
		_urbd->error_count=0;
		_ifxhc->split=1;
		#if 0
		if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet))
		{
			// Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr
			// Solution:   NoSplit: Resend at next SOF
			//             Split  : Resend at next SOF with SSPLIT
			_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
		#endif
		{
			complete_channel(_ifxhcd, _ifxhc, _urbd);
		}
		return 1;
	}
	else if(hcint.b.nak        )
	{
		_ifxhc->split          = 1;
		if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
		{
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
		}
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.nyet)
	{
		//Retry Complete Split
		// Issue Retry instantly on next SOF, without gothrough process_channels
		_urbd->error_count=0;
		_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.stall      )
	{
		_urbd->error_count=0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		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->split=1;
			if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
			{
				_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
				_ifxhc->xfer_count     = _urbd->urb->actual_length;
			}
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
		}
		return 1;
	}
	else if(hcint.b.datatglerr )
	{
		if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0)
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
		else
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
		_ifxhc->split=1;
		if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA)
		{
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
		}
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		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.bblerr     )
	{
		_urbd->error_count=0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
		return 1;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_bulk_rx_csplit(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)
	{
		_urbd->error_count   =0;
		_ifxhc->split=1;
		complete_channel(_ifxhcd, _ifxhc, _urbd);
		return 1;
	}
	else if (hcint.b.nak)
	{
		_ifxhc->split          = 1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.nyet)
	{
		_urbd->error_count=0;
		_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.stall || hcint.b.bblerr )
	{
		_urbd->error_count=0;
		if     (hcint.b.stall)
			release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		else if(hcint.b.bblerr )
			release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
		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->split=1;
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
		}
		return 1;
	}
	else if(hcint.b.datatglerr )
	{
		if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0)
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
		else
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
		_ifxhc->split=1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.frmovrun   )
	{
		_urbd->error_count=0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
		return 1;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_bulk_tx_csplit(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.xfercomp   )
	{
		_urbd->error_count=0;
		_ifxhc->split=1;
		#if 0
		if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet))
		{
			// Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr
			// Solution:   NoSplit: Resend at next SOF
			//             Split  : Resend at next SOF with SSPLIT
			_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
		#endif
		{
			complete_channel(_ifxhcd, _ifxhc, _urbd);
		}
		return 1;
	}
	else if(hcint.b.nak        )
	{
		_ifxhc->split          = 1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.nyet)
	{
		//Retry Complete Split
		// Issue Retry instantly on next SOF, without gothrough process_channels
		_urbd->error_count=0;
		_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.stall      )
	{
		_urbd->error_count=0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		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->split=1;
			_ifxhc->epqh->do_ping=1;
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
		}
		return 1;
	}
	else if(hcint.b.datatglerr )
	{
		if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0)
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
		else
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
		_ifxhc->split=1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		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.bblerr     )
	{
		_urbd->error_count=0;
		release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
		return 1;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_intr_rx_csplit(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   )
	{
		_urbd->error_count=0;
		_ifxhc->split=1;
		complete_channel(_ifxhcd, _ifxhc, _urbd);
		return 1;
	}
	else if(hcint.b.nak        )
	{
		_ifxhc->split          = 1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.nyet)
	{
		_urbd->error_count=0;
		_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.frmovrun || hcint.b.bblerr || hcint.b.stall )
	{
		_urbd->error_count=0;
		if     (hcint.b.stall)
			release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		else if(hcint.b.bblerr )
			release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR);
		else if(hcint.b.frmovrun )
			release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
		return 1;
	}
	else if(hcint.b.xacterr    )
	{
		hcchar_data_t 	hcchar;
		hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar);
		_urbd->error_count=hcchar.b.multicnt;
		if(_urbd->error_count>=3)
		{
			_urbd->error_count=0;
			release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
		}
		else
		{
			_ifxhc->split=1;
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
		}
		return 1;
	}
	else if(hcint.b.datatglerr )
	{
		if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0)
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
		else
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
		_ifxhc->split=1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_intr_tx_csplit(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.xfercomp   )
	{
		_urbd->error_count=0;
		_ifxhc->split=1;
		complete_channel(_ifxhcd, _ifxhc, _urbd);
		return 1;
	}
	else if(hcint.b.nak        )
	{
		_ifxhc->split          = 1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.nyet)
	{
		_urbd->error_count=0;
		_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
		_ifxhc->phase=HC_WAITING;
		ifxhcd_hc_start(_ifxhcd, _ifxhc);
		return 1;
	}
	else if(hcint.b.stall || hcint.b.frmovrun)
	{
		_urbd->error_count=0;
		if     (hcint.b.stall)
			release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
		else if(hcint.b.frmovrun )
			release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN);
		return 1;
	}
	else if(hcint.b.xacterr    )
	{
		hcchar_data_t 	hcchar;
		hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar);
		_urbd->error_count=hcchar.b.multicnt;
		if(_urbd->error_count>=3)
		{
			_urbd->error_count=0;
			release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR);
		}
		else
		{
			_ifxhc->split=1;
			_ifxhc->epqh->do_ping=1;
			_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
			_ifxhc->xfer_count     = _urbd->urb->actual_length;
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
		}
		return 1;
	}
	else if(hcint.b.datatglerr )
	{
		if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0)
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1;
		else
			_ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0;
		_ifxhc->split=1;
		_ifxhc->epqh->do_ping=1;
		_ifxhc->xfer_len       = _urbd->xfer_len - _urbd->urb->actual_length;
		_ifxhc->xfer_count     = _urbd->urb->actual_length;
		_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;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_isoc_rx_csplit(ifxhcd_hcd_t      *_ifxhcd,
                                   ifxhcd_hc_t       *_ifxhc,
                                   ifxusb_hc_regs_t  *_hc_regs,
                                   ifxhcd_urbd_t     *_urbd)
{
	#if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
		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   )
		{
			disable_hc_int(_hc_regs,ack);
			disable_hc_int(_hc_regs,nak);
			disable_hc_int(_hc_regs,nyet);
			_urbd->error_count=0;
			_ifxhc->split=1;
			complete_channel(_ifxhcd, _ifxhc, _urbd);
			return 1;
		}
		else if(hcint.b.nak        )
		{
			Retry Start Split (in next b_interval V 1 uF)
		}
		else if(hcint.b.nyet)
		{
			//Do Next Complete Split
			// Issue Retry instantly on next SOF, without gothrough process_channels
			_urbd->error_count=0;
			//disable_hc_int(_hc_regs,ack);
			//disable_hc_int(_hc_regs,nak);
			//disable_hc_int(_hc_regs,datatglerr);
			_ifxhc->halt_status    = HC_XFER_NO_HALT_STATUS;
			_ifxhc->phase=HC_WAITING;
			ifxhcd_hc_start(_ifxhcd, _ifxhc);
			return 1;
		}
		else if(hcint.b.frmovrun || hcint.b.stall || hcint.b.bblerr)
		{
			_urbd->error_count=0;
			disable_hc_int(_hc_regs,ack);
			disable_hc_int(_hc_regs,nyet);
			disable_hc_int(_hc_regs,nak);
			_ifxhc->wait_for_sof   = 0;

			//if(hctsiz.b.pktcnt==0)
			//{
			//	complete_channel(_ifxhcd, _ifxhc, _urbd);
			//	return 1;
			//}
			//else
			//	_urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize);
			if     (hcint.b.stall)
				release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL);
			else if(hcint.b.frmovrun )
			else if(hcint.b.bblerr )
			return 1;
		}
		else if(hcint.b.xacterr    )
		{
			Rewind Buffer Pointers
			if (HCCHARn.EC = = 3) // ERR response received
			{
				Record ERR error
				Do Next Start Split (in next frame)
			}
			else
			{
				De-allocate Channel
			}
		}
		else if(hcint.b.datatglerr )
		{
			warning
		}
		else if(hcint.b.ack )
		{
			warning
		}
	#endif
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int32_t chhltd_isoc_tx_csplit(ifxhcd_hcd_t      *_ifxhcd,
                                   ifxhcd_hc_t       *_ifxhc,
                                   ifxusb_hc_regs_t  *_hc_regs,
                                   ifxhcd_urbd_t     *_urbd)
{
	#if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
		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);
		warning
	#endif
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*!
	 \fn    static int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t      *_ifxhcd,
                                     ifxhcd_hc_t       *_ifxhc,
                                     ifxusb_hc_regs_t  *_hc_regs,
                                     ifxhcd_urbd_t      *_urbd)
	 \brief This function handles halted interrupts of host channels.
	 \param  _ifxhcd Pointer to the sate of HCD structure
	 \param  _ifxhc Pointer to host channel descriptor
	 \param  _hc_regs Pointer to host channel registers
	 \param  _urbd Pointer to URB descriptor
	 \return  0 OK
	 \ingroup  IFXUSB_HCD
 */
static
int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t      *_ifxhcd,
                                     ifxhcd_hc_t       *_ifxhc,
                                     ifxusb_hc_regs_t  *_hc_regs,
                                     ifxhcd_urbd_t      *_urbd)
{
	IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: Channel Halted--\n", _ifxhc->hc_num);

	_ifxhc->phase = HC_STOPPED;
	if(_ifxhc->epqh)
		if(_ifxhc->epqh->urbd)
			_ifxhc->epqh->urbd->phase=URBD_ACTIVE;

	if (_ifxhc->halt_status == HC_XFER_URB_DEQUEUE ||
	    _ifxhc->halt_status == HC_XFER_AHB_ERR) {
		/*
		 * Just release the channel. A dequeue can happen on a
		 * transfer timeout. In the case of an AHB Error, the channel
		 * was forced to halt because there's no way to gracefully
		 * recover.
		 */
		if(_ifxhc->epqh)
			if(_ifxhc->epqh->urbd)
				_ifxhc->epqh->urbd->phase=URBD_DEQUEUEING;
		release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status);
		return 1;
	}

	if     (_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)
	{
		if     (_ifxhc->split==0)
		{
			if(_ifxhc->is_in)
				return (chhltd_ctrl_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_ctrl_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==1)
		{
			if(_ifxhc->is_in)
				return (chhltd_ctrl_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_ctrl_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==2)
		{
			if(_ifxhc->is_in)
				return (chhltd_ctrl_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_ctrl_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
	}
	else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)
	{
		if     (_ifxhc->split==0)
		{
			if(_ifxhc->is_in)
				return (chhltd_bulk_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_bulk_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==1)
		{
			if(_ifxhc->is_in)
				return (chhltd_bulk_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_bulk_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==2)
		{
			if(_ifxhc->is_in)
				return (chhltd_bulk_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_bulk_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
	}
	else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)
	{
		if     (_ifxhc->split==0)
		{
			if(_ifxhc->is_in)
				return (chhltd_intr_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_intr_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==1)
		{
			if(_ifxhc->is_in)
				return (chhltd_intr_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_intr_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==2)
		{
			if(_ifxhc->is_in)
				return (chhltd_intr_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_intr_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
	}
	else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
	{
		if     (_ifxhc->split==0)
		{
			if(_ifxhc->is_in)
				return (chhltd_isoc_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_isoc_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==1)
		{
			if(_ifxhc->is_in)
				return (chhltd_isoc_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_isoc_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
		else if(_ifxhc->split==2)
		{
			if(_ifxhc->is_in)
				return (chhltd_isoc_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
			else
				return (chhltd_isoc_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd));
		}
	}
	return 0;
}

/*
 * Handles a host channel AHB error interrupt. This handler is only called in
 * DMA mode.
 */
static void hc_other_intr_dump(ifxhcd_hcd_t      *_ifxhcd,
                               ifxhcd_hc_t       *_ifxhc,
                               ifxusb_hc_regs_t  *_hc_regs,
                               ifxhcd_urbd_t      *_urbd)
{
	#ifdef __DEBUG__
		hcchar_data_t hcchar;
		hcsplt_data_t hcsplt;
		hctsiz_data_t hctsiz;
		uint32_t      hcdma;
		struct urb   *urb = _urbd->urb;
		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_ERROR("Channel %d\n", _ifxhc->hc_num);
		IFX_ERROR("  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
		IFX_ERROR("  hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
		IFX_ERROR("  Device address: %d\n", usb_pipedevice(urb->pipe));
		IFX_ERROR("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
			    (usb_pipein(urb->pipe) ? "IN" : "OUT"));
		IFX_ERROR("  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;}));
		IFX_ERROR("  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;}));
		IFX_ERROR("  Max packet size: %d\n",
			    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
		IFX_ERROR("  Data buffer length: %d\n", urb->transfer_buffer_length);
		IFX_ERROR("  Transfer buffer: %p, Transfer DMA: %p\n",
			    urb->transfer_buffer, (void *)urb->transfer_dma);
		IFX_ERROR("  Setup buffer: %p, Setup DMA: %p\n",
			    urb->setup_packet, (void *)urb->setup_dma);
		IFX_ERROR("  Interval: %d\n", urb->interval);
	#endif //__DEBUG__
}

/*
 * Handles a host channel ACK interrupt. This interrupt is enabled when
 *  errors occur, and during Start Split transactions.
 */
static
int32_t handle_hc_ack_intr(ifxhcd_hcd_t      *_ifxhcd,
                                  ifxhcd_hc_t      *_ifxhc,
                                  ifxusb_hc_regs_t *_hc_regs,
                                  ifxhcd_urbd_t     *_urbd)
{
	_urbd->error_count=0;
	_ifxhc->erron = 0;

	disable_hc_int(_hc_regs,nyet);

	#ifdef __NAKSTOP__
	if(!_ifxhc->stop_on)
	{
		disable_hc_int(_hc_regs,ack);
		disable_hc_int(_hc_regs,nak);
	}
	#else
		disable_hc_int(_hc_regs,ack);
		disable_hc_int(_hc_regs,nak);
	#endif
	return 1;
}

/*
 * Handles a host channel ACK interrupt. This interrupt is enabled when
 *  errors occur, and during Start Split transactions.
 */
static
int32_t handle_hc_nak_intr(ifxhcd_hcd_t      *_ifxhcd,
                                  ifxhcd_hc_t      *_ifxhc,
                                  ifxusb_hc_regs_t *_hc_regs,
                                  ifxhcd_urbd_t     *_urbd)
{
	_urbd->error_count=0;
	_ifxhc->erron=0;
	disable_hc_int(_hc_regs,nyet);
	disable_hc_int(_hc_regs,ack);
	disable_hc_int(_hc_regs,nak);
	#ifdef __NAKSTOP__
	if(_ifxhc->stop_on)
	{
		hcchar_data_t   hcchar;
		hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar);
		if(hcchar.b.chen)
		{
			hcchar.b.chdis = 1;
			_ifxhc->halt_status = HC_XFER_NAK;
			ifxusb_wreg(&_hc_regs->hcchar, hcchar.d32);
		}
	}
	#endif
	return 1;
}

static
int32_t handle_hc_nyet_intr(ifxhcd_hcd_t      *_ifxhcd,
                                   ifxhcd_hc_t      *_ifxhc,
                                   ifxusb_hc_regs_t *_hc_regs,
                                   ifxhcd_urbd_t     *_urbd)
{
	_urbd->error_count=0;
	_ifxhc->erron = 0;

	disable_hc_int(_hc_regs,nyet);
	#ifdef __NAKSTOP__
	if(!_ifxhc->stop_on)
	{
		disable_hc_int(_hc_regs,ack);
		disable_hc_int(_hc_regs,nak);
	}
	#else
		disable_hc_int(_hc_regs,ack);
		disable_hc_int(_hc_regs,nak);
	#endif
	return 1;
}

/*
 * Handles a host channel AHB error interrupt. This handler is only called in
 * DMA mode.
 */
static int32_t handle_hc_ahberr_intr(ifxhcd_hcd_t      *_ifxhcd,
                                     ifxhcd_hc_t       *_ifxhc,
                                     ifxusb_hc_regs_t  *_hc_regs,
                                     ifxhcd_urbd_t      *_urbd)
{
	IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
		    "AHB Error--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);

	ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_AHB_ERR);
	return 1;
}

/*
 * Datatoggle
 */
static int32_t handle_hc_datatglerr_intr(ifxhcd_hcd_t      *_ifxhcd,
                                         ifxhcd_hc_t      *_ifxhc,
                                         ifxusb_hc_regs_t *_hc_regs,
                                         ifxhcd_urbd_t     *_urbd)
{
	IFX_ERROR( "--Host Channel %d Interrupt: "
		    "DATATOGGLE Error--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);
	disable_hc_int(_hc_regs,datatglerr);
	return 1;
}


/*
 * Interrupts which should not been triggered
 */
static int32_t handle_hc_frmovrun_intr(ifxhcd_hcd_t      *_ifxhcd,
                                       ifxhcd_hc_t      *_ifxhc,
                                       ifxusb_hc_regs_t *_hc_regs,
                                       ifxhcd_urbd_t     *_urbd)
{
	IFX_ERROR( "--Host Channel %d Interrupt: "
		    "FrameOverRun Error--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);
	disable_hc_int(_hc_regs,frmovrun);
	return 1;
}

static int32_t handle_hc_bblerr_intr(ifxhcd_hcd_t      *_ifxhcd,
                                     ifxhcd_hc_t      *_ifxhc,
                                     ifxusb_hc_regs_t *_hc_regs,
                                     ifxhcd_urbd_t     *_urbd)
{
	IFX_ERROR( "--Host Channel %d Interrupt: "
		    "BBL Error--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);
	disable_hc_int(_hc_regs,bblerr);
	return 1;
}

static int32_t handle_hc_xacterr_intr(ifxhcd_hcd_t      *_ifxhcd,
                                      ifxhcd_hc_t      *_ifxhc,
                                      ifxusb_hc_regs_t *_hc_regs,
                                      ifxhcd_urbd_t     *_urbd)
{
	IFX_ERROR( "--Host Channel %d Interrupt: "
		    "XACT Error--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);
	disable_hc_int(_hc_regs,xacterr);
	return 1;
}


static int32_t handle_hc_stall_intr(ifxhcd_hcd_t      *_ifxhcd,
                                    ifxhcd_hc_t      *_ifxhc,
                                    ifxusb_hc_regs_t *_hc_regs,
                                    ifxhcd_urbd_t     *_urbd)
{
	IFX_ERROR( "--Host Channel %d Interrupt: "
		    "STALL--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);
	disable_hc_int(_hc_regs,stall);
	return 1;
}

static int32_t handle_hc_xfercomp_intr(ifxhcd_hcd_t      *_ifxhcd,
                                       ifxhcd_hc_t      *_ifxhc,
                                       ifxusb_hc_regs_t *_hc_regs,
                                       ifxhcd_urbd_t     *_urbd)
{
	IFX_ERROR( "--Host Channel %d Interrupt: "
		    "XFERCOMP--\n", _ifxhc->hc_num);
	hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd);
	disable_hc_int(_hc_regs,xfercomp);
	return 1;
}

/* This interrupt indicates that the specified host channels has a pending
 * interrupt. There are multiple conditions that can cause each host channel
 * interrupt. This function determines which conditions have occurred for this
 * host channel interrupt and handles them appropriately. */
static int32_t handle_hc_n_intr (ifxhcd_hcd_t *_ifxhcd, uint32_t _num)
{
	uint32_t          hcintval,hcintmsk;
	hcint_data_t      hcint;
	ifxhcd_hc_t      *ifxhc;
	ifxusb_hc_regs_t *hc_regs;
	ifxhcd_urbd_t     *urbd;

	int retval = 0;

	IFX_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num);

	ifxhc = &_ifxhcd->ifxhc[_num];
	hc_regs = _ifxhcd->core_if.hc_regs[_num];

	hcintval  = ifxusb_rreg(&hc_regs->hcint);
	hcintmsk  = ifxusb_rreg(&hc_regs->hcintmsk);
	hcint.d32 = hcintval & hcintmsk;
	IFX_DEBUGPL(DBG_HCDV, "  0x%08x & 0x%08x = 0x%08x\n",
		    hcintval, hcintmsk, hcint.d32);

	urbd = ifxhc->epqh->urbd;

	if (hcint.b.ahberr)
		retval |= handle_hc_ahberr_intr(_ifxhcd, ifxhc, hc_regs, urbd);
	else if (hcint.b.chhltd)
		retval |= handle_hc_chhltd_intr(_ifxhcd, ifxhc, hc_regs, urbd);
	else
	{
		if (hcint.b.datatglerr)
			retval |= handle_hc_datatglerr_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.frmovrun)
			retval |= handle_hc_frmovrun_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.bblerr)
			retval |= handle_hc_bblerr_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.xacterr)
			retval |= handle_hc_xacterr_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.nyet)
			retval |= handle_hc_nyet_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.ack)
			retval |= handle_hc_ack_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.nak)
			retval |= handle_hc_nak_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.stall)
			retval |= handle_hc_stall_intr(_ifxhcd, ifxhc, hc_regs, urbd);
		if (hcint.b.xfercomp)
			retval |= handle_hc_xfercomp_intr(_ifxhcd, ifxhc, hc_regs, urbd);
	}

	ifxusb_wreg(&hc_regs->hcint,hcintval);

	return retval;
}


static uint8_t update_interval_counter(ifxhcd_epqh_t *_epqh,uint32_t _diff)
{
	if(_diff>=_epqh->period_counter)
	{
		_epqh->period_do=1;
		if(_diff>_epqh->interval)
			_epqh->period_counter=1;
		else
			_epqh->period_counter=_epqh->period_counter+_epqh->interval-_diff;
		return 1;
	}
	_epqh->period_counter=_epqh->period_counter-_diff;
	return 0;
}

static
void process_unaligned( ifxhcd_epqh_t *_epqh, ifxusb_core_if_t *_core_if)
{
	ifxhcd_urbd_t *urbd;
	urbd  =_epqh->urbd;

	#if   defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__)
	if(!urbd->aligned_checked)
	{
		#if   defined(__UNALIGNED_BUF_ADJ__)
			uint32_t xfer_len;
			xfer_len=urbd->xfer_len;
			if(urbd->is_in && xfer_len<_epqh->mps)
				xfer_len = _epqh->mps;
//			urbd->using_aligned_buf=0;

			if(xfer_len > 0 && ((unsigned long)urbd->xfer_buff) & _core_if->unaligned_mask)
			{
				if(   urbd->aligned_buf
				   && urbd->aligned_buf_len > 0
				   && urbd->aligned_buf_len < xfer_len
				  )
				{
					ifxusb_free_buf_h(urbd->aligned_buf);
					urbd->aligned_buf=NULL;
					urbd->aligned_buf_len=0;
				}
				if(! urbd->aligned_buf || ! urbd->aligned_buf_len)
				{
					urbd->aligned_buf = ifxusb_alloc_buf_h(xfer_len, urbd->is_in);
					if(urbd->aligned_buf)
						urbd->aligned_buf_len = xfer_len;
				}
				if(urbd->aligned_buf)
				{
					if(!urbd->is_in)
						memcpy(urbd->aligned_buf, urbd->xfer_buff, xfer_len);
//					urbd->using_aligned_buf=1;
					_epqh->hc->xfer_buff = urbd->aligned_buf;
				}
				else
					IFX_WARN("%s():%d\n",__func__,__LINE__);
			}
			if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL)
			{
//				urbd->using_aligned_setup=0;
				if(((unsigned long)urbd->setup_buff) & _core_if->unaligned_mask)
				{
					if(! urbd->aligned_setup)
						urbd->aligned_setup = ifxusb_alloc_buf_h(8,0);
					if(urbd->aligned_setup)
					{
						memcpy(urbd->aligned_setup, urbd->setup_buff, 8);
//						urbd->using_aligned_setup=1;
					}
					else
						IFX_WARN("%s():%d\n",__func__,__LINE__);
					_epqh->hc->xfer_buff = urbd->aligned_setup;
				}
			}
		#elif defined(__UNALIGNED_BUF_CHK__)
			if(_epqh->urbd->is_in)
			{
				if(_epqh->urbd->xfer_len==0)
					IFX_WARN("%s():%d IN xfer while length is zero \n",__func__,__LINE__);
				else{
					if(_epqh->urbd->xfer_len < _epqh->mps)
						IFX_WARN("%s():%d IN xfer while length < mps \n",__func__,__LINE__);
					if(((unsigned long)_epqh->urbd->xfer_buff) & _core_if->unaligned_mask)
						IFX_WARN("%s():%d IN xfer Buffer UNALIGNED\n",__func__,__LINE__);
				}
			}
			else
			{
				if(_epqh->urbd->xfer_len > 0 && (((unsigned long)_epqh->urbd->xfer_buff) & _core_if->unaligned_mask))
					IFX_WARN("%s():%d OUT xfer Buffer UNALIGNED\n",__func__,__LINE__);
			}
			if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL)
			{
				if(((unsigned long)_epqh->urbd->setup_buff) & _core_if->unaligned_mask)
					IFX_WARN("%s():%d SETUP xfer Buffer UNALIGNED\n",__func__,__LINE__);
			}
		#endif
	}
	urbd->aligned_checked=1;
	#endif
}

/*!
 \brief Assigns transactions from a URBD to a free host channel and initializes the
 host channel to perform the transactions. The host channel is removed from
 the free list.
 \param _ifxhcd The HCD state structure.
 \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel.
 */
static
int assign_hc(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh,ifxhcd_urbd_t *_urbd)
{
	ifxhcd_hc_t   *ifxhc;
	struct urb    *urb;

	IFX_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _ifxhcd, _epqh);

	if(_ifxhcd->disconnecting)
	{
		printk(KERN_INFO "Warning: %s() Port is in discoonection\n",__func__);
		return 0;
	}

	if(!_epqh)       return 0;
	if(!_urbd)       return 0;
	if(!_urbd->urb)  return 0;

	{
		int i;
		int num_channels = _ifxhcd->core_if.params.host_channels;
		for(i=0;i<num_channels ; i++)
		{
			hcchar_data_t hcchar;
			ifxusb_hc_regs_t *hc_regs;
			hc_regs = _ifxhcd->core_if.hc_regs[i];
			if(_ifxhcd->ifxhc[i].phase!=HC_IDLE)
			{
				continue;
			}
			hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
			if(hcchar.b.chen || hcchar.b.chdis)
			{
				continue;
			}
			break;
		}

		if(i<num_channels)
		{
			ifxhc=&_ifxhcd->ifxhc[i];
			ifxhc->phase=HC_ASSIGNED;
		}
		else
			return 0;
	}

	urb         = _urbd->urb;
	_epqh->hc   = ifxhc;
	_epqh->urbd = _urbd;
	ifxhc->epqh = _epqh;
	/*
	 * Use usb_pipedevice to determine device address. This address is
	 * 0 before the SET_ADDRESS command and the correct address afterward.
	 */
	ifxhc->dev_addr = usb_pipedevice(urb->pipe);
	ifxhc->ep_num   = usb_pipeendpoint(urb->pipe);

	if      (urb->dev->speed == USB_SPEED_LOW)  ifxhc->speed = IFXUSB_EP_SPEED_LOW;
	else if (urb->dev->speed == USB_SPEED_FULL) ifxhc->speed = IFXUSB_EP_SPEED_FULL;
	else                                        ifxhc->speed = IFXUSB_EP_SPEED_HIGH;

	ifxhc->mps         = _epqh->mps;
	ifxhc->halt_status = HC_XFER_NO_HALT_STATUS;
	ifxhc->ep_type = _epqh->ep_type;

	ifxhc->split = 0;
	if (_epqh->need_split)
	{
		ifxhc->split = 1;
		ifxhc->hub_addr       = urb->dev->tt->hub->devnum;
		ifxhc->port_addr      = urb->dev->ttport;
	}
	return 1;
}

/*!
 \brief Assigns transactions from a URBD to a free host channel and initializes the
 host channel to perform the transactions. The host channel is removed from
 the free list.
 \param _ifxhcd The HCD state structure.
 \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel.
 */
static
void init_hc(ifxhcd_epqh_t *_epqh)
{
	ifxhcd_hc_t   *ifxhc;
	ifxhcd_urbd_t *urbd;
	struct urb    *urb;
	ifxhcd_hcd_t  *ifxhcd;

	IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _epqh);

	ifxhc =_epqh->hc;
	urbd  =_epqh->urbd;
	ifxhcd=_epqh->ifxhcd;
	urb  = urbd->urb;
	#if   defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__)
	urbd->aligned_checked=0;
	#endif

	ifxhc->halt_status = HC_XFER_NO_HALT_STATUS;

	if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL)
	{
		ifxhc->control_phase  =IFXHCD_CONTROL_SETUP;
		ifxhc->is_in          = 0;
		ifxhc->data_pid_start = IFXUSB_HC_PID_SETUP;
		ifxhc->xfer_buff      = urbd->setup_buff;
		ifxhc->xfer_len       = 8;
		ifxhc->xfer_count     = 0;
		ifxhc->short_rw       =(urb->transfer_flags & URB_ZERO_PACKET)?1:0;
		ifxhc->sof_delay      = 0;
		_epqh->do_ping=0;
		if(!ifxhc->is_in && ifxhc->split==0)
			_epqh->do_ping=1;
	}
	else if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC)
	{
		#ifdef __EN_ISOC__
			struct usb_iso_packet_descriptor *frame_desc;
			ifxhc->is_in          = urbd->is_in;
			frame_desc            = &urb->iso_frame_desc[urbd->isoc_frame_index];
			urbd->xfer_len        = ifxhc->xfer_len       = frame_desc->length;
			ifxhc->xfer_buff      = urbd->xfer_buff;
			ifxhc->xfer_buff     += frame_desc->offset;
			ifxhc->xfer_count     = 0;
			ifxhc->sof_delay      = 0;
			if(usb_gettoggle (urb->dev,usb_pipeendpoint (urb->pipe), (ifxhc->is_in)?0:1))
				ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA1;
			else
				ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA0;

			if(ifxhc->is_in)
				ifxhc->short_rw       =0;
			else
				ifxhc->short_rw       =(urb->transfer_flags & URB_ZERO_PACKET)?1:0;
			#ifdef __EN_ISOC_SPLIT__
				ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_ALL;
			#endif

			_epqh->isoc_frame_index=0;
			_epqh->isoc_now=0;
			_epqh->isoc_start_frame=0;
			if(_urb->transfer_flags && URB_ISO_ASAP)
				_epqh->isoc_now=1;
			else
				_epqh->isoc_start_frame=_urb->start_frame;
			#ifdef __EN_ISOC_SPLIT__
				_epqh->isoc_split_pos   =0;
				_epqh->isoc_split_offset=0;
			#endif
			_epqh->do_ping=0;
		#endif
	}
	else
	{
		ifxhc->is_in          = urbd->is_in;
		ifxhc->xfer_buff      = urbd->xfer_buff;
		ifxhc->xfer_len       = urbd->xfer_len;
		ifxhc->xfer_count     = 0;
		ifxhc->sof_delay      = 0;
//		if(ifxhc->xfer_len==13 &&  ifxhc->is_in && _epqh->ep_type==IFXUSB_EP_TYPE_BULK && ifxhc->split==0)
//			ifxhc->sof_delay      = 8;
		if(usb_gettoggle (urb->dev,usb_pipeendpoint (urb->pipe), (ifxhc->is_in)?0:1))
			ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA1;
		else
			ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA0;
		if(ifxhc->is_in)
			ifxhc->short_rw       =0;
		else
			ifxhc->short_rw       =(urb->transfer_flags & URB_ZERO_PACKET)?1:0;
		_epqh->do_ping=0;
		if(!ifxhc->is_in && ifxhc->split==0)
		{
			if(_epqh->ep_type==IFXUSB_EP_TYPE_BULK) _epqh->do_ping=1;
		}
	}

	{
		hcint_data_t      hc_intr_mask;
		uint8_t           hc_num = ifxhc->hc_num;
		ifxusb_hc_regs_t *hc_regs = ifxhcd->core_if.hc_regs[hc_num];

		/* Clear old interrupt conditions for this host channel. */
		hc_intr_mask.d32 = 0xFFFFFFFF;
		hc_intr_mask.b.reserved = 0;
		ifxusb_wreg(&hc_regs->hcint, hc_intr_mask.d32);

		/* Enable channel interrupts required for this transfer. */
		hc_intr_mask.d32 = 0;
		hc_intr_mask.b.chhltd = 1;
		hc_intr_mask.b.ahberr = 1;

		ifxusb_wreg(&hc_regs->hcintmsk, hc_intr_mask.d32);

		/* Enable the top level host channel interrupt. */
		{
			uint32_t          intr_enable;
			intr_enable = (1 << hc_num);
			ifxusb_mreg(&ifxhcd->core_if.host_global_regs->haintmsk, 0, intr_enable);
		}

		/* Make sure host channel interrupts are enabled. */
		{
			gint_data_t       gintmsk ={.d32 = 0};
			gintmsk.b.hcintr = 1;
			ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0, gintmsk.d32);
		}

		/*
		 * Program the HCCHARn register with the endpoint characteristics for
		 * the current transfer.
		 */
		{
			hcchar_data_t     hcchar;

			hcchar.d32 = 0;
			hcchar.b.devaddr   =  ifxhc->dev_addr;
			hcchar.b.epnum     =  ifxhc->ep_num;
			hcchar.b.lspddev   = (ifxhc->speed == IFXUSB_EP_SPEED_LOW);
			hcchar.b.eptype    =  ifxhc->ep_type;
			hcchar.b.mps       =  ifxhc->mps;
			ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);

			IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, ifxhc->hc_num);
			IFX_DEBUGPL(DBG_HCDV, "  Dev Addr: %d\n"    , hcchar.b.devaddr);
			IFX_DEBUGPL(DBG_HCDV, "  Ep Num: %d\n"      , hcchar.b.epnum);
			IFX_DEBUGPL(DBG_HCDV, "  Is Low Speed: %d\n", hcchar.b.lspddev);
			IFX_DEBUGPL(DBG_HCDV, "  Ep Type: %d\n"     , hcchar.b.eptype);
			IFX_DEBUGPL(DBG_HCDV, "  Max Pkt: %d\n"     , hcchar.b.mps);
			IFX_DEBUGPL(DBG_HCDV, "  Multi Cnt: %d\n"   , hcchar.b.multicnt);
		}
		/* Program the HCSPLIT register for SPLITs */
		{
			hcsplt_data_t     hcsplt;

			hcsplt.d32 = 0;
			if (ifxhc->split)
			{
				IFX_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", ifxhc->hc_num,
					   (ifxhc->split==2) ? "CSPLIT" : "SSPLIT");
				hcsplt.b.spltena  = 1;
				hcsplt.b.compsplt = (ifxhc->split==2);
				#if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__)
					if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC)
						hcsplt.b.xactpos  = ifxhc->isoc_xact_pos;
					else
				#endif
					hcsplt.b.xactpos  = IFXUSB_HCSPLIT_XACTPOS_ALL;
				hcsplt.b.hubaddr  = ifxhc->hub_addr;
				hcsplt.b.prtaddr  = ifxhc->port_addr;
				IFX_DEBUGPL(DBG_HCDV, "   comp split %d\n" , hcsplt.b.compsplt);
				IFX_DEBUGPL(DBG_HCDV, "   xact pos %d\n"   , hcsplt.b.xactpos);
				IFX_DEBUGPL(DBG_HCDV, "   hub addr %d\n"   , hcsplt.b.hubaddr);
				IFX_DEBUGPL(DBG_HCDV, "   port addr %d\n"  , hcsplt.b.prtaddr);
				IFX_DEBUGPL(DBG_HCDV, "   is_in %d\n"      , ifxhc->is_in);
				IFX_DEBUGPL(DBG_HCDV, "   Max Pkt: %d\n"   , ifxhc->mps);
				IFX_DEBUGPL(DBG_HCDV, "   xferlen: %d\n"   , ifxhc->xfer_len);
			}
			ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32);
		}
	}
	process_unaligned(_epqh,&ifxhcd->core_if);


	#ifdef __NAKSTOP__
		ifxhc->stop_on=0;
		if (!ifxhc->split && ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)
		{
			#ifdef __INNAKSTOP_BULK__
				if(ifxhc->is_in)
					ifxhc->stop_on=1;
			#endif
			#ifdef __PINGSTOP_BULK__
				if(!ifxhc->is_in)
					ifxhc->stop_on=1;
			#endif
		}
	#endif
}


static
void select_eps_sub(ifxhcd_hcd_t *_ifxhcd)
{
	struct list_head *epqh_ptr;
	ifxhcd_epqh_t    *epqh;
	struct list_head *urbd_ptr;
	unsigned long     flags;
	ifxhcd_urbd_t    *urbd;

	hfnum_data_t hfnum;
	uint32_t fndiff;

	if(_ifxhcd->disconnecting)
	{
//		printk(KERN_INFO "Warning: %s() Port is in discoonection\n",__func__);
		return ;
	}

	local_irq_save(flags);
	LOCK_EPQH_LIST(_ifxhcd);

	hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum);
	fndiff = hfnum.b.frnum;
	fndiff+= 0x00004000;
	fndiff-= _ifxhcd->lastframe ;
	fndiff&= 0x00003FFF;
	if(!fndiff) fndiff =1;

	#ifdef __EN_ISOC__
		epqh_ptr       = _ifxhcd->epqh_list_isoc.next;
		while (epqh_ptr != &_ifxhcd->epqh_list_isoc)
		{
			epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, ql);
			epqh_ptr = epqh_ptr->next;

			#ifdef __DYN_SOF_INTR__
			if (!list_empty(&epqh->urbd_list))
				_ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF;
			#endif

			if(epqh->pause)
				continue;
			if(epqh->phase==EPQH_READY)
			{
				if(update_interval_counter(epqh,fndiff) || epqh->isoc_now)
				{
					LOCK_URBD_LIST(epqh);
					urbd_ptr       = epqh->urbd_list.next;
					while (urbd_ptr != &epqh->urbd_list)
					{
						urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, ql);
						urbd_ptr=urbd_ptr->next;
						if(urbd->phase==URBD_IDLE)
						{
							if(assign_hc(_ifxhcd, epqh,urbd))
							{
								IFX_DEBUGPL(DBG_HCD, "  select_eps ISOC\n");
								#ifdef __EPQD_DESTROY_TIMEOUT__
									del_timer(&epqh->destroy_timer);
								#endif
								epqh->isoc_now=0;
								list_del_init (&epqh->ql);
								list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_isoc);
								init_hc(epqh);
								epqh->phase=EPQH_ACTIVE;
								urbd->phase==URBD_ACTIVE;
								epqh->hc.phase=HC_WAITING;
								ifxhcd_hc_start(_ifxhcd, epqh->hc);
							}
							break;
						}
					}
					UNLOCK_URBD_LIST(epqh);
				}
			}
		}
	#endif //__EN_ISOC__

	epqh_ptr       = _ifxhcd->epqh_list_intr.next;
	while (epqh_ptr != &_ifxhcd->epqh_list_intr)
	{
		epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, ql);
		epqh_ptr = epqh_ptr->next;
		#ifdef __DYN_SOF_INTR__
		if (!list_empty(&epqh->urbd_list))
			_ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF;
		#endif
		if(epqh->pause)
			continue;
		if(epqh->phase==EPQH_READY)
		{
			if(update_interval_counter(epqh,fndiff))
			{
				LOCK_URBD_LIST(epqh);
				urbd_ptr       = epqh->urbd_list.next;
				while (urbd_ptr != &epqh->urbd_list)
				{
					urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, ql);
					urbd_ptr=urbd_ptr->next;
					if(urbd->phase==URBD_IDLE)
					{
						if(assign_hc(_ifxhcd, epqh,urbd))
						{
							IFX_DEBUGPL(DBG_HCD, "  select_eps INTR\n");
							#ifdef __EPQD_DESTROY_TIMEOUT__
								del_timer(&epqh->destroy_timer);
							#endif
							list_del_init (&epqh->ql);
							list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_intr);
							init_hc(epqh);
							epqh->phase=EPQH_ACTIVE;
							urbd->phase=URBD_ACTIVE;
							epqh->hc->phase=HC_WAITING;
							ifxhcd_hc_start(_ifxhcd, epqh->hc);
						}
						break;
					}
				}
				UNLOCK_URBD_LIST(epqh);
			}
		}
		else if(epqh->phase==EPQH_STDBY)
		{
			if(epqh->period_counter > 0 )
				epqh->period_counter --;
			if(epqh->period_counter == 0)
				ifxhcd_epqh_idle_periodic(epqh);
			update_interval_counter(epqh,fndiff);
		}
		else
			update_interval_counter(epqh,fndiff);
	}

	epqh_ptr       = _ifxhcd->epqh_list_np.next;
	while (epqh_ptr != &_ifxhcd->epqh_list_np)  // may need to preserve at lease one for period
	{
		epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, ql);
		epqh_ptr = epqh_ptr->next;
		#ifdef __DYN_SOF_INTR__
		if (!list_empty(&epqh->urbd_list))
			_ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF;
		#endif
		if(epqh->pause)
			continue;
		if(epqh->phase==EPQH_READY)
		{
			LOCK_URBD_LIST(epqh);
			urbd_ptr       = epqh->urbd_list.next;
			while (urbd_ptr != &epqh->urbd_list)
			{
				urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, ql);
				urbd_ptr=urbd_ptr->next;
				if(urbd->phase==URBD_IDLE)
				{
					if(assign_hc(_ifxhcd, epqh,urbd))
					{
						IFX_DEBUGPL(DBG_HCD, "  select_eps Non-Period\n");
						#ifdef __EPQD_DESTROY_TIMEOUT__
							del_timer(&epqh->destroy_timer);
						#endif
						list_del_init (&epqh->ql);
						list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_np);
						init_hc(epqh);
						epqh->phase=EPQH_ACTIVE;
						urbd->phase=URBD_ACTIVE;
						epqh->hc->phase=HC_WAITING;
						ifxhcd_hc_start(_ifxhcd, epqh->hc);
					}
					break;
				}
			}
			UNLOCK_URBD_LIST(epqh);
		}
	}

	_ifxhcd->lastframe=hfnum.b.frnum;

	UNLOCK_EPQH_LIST(_ifxhcd);
	local_irq_restore(flags);
}

static
void select_eps_func(unsigned long data)
{
	ifxhcd_hcd_t *ifxhcd;
	ifxhcd=((ifxhcd_hcd_t *)data);

	select_eps_sub(ifxhcd);
}

/*!
	 \fn    void select_eps(ifxhcd_hcd_t *_ifxhcd)
	 \brief This function selects transactions from the HCD transfer schedule and assigns them to available host channels.
	 \param _ifxhcd Pointer to the sate of HCD structure
	 \ingroup  IFXUSB_HCD
 */
void select_eps(ifxhcd_hcd_t *_ifxhcd)
{
	if(in_irq())
	{
		if(!_ifxhcd->tasklet_select_eps.func)
		{
			_ifxhcd->tasklet_select_eps.next = NULL;
			_ifxhcd->tasklet_select_eps.state = 0;
			atomic_set( &_ifxhcd->tasklet_select_eps.count, 0);
			_ifxhcd->tasklet_select_eps.func = select_eps_func;
			_ifxhcd->tasklet_select_eps.data = (unsigned long)_ifxhcd;
		}
		tasklet_schedule(&_ifxhcd->tasklet_select_eps);
	}
	else
	{
		select_eps_sub(_ifxhcd);
	}
}

static
void ifxhcd_hc_kickstart(ifxhcd_hcd_t *_ifxhcd)
{
	int               num_channels;
	ifxusb_hc_regs_t *hc_regs;
	int               i;
	ifxhcd_hc_t      *ifxhc;
	num_channels = _ifxhcd->core_if.params.host_channels;

	for (i = 0; i < num_channels; i++)
	{
		ifxhc=&_ifxhcd->ifxhc[i];
		if(ifxhc->phase==HC_STARTING)
		{
			if(ifxhc->sof_delay) ifxhc->sof_delay--;
			if(!ifxhc->sof_delay)
			{
				hcint_data_t hcint;
//				ifxhc->erron=0;
				hc_regs = _ifxhcd->core_if.hc_regs[i];
				hcint.d32 =0xFFFFFFFF;
				ifxusb_wreg(&hc_regs->hcint, hcint.d32);
				hcint.d32 =ifxusb_rreg(&hc_regs->hcintmsk);
				hcint.b.nak =0;
				hcint.b.ack =0;
				hcint.b.nyet=0;
				if(ifxhc->erron)
				{
					hcint.b.ack  =1;
					hcint.b.nak  =1;
					hcint.b.nyet =1;
				}
				#ifdef __NAKSTOP__
				if(ifxhc->stop_on)
				{
					hcint.b.ack  =1;
					hcint.b.nak =1;
				}
				#endif
				ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32);
				ifxusb_wreg(&hc_regs->hcchar, ifxhc->hcchar);
				ifxhc->phase=HC_STARTED;
			}
		}
	}

	for (i = 0; i < num_channels; i++)
	{
		ifxhc=&_ifxhcd->ifxhc[i];
		if(ifxhc->phase==HC_WAITING &&
		    (ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)
		  )
		{
			ifxhcd_hc_start(_ifxhcd, ifxhc);
		}
	}

	for (i = 0; i < num_channels; i++)
	{
		ifxhc=&_ifxhcd->ifxhc[i];
		if(ifxhc->phase==HC_WAITING)
		{
			ifxhcd_hc_start(_ifxhcd, ifxhc);
		}
	}
}

/*
 * Handles the start-of-frame interrupt in host mode. Non-periodic
 * transactions may be queued to the DWC_otg controller for the current
 * (micro)frame. Periodic transactions may be queued to the controller for the
 * next (micro)frame.
 */
static
int32_t handle_sof_intr (ifxhcd_hcd_t *_ifxhcd)
{
	_ifxhcd->pkt_remaining=_ifxhcd->pkt_remaining_reload;
	ifxhcd_hc_kickstart(_ifxhcd);

	select_eps(_ifxhcd);

	/* Clear interrupt */
	{
		gint_data_t gintsts;
		gintsts.d32=0;
		gintsts.b.sofintr = 1;
		ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32);

		#ifdef __DYN_SOF_INTR__
			if(_ifxhcd->dyn_sof_count)
				_ifxhcd->dyn_sof_count--;
			if(!_ifxhcd->dyn_sof_count)
				ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0);
		#endif
	}
	return 1;
}



/* There are multiple conditions that can cause a port interrupt. This function
 * determines which interrupt conditions have occurred and handles them
 * appropriately. */
static int32_t handle_port_intr (ifxhcd_hcd_t *_ifxhcd)
{
	int retval = 0;
	hprt0_data_t hprt0;
	hprt0_data_t hprt0_modify;

	hprt0.d32        =
	hprt0_modify.d32 = ifxusb_rreg(_ifxhcd->core_if.hprt0);

	/* Clear appropriate bits in HPRT0 to clear the interrupt bit in
	 * GINTSTS */

	hprt0_modify.b.prtena = 0;
	hprt0_modify.b.prtconndet = 0;
	hprt0_modify.b.prtenchng = 0;
	hprt0_modify.b.prtovrcurrchng = 0;

	/* Port Connect Detected
	 * Set flag and clear if detected */
	if (hprt0.b.prtconndet) {
		IFX_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
			    "Port Connect Detected--\n", hprt0.d32);
		_ifxhcd->flags.b.port_connect_status_change = 1;
		_ifxhcd->flags.b.port_connect_status = 1;
		hprt0_modify.b.prtconndet = 1;

		/* The Hub driver asserts a reset when it sees port connect
		 * status change flag */
		retval |= 1;
	}

	/* Port Enable Changed
	 * Clear if detected - Set internal flag if disabled */
	if (hprt0.b.prtenchng) {
		IFX_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
			    "Port Enable Changed--\n", hprt0.d32);
		hprt0_modify.b.prtenchng = 1;
		if (hprt0.b.prtena == 1)
		{
			/* Port has been enabled set the reset change flag */
			_ifxhcd->flags.b.port_reset_change = 1;
			if      (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED)
				_ifxhcd->pkt_remaining_reload=_ifxhcd->pkt_remaining_reload_hs;
			else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED)
				_ifxhcd->pkt_remaining_reload=_ifxhcd->pkt_remaining_reload_ls;
			else
				_ifxhcd->pkt_remaining_reload=_ifxhcd->pkt_remaining_reload_fs;
		}
		else
			_ifxhcd->flags.b.port_enable_change = 1;
		retval |= 1;
	}

	/* Overcurrent Change Interrupt */

	if (hprt0.b.prtovrcurrchng) {
		IFX_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
			    "Port Overcurrent Changed--\n", hprt0.d32);
		_ifxhcd->flags.b.port_over_current_change = 1;
		hprt0_modify.b.prtovrcurrchng = 1;
		retval |= 1;
	}

	/* Clear Port Interrupts */
	ifxusb_wreg(_ifxhcd->core_if.hprt0, hprt0_modify.d32);
	return retval;
}

/*
 * This interrupt indicates that SUSPEND state has been detected on
 * the USB.
 * No Functioning in Host Mode
 */
static int32_t handle_usb_suspend_intr(ifxhcd_hcd_t *_ifxhcd)
{
	gint_data_t gintsts;
	IFX_DEBUGP("USB SUSPEND RECEIVED!\n");
	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.usbsuspend = 1;
	ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/*
 * This interrupt indicates that the IFXUSB controller has detected a
 * resume or remote wakeup sequence. If the IFXUSB controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */
static int32_t handle_wakeup_detected_intr(ifxhcd_hcd_t *_ifxhcd)
{
	gint_data_t gintsts;
	hprt0_data_t hprt0 = {.d32=0};
	pcgcctl_data_t pcgcctl = {.d32=0};
	ifxusb_core_if_t *core_if = &_ifxhcd->core_if;

	IFX_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n");

	/*
	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
	 * so that OPT tests pass with all PHYs).
	 */
	/* Restart the Phy Clock */
	pcgcctl.b.stoppclk = 1;
	ifxusb_mreg(core_if->pcgcctl, pcgcctl.d32, 0);
	UDELAY(10);

	/* Now wait for 70 ms. */
	hprt0.d32 = ifxusb_read_hprt0( core_if );
	IFX_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32);
	MDELAY(70);
	hprt0.b.prtres = 0; /* Resume */
	ifxusb_wreg(core_if->hprt0, hprt0.d32);
	IFX_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", ifxusb_rreg(core_if->hprt0));

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.wkupintr = 1;
	ifxusb_wreg(&core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/*
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power.
 */
static int32_t handle_session_req_intr(ifxhcd_hcd_t *_ifxhcd)
{
	/* Clear interrupt */
	gint_data_t gintsts = { .d32 = 0 };
	gintsts.b.sessreqintr = 1;
	ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/*
 * This interrupt indicates that a device has been disconnected from
 * the root port.
 */
static int32_t handle_disconnect_intr(ifxhcd_hcd_t *_ifxhcd)
{
	gint_data_t gintsts;

	ifxhcd_disconnect(_ifxhcd);

	gintsts.d32 = 0;
	gintsts.b.disconnect = 1;
	ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/*
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 */
static int32_t handle_conn_id_status_change_intr(ifxhcd_hcd_t *_ifxhcd)
{
	gint_data_t gintsts;

	IFX_WARN("ID Status Change Interrupt: currently in %s mode\n",
	     ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device");

	gintsts.d32 = 0;
	gintsts.b.conidstschng = 1;
	ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32);
	return 1;
}

static int32_t handle_otg_intr(ifxhcd_hcd_t *_ifxhcd)
{
	ifxusb_core_global_regs_t *global_regs = _ifxhcd->core_if.core_global_regs;
	gotgint_data_t gotgint;
	gotgint.d32 = ifxusb_rreg( &global_regs->gotgint);
	/* Clear GOTGINT */
	ifxusb_wreg (&global_regs->gotgint, gotgint.d32);
	return 1;
}

/** This function will log a debug message */
static int32_t handle_mode_mismatch_intr(ifxhcd_hcd_t *_ifxhcd)
{
	gint_data_t gintsts;

	IFX_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
	     ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device");
	gintsts.d32 = 0;
	gintsts.b.modemismatch = 1;
	ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** This function handles interrupts for the HCD. */
int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd)
{
	int retval = 0;

	ifxusb_core_if_t *core_if = &_ifxhcd->core_if;
	gint_data_t gintsts,gintsts2;

	/* Check if HOST Mode */
	if (ifxusb_is_device_mode(core_if))
	{
		IFX_ERROR("%s() CRITICAL!  IN DEVICE MODE\n", __func__);
		return 0;
	}

	gintsts.d32 = ifxusb_read_core_intr(core_if);
	gintsts2.d32 = 0;

	if (!gintsts.d32)
		return 0;

	//Common INT
	if (gintsts.b.modemismatch)
	{
		retval |= handle_mode_mismatch_intr(_ifxhcd);
		gintsts.b.modemismatch=0;
		gintsts2.b.modemismatch=1;
	}
	if (gintsts.b.otgintr)
	{
		retval |= handle_otg_intr(_ifxhcd);
		gintsts.b.otgintr=0;
		gintsts2.b.otgintr=1;
	}
	if (gintsts.b.conidstschng)
	{
		retval |= handle_conn_id_status_change_intr(_ifxhcd);
		gintsts.b.conidstschng=0;
		gintsts2.b.conidstschng=1;
	}
	if (gintsts.b.disconnect)
	{
		retval |= handle_disconnect_intr(_ifxhcd);
		gintsts.b.disconnect=0;
		gintsts2.b.disconnect=1;
	}
	if (gintsts.b.sessreqintr)
	{
		retval |= handle_session_req_intr(_ifxhcd);
		gintsts.b.sessreqintr=0;
		gintsts2.b.sessreqintr=1;
	}
	if (gintsts.b.wkupintr)
	{
		retval |= handle_wakeup_detected_intr(_ifxhcd);
		gintsts.b.wkupintr=0;
		gintsts2.b.wkupintr=1;
	}
	if (gintsts.b.usbsuspend)
	{
		retval |= handle_usb_suspend_intr(_ifxhcd);
		gintsts.b.usbsuspend=0;
		gintsts2.b.usbsuspend=1;
	}

	//Host Int
	if (gintsts.b.sofintr)
	{
		retval |= handle_sof_intr (_ifxhcd);
		gintsts.b.sofintr=0;
		gintsts2.b.sofintr=1;
	}
	if (gintsts.b.portintr)
	{
		retval |= handle_port_intr (_ifxhcd);
		gintsts.b.portintr=0;
		gintsts2.b.portintr=1;
	}
	if (gintsts.b.hcintr)
	{
		int i;
		haint_data_t haint;
		haint.d32 = ifxusb_read_host_all_channels_intr(core_if);
		for (i=0; i<MAX_EPS_CHANNELS && i< core_if->params.host_channels; i++)
			if (haint.b2.chint & (1 << i))
				retval |= handle_hc_n_intr (_ifxhcd, i);
		gintsts.b.hcintr=0;
		gintsts2.b.hcintr=1;
	}
	return retval;
}

