diff options
Diffstat (limited to 'package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c')
-rw-r--r-- | package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c | 4844 |
1 files changed, 4844 insertions, 0 deletions
diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c new file mode 100644 index 0000000000..27885bb860 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c @@ -0,0 +1,4844 @@ +/***************************************************************************** + ** FILE NAME : ifxhcd_intr.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : This file contains the implementation of the HCD Interrupt handlers. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxhcd_intr.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the implementation of the HCD Interrupt handlers. +*/ + + +#include <linux/version.h> +#include "ifxusb_version.h" + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" + +#include "ifxhcd.h" + +/* Macro used to clear one channel interrupt */ +#define clear_hc_int(_hc_regs_,_intr_) \ + do { \ + hcint_data_t hcint_clear = {.d32 = 0}; \ + hcint_clear.b._intr_ = 1; \ + ifxusb_wreg(&((_hc_regs_)->hcint), hcint_clear.d32); \ + } while (0) + +/* + * Macro used to disable one channel interrupt. Channel interrupts are + * disabled when the channel is halted or released by the interrupt handler. + * There is no need to handle further interrupts of that type until the + * channel is re-assigned. In fact, subsequent handling may cause crashes + * because the channel structures are cleaned up when the channel is released. + */ +#define disable_hc_int(_hc_regs_,_intr_) \ + do { \ + hcint_data_t hcintmsk = {.d32 = 0}; \ + hcintmsk.b._intr_ = 1; \ + ifxusb_mreg(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ + } while (0) + +#define enable_hc_int(_hc_regs_,_intr_) \ + do { \ + hcint_data_t hcintmsk = {.d32 = 0}; \ + hcintmsk.b._intr_ = 1; \ + ifxusb_mreg(&((_hc_regs_)->hcintmsk),0, hcintmsk.d32); \ + } while (0) + +/* + * Save the starting data toggle for the next transfer. The data toggle is + * saved in the QH for non-control transfers and it's saved in the QTD for + * control transfers. + */ +uint8_t read_data_toggle(ifxusb_hc_regs_t *_hc_regs) +{ + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + return(hctsiz.b.pid); +} + + +static void release_channel_dump(ifxhcd_hc_t *ifxhc, + struct urb *urb, + ifxhcd_epqh_t *epqh, + ifxhcd_urbd_t *urbd, + ifxhcd_halt_status_e halt_status) +{ + #ifdef __DEBUG__ + printk(KERN_INFO); + switch (halt_status) + { + case HC_XFER_NO_HALT_STATUS: + printk("HC_XFER_NO_HALT_STATUS");break; + case HC_XFER_URB_COMPLETE: + printk("HC_XFER_URB_COMPLETE");break; + case HC_XFER_AHB_ERR: + printk("HC_XFER_AHB_ERR");break; + case HC_XFER_STALL: + printk("HC_XFER_STALL");break; + case HC_XFER_BABBLE_ERR: + printk("HC_XFER_BABBLE_ERR");break; + case HC_XFER_XACT_ERR: + printk("HC_XFER_XACT_ERR");break; + case HC_XFER_URB_DEQUEUE: + printk("HC_XFER_URB_DEQUEUE");break; + case HC_XFER_FRAME_OVERRUN: + printk("HC_XFER_FRAME_OVERRUN");break; + case HC_XFER_DATA_TOGGLE_ERR: + printk("HC_XFER_DATA_TOGGLE_ERR");break; + #ifdef __NAKSTOP__ + case HC_XFER_NAK: + printk("HC_XFER_NAK");break; + #endif + case HC_XFER_COMPLETE: + printk("HC_XFER_COMPLETE");break; + default: + printk("KNOWN");break; + } + if(ifxhc) + printk("Ch %d %s%s S%d " , ifxhc->hc_num + ,(ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)?"CTRL-": + ((ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)?"BULK-": + ((ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)?"INTR-": + ((ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)?"ISOC-":"????" + ) + ) + ) + ,(ifxhc->is_in)?"IN":"OUT" + ,(ifxhc->split) + ); + else + printk(" [NULL HC] "); + printk("urb=%p epqh=%p urbd=%p\n",urb,epqh,urbd); + + if(urb) + { + printk(KERN_INFO " Device address: %d\n", usb_pipedevice(urb->pipe)); + printk(KERN_INFO " Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), + (usb_pipein(urb->pipe) ? "IN" : "OUT")); + printk(KERN_INFO " Endpoint type: %s\n", + ({char *pipetype; + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: pipetype = "CTRL"; break; + case PIPE_BULK: pipetype = "BULK"; break; + case PIPE_INTERRUPT: pipetype = "INTR"; break; + case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; + default: pipetype = "????"; break; + }; pipetype;})); + printk(KERN_INFO " Speed: %s\n", + ({char *speed; + switch (urb->dev->speed) { + case USB_SPEED_HIGH: speed = "HS"; break; + case USB_SPEED_FULL: speed = "FS"; break; + case USB_SPEED_LOW: speed = "LS"; break; + default: speed = "????"; break; + }; speed;})); + printk(KERN_INFO " Max packet size: %d\n", + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); + printk(KERN_INFO " Data buffer length: %d/%d\n",urb->actual_length, urb->transfer_buffer_length); + printk(KERN_INFO " Transfer buffer: %p, Transfer DMA: %p\n", + urb->transfer_buffer, (void *)urb->transfer_dma); + printk(KERN_INFO " Setup buffer: %p, Setup DMA: %p\n", + urb->setup_packet, (void *)urb->setup_dma); + printk(KERN_INFO " Interval: %d\n", urb->interval); + } + if(urbd) + { + switch (urbd->status) + { + case HC_XFER_NO_HALT_STATUS: + printk(KERN_INFO " STATUS:HC_XFER_NO_HALT_STATUS\n");break; + case HC_XFER_URB_COMPLETE: + printk(KERN_INFO " STATUS:HC_XFER_URB_COMPLETE\n");break; + case HC_XFER_AHB_ERR: + printk(KERN_INFO " STATUS:HC_XFER_AHB_ERR\n");break; + case HC_XFER_STALL: + printk(KERN_INFO " STATUS:HC_XFER_STALL\n");break; + case HC_XFER_BABBLE_ERR: + printk(KERN_INFO " STATUS:HC_XFER_BABBLE_ERR\n");break; + case HC_XFER_XACT_ERR: + printk(KERN_INFO " STATUS:HC_XFER_XACT_ERR\n");break; + case HC_XFER_URB_DEQUEUE: + printk(KERN_INFO " STATUS:HC_XFER_URB_DEQUEUE\n");break; + case HC_XFER_FRAME_OVERRUN: + printk(KERN_INFO " STATUS:HC_XFER_FRAME_OVERRUN\n");break; + case HC_XFER_DATA_TOGGLE_ERR: + printk(KERN_INFO " STATUS:HC_XFER_DATA_TOGGLE_ERR\n");break; + case HC_XFER_COMPLETE: + printk(KERN_INFO " STATUS:HC_XFER_COMPLETE\n");break; + default: + printk(KERN_INFO " STATUS:UNKKNOWN %d\n",urbd->status);break; + } + } + #endif +} + +/*! + \fn static void release_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_halt_status_e _halt_status) + \brief Release the halted channel. + \param _ifxhcd Pointer to the sate of HCD structure + \param _ifxhc Pointer to host channel descriptor + \param _halt_status Halt satus + \return None + \ingroup IFXUSB_HCD + */ + +static void release_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_halt_status_e _halt_status) +{ + ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; + struct urb *urb = NULL; + ifxhcd_epqh_t *epqh = NULL; + ifxhcd_urbd_t *urbd = NULL; + + IFX_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", + __func__, _ifxhc->hc_num, _halt_status); + + epqh=_ifxhc->epqh; + + if(!epqh) + { + if(_halt_status!=HC_XFER_NO_EPQH) + IFX_ERROR("%s epqh=null\n",__func__); + } + else + { + urbd=epqh->urbd; + if(!urbd) + IFX_ERROR("%s urbd=null\n",__func__); + else + { + urb=urbd->urb; + if(!urb) + { + if(_halt_status!=HC_XFER_NO_URB) + IFX_ERROR("%s urb =null\n",__func__); + } + else + { + if (read_data_toggle(hc_regs) == IFXUSB_HCTSIZ_DATA0) + usb_settoggle (urb->dev,usb_pipeendpoint (urb->pipe), (_ifxhc->is_in)?0:1,0); + else if (read_data_toggle(hc_regs) == IFXUSB_HCTSIZ_DATA1) + usb_settoggle (urb->dev,usb_pipeendpoint (urb->pipe), (_ifxhc->is_in)?0:1,1); + } + } + } + + switch (_halt_status) + { + case HC_XFER_NO_HALT_STATUS: + IFX_ERROR("%s: No halt_status, channel %d\n", __func__, _ifxhc->hc_num); +// return; + break; + case HC_XFER_COMPLETE: + IFX_ERROR("%s: Inavalid halt_status HC_XFER_COMPLETE, channel %d\n", __func__, _ifxhc->hc_num); +// return; + break; + case HC_XFER_NO_URB: + break; + case HC_XFER_NO_EPQH: + break; + case HC_XFER_URB_DEQUEUE: + case HC_XFER_AHB_ERR: + case HC_XFER_XACT_ERR: + case HC_XFER_FRAME_OVERRUN: + if(urbd && urb) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + case HC_XFER_URB_COMPLETE: + if(urbd && urb) + { + urbd->phase=URBD_COMPLETING; + ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + case HC_XFER_STALL: + if(urbd) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(_ifxhcd, urbd, -EPIPE); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + if(epqh && urb && urb->dev && urb->pipe) + usb_settoggle(urb->dev, usb_pipeendpoint (urb->pipe), !usb_pipein(urb->pipe), IFXUSB_HC_PID_DATA0); + break; + case HC_XFER_BABBLE_ERR: + case HC_XFER_DATA_TOGGLE_ERR: + if(urbd) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(_ifxhcd, urbd, -EOVERFLOW); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + #ifdef __NAKSTOP__ + case HC_XFER_NAK: + if (_ifxhc->is_in) + { + if(urbd && urb) + { + urbd->phase=URBD_COMPLETING; + ifxhcd_complete_urb(_ifxhcd, urbd, 0); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + #endif + #if defined(__INTRNAKRETRY__) || defined(__INTRINCRETRY__) + case HC_XFER_INTR_NAK_RETRY: + epqh->phase=EPQH_READY; + urbd->phase=URBD_IDLE; + ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); + select_eps(_ifxhcd); + return; + break; + + #endif + } + if(epqh) + { + ifxhcd_epqh_idle(epqh); + } + else if(_halt_status!=HC_XFER_NO_EPQH) + { + IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); + select_eps(_ifxhcd); +} + +/* + * Updates the state of the URB after a Transfer Complete interrupt on the + * host channel. Updates the actual_length field of the URB based on the + * number of bytes transferred via the host channel. Sets the URB status + * if the data transfer is finished. + * + * @return 1 if the data transfer specified by the URB is completely finished, + * 0 otherwise. + */ +static int update_urb_state_xfer_comp(ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + struct urb *_urb, + ifxhcd_urbd_t *_urbd) +{ + int xfer_done = 0; + + #ifdef __EN_ISOC__ + if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_ISOC) + { + struct usb_iso_packet_descriptor *frame_desc; + frame_desc = &_urb->iso_frame_desc[_urbd->isoc_frame_index]; + if (_ifxhc->is_in) + { + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + frame_desc->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + if ((hctsiz.b.xfersize != 0) || (frame_desc->actual_length >= _urbd->xfer_len)) + { + xfer_done = 1; + frame_desc->status = 0; + #if 0 + if (frame_desc->actual_length < frame_desc->length && _urb->transfer_flags & URB_SHORT_NOT_OK) + frame_desc->status = -EREMOTEIO; + #endif + } + } + else + { + if (_ifxhc->split) + frame_desc->actual_length += _ifxhc->ssplit_out_xfer_count; + else + frame_desc->actual_length += _ifxhc->xfer_len; + if (frame_desc->actual_length >= _urbd->xfer_len) + { + xfer_done = 1; + frame_desc->status = 0; + } + } + } + else + #endif + if (_ifxhc->is_in) + { + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + _urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +#ifdef __INTRINCRETRY__ + if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_INTR) + { + if(_ifxhc->xfer_len != hctsiz.b.xfersize) + { + xfer_done = 1; + _urbd->status = 0; + } + } + else +#endif + if ((hctsiz.b.xfersize != 0) || (_urb->actual_length >= _urb->transfer_buffer_length)) + { + xfer_done = 1; + _urbd->status = 0; + if(_urb->transfer_flags & URB_SHORT_NOT_OK) + { + if (_urb->actual_length < _urb->transfer_buffer_length) + _urbd->status = -EREMOTEIO; + } + } + } + else if(_urb->transfer_buffer_length%_ifxhc->mps) // OUT without ZLP + { + if (_ifxhc->split) + _urb->actual_length += _ifxhc->ssplit_out_xfer_count; + else + _urb->actual_length += _ifxhc->xfer_len; + if (_urb->actual_length >= _urb->transfer_buffer_length) + { + xfer_done = 1; + _urbd->status = 0; + } + } + else if (_urb->actual_length >= _urb->transfer_buffer_length) //OUT with ZLP + { + xfer_done = 1; + _urbd->status = 0; + } + else //OUT without ZLP, unfinished + { + if (_ifxhc->split) + _urb->actual_length += _ifxhc->ssplit_out_xfer_count; + else + _urb->actual_length += _ifxhc->xfer_len; + if (!_ifxhc->short_rw && _urb->actual_length >= _urb->transfer_buffer_length) + { + xfer_done = 1; + _urbd->status = 0; + } + } + + #ifdef __DEBUG__ + { + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + IFX_DEBUGPL(DBG_HCDV, "IFXUSB: %s: %s, channel %d\n", + __func__, (_ifxhc->is_in ? "IN" : "OUT"), _ifxhc->hc_num); + IFX_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _ifxhc->xfer_len); + IFX_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); + #ifdef __EN_ISOC__ + if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_ISOC) + { + IFX_DEBUGPL(DBG_HCDV, " descritor # %d\n", _urbd->isoc_frame_index); + IFX_DEBUGPL(DBG_HCDV, " buffer_length %d\n", + _urb->iso_frame_desc[_urbd->isoc_frame_index].length); + IFX_DEBUGPL(DBG_HCDV, " actual_length %d\n", _urb->iso_frame_desc[_urbd->isoc_frame_index].actual_length); + } + else + #endif + { + IFX_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", + _urb->transfer_buffer_length); + IFX_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); + } + } + #endif + return xfer_done; +} + +#ifdef __EN_ISOC__ + static void next_isoc_sub(unsigned long data) + { + ifxhcd_urbd_t *urbd; + ifxhcd_hcd_t *ifxhcd; + + urbd=((ifxhcd_urbd_t *)data); + ifxhcd=urbd->epqh->ifxhcd; + + if (!urbd->epqh) + IFX_ERROR("%s: invalid epqd\n",__func__); + #if defined(__UNALIGNED_BUF_ADJ__) + else + { + if( urbd->aligned_checked && +// urbd->using_aligned_buf && + urbd->xfer_buff && + urbd->is_in) + { + uint8_t *buf; + + buf=urbd->xfer_buff; + buf+=urbd->urb->iso_frame_desc[urbd->isoc_frame_index].offset; + memcpy(buf,urbd->aligned_buf,urbd->urb->iso_frame_desc[urbd->isoc_frame_index].length); + } +// urbd->using_aligned_buf=0; +// urbd->using_aligned_setup=0; + } + #endif + + urbd->isoc_frame_index++; + if(urbd->isoc_frame_index>=urbd->urb->number_of_packets) + release_channel(ifxhcd,urbd->epqh->hc,HC_XFER_URB_COMPLETE); + else + init_hc(urbd->epqh); + } +#endif + +/*! + \fn static void complete_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_urbd_t *_urbd) + \brief Complete the transaction on the channel. + \param _ifxhcd Pointer to the sate of HCD structure + \param _ifxhc Pointer to host channel descriptor + \param _urbd Pointer to URB descriptor + \return None + \ingroup IFXUSB_HCD + */ +static void complete_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_urbd_t *_urbd) +{ + ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; + struct urb *urb = NULL; + ifxhcd_epqh_t *epqh = NULL; + int urb_xfer_done; + + IFX_DEBUGPL(DBG_HCD, "--Complete Channel %d : \n", _ifxhc->hc_num); + + if(!_urbd) + { + IFX_ERROR("ERROR %s():%d urbd=%p\n",__func__,__LINE__,_urbd); + return; + } + + urb = _urbd->urb; + epqh = _urbd->epqh; + + if(!epqh) + { + release_channel(_ifxhcd,_ifxhc,HC_XFER_NO_EPQH); + return; + } + if(!urb || (unsigned long)urb->hcpriv!=(unsigned long)_urbd) + { + release_channel(_ifxhcd,_ifxhc,HC_XFER_NO_URB); + return; + } + + if (_ifxhc->split) + _ifxhc->split = 1; + + switch (epqh->ep_type) + { + case IFXUSB_EP_TYPE_CTRL: + switch (_ifxhc->control_phase) + { + case IFXHCD_CONTROL_SETUP: + if (_urbd->xfer_len > 0) + { + _ifxhc->control_phase = IFXHCD_CONTROL_DATA; + IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done Data Stage now\n"); + _ifxhc->is_in = _urbd->is_in; + _ifxhc->xfer_len = _urbd->xfer_len; + #if defined(__UNALIGNED_BUF_ADJ__) + if(_urbd->aligned_buf) + _ifxhc->xfer_buff = _urbd->aligned_buf; + else + #endif + _ifxhc->xfer_buff = _urbd->xfer_buff; + #ifdef __NAKSTOP__ + if(!_ifxhc->split) + { + #ifdef __INNAKSTOP_CTRL__ + if(_ifxhc->is_in) + _ifxhc->stop_on=1; + #endif + #ifdef __PINGSTOP_CTRL__ + if(!_ifxhc->is_in) + _ifxhc->stop_on=1; + #endif + } + #endif + } + else + { + IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done Status Stage now\n"); + _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; + _ifxhc->is_in = 1; + _ifxhc->xfer_len = 0; + _ifxhc->xfer_buff = _ifxhcd->status_buf; + #ifdef __NAKSTOP__ + _ifxhc->stop_on=0; + #endif + } + if(_ifxhc->is_in) + _ifxhc->short_rw =0; + else + _ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + break; + case IFXHCD_CONTROL_DATA: + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + if (urb_xfer_done) + { + _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; + IFX_DEBUGPL(DBG_HCDV, " Control data transaction done Status Stage now\n"); + _ifxhc->is_in = (_urbd->is_in)?0:1; + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->xfer_buff = _ifxhcd->status_buf; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + if(_ifxhc->is_in) + _ifxhc->short_rw =0; + else + _ifxhc->short_rw =1; + #ifdef __NAKSTOP__ + _ifxhc->stop_on=0; + #endif + } + else // continue + { + IFX_DEBUGPL(DBG_HCDV, " Control data transaction continue\n"); + _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; + _ifxhc->xfer_count = urb->actual_length; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = read_data_toggle(hc_regs); + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + break; + case IFXHCD_CONTROL_STATUS: + IFX_DEBUGPL(DBG_HCDV, " Control status transaction done\n"); + if (_urbd->status == -EINPROGRESS) + _urbd->status = 0; + release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); + break; + } + break; + case IFXUSB_EP_TYPE_BULK: + IFX_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + if (urb_xfer_done) + release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); + else + { + _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; + _ifxhc->xfer_count = urb->actual_length; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = read_data_toggle(hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + break; + case IFXUSB_EP_TYPE_INTR: + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + + #ifdef __INTRINCRETRY__ + if(!urb_xfer_done) + release_channel(_ifxhcd,_ifxhc,HC_XFER_INTR_NAK_RETRY); + else + #endif + release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); + break; + case IFXUSB_EP_TYPE_ISOC: + #ifdef __EN_ISOC__ + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + if (urb_xfer_done) + { + #if defined(__UNALIGNED_BUF_ADJ__) + if(in_irq()) + { + if(!epqh->tasklet_next_isoc.func) + { + epqh->tasklet_next_isoc.next = NULL; + epqh->tasklet_next_isoc.state = 0; + atomic_set( &epqh->tasklet_next_isoc.count, 0); + epqh->tasklet_next_isoc.func = next_isoc_sub; + epqh->tasklet_next_isoc.data = (unsigned long)_urbd; + } + tasklet_schedule(&epqh->tasklet_next_isoc); + } + else + #endif + { + next_isoc_sub((unsigned long)_urbd); + } + } + else + { + struct usb_iso_packet_descriptor *frame_desc; + frame_desc = &urb->iso_frame_desc[_urbd->isoc_frame_index]; + _ifxhc->xfer_len = _urbd->xfer_len - frame_desc->actual_length; + _ifxhc->xfer_count = frame_desc->actual_length; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = read_data_toggle(hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + #endif + break; + } +} + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __INNAKSTOP_CTRL__ + if (_ifxhc->halt_status == HC_XFER_NAK) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + + if(_urbd->xfer_len && actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + else + { + printk(KERN_INFO "Warning: %s() %d Invalid CTRL Phase:%d\n",__func__,__LINE__,_ifxhc->control_phase); + release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); + } + return 1; + } + #endif + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + #if 0 + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.bblerr) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + #if 0 + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + #if 1 + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + #if 1 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + #if 0 + #if 1 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length = actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + } + #endif + #else + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + #endif + return 1; + } + else if(hcint.b.frmovrun ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __PINGSTOP_CTRL__ + if (_ifxhc->halt_status == HC_XFER_NAK) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + + if(_urbd->xfer_len && actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + else + { + printk(KERN_INFO "Warning: %s() %d Invalid CTRL Phase:%d\n",__func__,__LINE__,_ifxhc->control_phase); + release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); + } + return 1; + } + #endif + + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) + { + // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr + // Solution: NoSplit: Resend at next SOF + // Split : Resend at next SOF with SSPLIT + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + { + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_SETUP) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + #if 0 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + _ifxhc->epqh->do_ping=1; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + return 1; + } + else if(hcint.b.bblerr ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.nak || hcint.b.nyet) + { + #ifdef __PINGSTOP_CTRL__ + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + #else + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_SETUP) + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + #if 0 + _ifxhc->epqh->do_ping=1; + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + _ifxhc->epqh->do_ping=1; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->erron=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + #endif + } + #endif + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __INNAKSTOP_BULK__ + if(_ifxhc->halt_status == HC_XFER_NAK) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + + if( + (_urbd->xfer_len && actual_length>=_urbd->xfer_len) + || hctsiz.b.pktcnt==0 + || (hctsiz.b.xfersize % _ifxhc->mps)>0 + ) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + #endif + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.bblerr) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + #if 0 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + return 1; + } + else if(hcint.b.datatglerr ) + { + #if 0 + #if 1 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length = actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + } + #endif + #else + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + #endif + return 1; + } + else if(hcint.b.frmovrun ) + { +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d sz:%d/%d/%d/%d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status , hctsiz.b.xfersize, _ifxhc->xfer_len-_ifxhc->xfer_len,_ifxhc->xfer_len,_urbd->xfer_len); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __PINGSTOP_BULK__ + if (_ifxhc->halt_status == HC_XFER_NAK) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + + if(_urbd->xfer_len && actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + #endif + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) + { + // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr + // Solution: NoSplit: Resend at next SOF + // Split : Resend at next SOF with SSPLIT + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + { + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(_urbd->urb->actual_length>_urbd->xfer_len) _urbd->urb->actual_length=_urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + #if 0 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + _ifxhc->epqh->do_ping=1; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(_urbd->urb->actual_length>_urbd->xfer_len) _urbd->urb->actual_length=_urbd->xfer_len; + IFX_ERROR("ERROR %s():%d invalid packet babble\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.nak || hcint.b.nyet) + { + #ifdef __PINGSTOP_BULK__ + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + #else + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + #if 0 + _ifxhc->epqh->do_ping=1; + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + _ifxhc->epqh->do_ping=1; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->erron=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + #endif + } + #endif + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + + // Don't care shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.bblerr) + { + _urbd->error_count =0; + + // Don't care shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + return 1; + } + else if (hcint.b.datatglerr || hcint.b.frmovrun) + { + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + return 1; + } + else if(hcint.b.nyet ) + { + return 1; + } + else if (hcint.b.nak) + { + + #ifdef __INTRNAKRETRY__ + if(hctsiz.b.pktcnt) + { + release_channel(_ifxhcd, _ifxhc, HC_XFER_INTR_NAK_RETRY); + return 1; + } + #endif + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else + { + _urbd->error_count =0; + //restart INTR immediately + #if 0 + if(hctsiz.b.pktcnt>0) + { + // TODO Re-initialize Channel (in next b_interval - 1 uF/F) + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + #endif + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nyet); + disable_hc_int(_hc_regs,nak); + _urbd->error_count =0; + + // Don't care shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->xfer_len!=0)// !_ifxhc->is_in + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if(hcint.b.nak || hcint.b.frmovrun ) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nyet); + disable_hc_int(_hc_regs,nak); + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if(hcint.b.xacterr ) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #ifdef __EN_ISOC__ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + if (hcint.b.xfercomp || hcint.b.frmovrun || hcint.d32 == 0x02) + { + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + if (hcint.b.xfercomp) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + } + else if (hcint.b.xacterr || hcint.b.bblerr) + { + #ifndef VR9Skip + if(hctsiz.b.pktcnt==0) + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + if (hcint.b.bblerr) + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + else if (hcint.b.xacterr) + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + enable_hc_int(_hc_regs,ack); + enable_hc_int(_hc_regs,nak); + enable_hc_int(_hc_regs,nyet); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else if(hcint.b.datatglerr ) + { + return 1; + } + else if(hcint.b.stall ) + { + return 1; + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #ifdef __EN_ISOC__ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.frmovrun) + { + #ifndef VR9Skip + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + #endif + } + else if(hcint.b.datatglerr ) + { + return 1; + } + else if(hcint.b.bblerr ) + { + #ifndef VR9Skip + if(hctsiz.b.pktcnt==0) + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + else + { + enable_hc_int(_hc_regs,ack); + enable_hc_int(_hc_regs,nak); + enable_hc_int(_hc_regs,nyet); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else if(hcint.b.xacterr ) + { + if(hctsiz.b.pktcnt==0) + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.stall ) + { + return 1; + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack) + { + _urbd->error_count=0; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.nak) + { + _urbd->error_count = 0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.xacterr) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.nyet ) + { + } + else if(hcint.b.xfercomp ) + { + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack ) + { + _urbd->error_count=0; + if (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP) + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + if (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP) + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nak ) + { + _urbd->error_count =0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.xfercomp ) + { + printk(KERN_INFO "Warning: %s() %d CTRL OUT SPLIT1 COMPLETE\n",__func__,__LINE__); + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack) + { + _urbd->error_count=0; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.nak) + { + _urbd->error_count = 0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.xacterr) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.nyet ) + { + } + else if(hcint.b.xfercomp ) + { + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack ) + { + _urbd->error_count=0; + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nak ) + { + _urbd->error_count =0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + 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; +} + |