610 lines
20 KiB
C
610 lines
20 KiB
C
|
/*!
|
||
|
\file usbh_int.c
|
||
|
\brief USB host mode interrupt handler file
|
||
|
|
||
|
\version 2017-06-06, V1.0.0, firmware for GD32F3x0
|
||
|
\version 2019-06-01, V2.0.0, firmware for GD32F3x0
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
Copyright (c) 2019, GigaDevice Semiconductor Inc.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without modification,
|
||
|
are permitted provided that the following conditions are met:
|
||
|
|
||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||
|
list of conditions and the following disclaimer.
|
||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||
|
this list of conditions and the following disclaimer in the documentation
|
||
|
and/or other materials provided with the distribution.
|
||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||
|
may be used to endorse or promote products derived from this software without
|
||
|
specific prior written permission.
|
||
|
|
||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||
|
*/
|
||
|
|
||
|
#include "usb_core.h"
|
||
|
#include "usb_defines.h"
|
||
|
#include "usbh_int.h"
|
||
|
|
||
|
static uint32_t usbh_intf_sof (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_port (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_hc (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_hc_in (usb_core_handle_struct *pudev, uint8_t channel_num);
|
||
|
static uint32_t usbh_intf_hc_out (usb_core_handle_struct *pudev, uint8_t channel_num);
|
||
|
static uint32_t usbh_intf_rxfifo_noempty (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_nptxfifo_empty (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_ptxfifo_empty (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_disconnect (usb_core_handle_struct *pudev);
|
||
|
static uint32_t usbh_intf_iso_incomplete_xfer (usb_core_handle_struct *pudev);
|
||
|
|
||
|
/*!
|
||
|
\brief handle global host interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
uint32_t usbh_isr (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
uint32_t retval = 0U;
|
||
|
uint32_t int_flag = 0U;
|
||
|
|
||
|
/* check if host mode */
|
||
|
if (USB_CURRENT_MODE_GET() == HOST_MODE) {
|
||
|
USB_CORE_INTR_READ(int_flag);
|
||
|
|
||
|
if (!int_flag) {
|
||
|
return 0U;
|
||
|
}
|
||
|
|
||
|
/* start of frame interrupt handle */
|
||
|
if (int_flag & GINTF_SOF) {
|
||
|
retval |= usbh_intf_sof (pudev);
|
||
|
}
|
||
|
|
||
|
/* Rx FIFO non-empty interrupt handle */
|
||
|
if (int_flag & GINTF_RXFNEIF) {
|
||
|
retval |= usbh_intf_rxfifo_noempty (pudev);
|
||
|
}
|
||
|
|
||
|
/* Non-Periodic Tx FIFO empty interrupt hanlde */
|
||
|
if (int_flag & GINTF_NPTXFEIF) {
|
||
|
retval |= usbh_intf_nptxfifo_empty (pudev);
|
||
|
}
|
||
|
|
||
|
/* periodic Tx FIFO empty interrupt handle */
|
||
|
if (int_flag & GINTF_PTXFEIF) {
|
||
|
retval |= usbh_intf_ptxfifo_empty (pudev);
|
||
|
}
|
||
|
|
||
|
/* host channels interrupt handle */
|
||
|
if (int_flag & GINTF_HCIF) {
|
||
|
retval |= usbh_intf_hc (pudev);
|
||
|
}
|
||
|
|
||
|
/* host port interrupt handle */
|
||
|
if (int_flag & GINTF_HPIF) {
|
||
|
retval |= usbh_intf_port (pudev);
|
||
|
}
|
||
|
|
||
|
/* disconnect interrupt handle */
|
||
|
if (int_flag & GINTF_DISCIF) {
|
||
|
retval |= usbh_intf_disconnect (pudev);
|
||
|
}
|
||
|
|
||
|
/* isochronous IN transfer not complete interrupt handle */
|
||
|
if (int_flag & GINTF_ISOONCIF) {
|
||
|
retval |= usbh_intf_iso_incomplete_xfer (pudev);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the start-of-frame interrupt in host mode
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_sof (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
usbh_hcd_int_fops->sof(pudev);
|
||
|
|
||
|
/* clear interrupt */
|
||
|
USB_GINTF = GINTF_SOF;
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle all host channels interrupt in host mode
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_hc (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
uint8_t i = 0U;
|
||
|
uint32_t retval = 0U;
|
||
|
|
||
|
for (i = 0U; i < pudev->cfg.host_channel_num; i++) {
|
||
|
if ((USB_HACHINT & HACHINT_HACHINT) & ((uint32_t)1U << i)) {
|
||
|
if ((USB_HCHxCTL((uint16_t)i) & HCHCTL_EPDIR) >> 15U) {
|
||
|
retval |= usbh_intf_hc_in (pudev, i);
|
||
|
} else {
|
||
|
retval |= usbh_intf_hc_out (pudev, i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the disconnect interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_disconnect (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
usbh_hcd_int_fops->device_disconnected(pudev);
|
||
|
|
||
|
/* clear interrupt */
|
||
|
USB_GINTF = GINTF_DISCIF;
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the non-periodic tx fifo empty interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_nptxfifo_empty (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
uint8_t channel_num = 0U;
|
||
|
uint32_t dword_len = 0U, len = 0U;
|
||
|
usb_hostchannel_struct *puhc;
|
||
|
|
||
|
channel_num = (uint8_t)((USB_HNPTFQSTAT & HNPTFQSTAT_CNUM) >> 27U);
|
||
|
puhc = &pudev->host.host_channel[channel_num];
|
||
|
dword_len = (puhc->xfer_len + 3U) / 4U;
|
||
|
|
||
|
while (((USB_HNPTFQSTAT & HNPTFQSTAT_NPTXFS) > dword_len) && (0U != puhc->xfer_len)) {
|
||
|
len = (USB_HNPTFQSTAT & HNPTFQSTAT_NPTXFS) * 4U;
|
||
|
|
||
|
if (len > puhc->xfer_len) {
|
||
|
/* last packet */
|
||
|
len = (uint16_t)puhc->xfer_len;
|
||
|
|
||
|
USB_GINTEN &= ~GINTF_NPTXFEIF;
|
||
|
|
||
|
}
|
||
|
|
||
|
dword_len = (puhc->xfer_len + 3U) / 4U;
|
||
|
usb_fifo_write (puhc->xfer_buff, channel_num, (uint16_t)len);
|
||
|
|
||
|
puhc->xfer_buff += len;
|
||
|
puhc->xfer_len -= len;
|
||
|
puhc->xfer_count += len;
|
||
|
}
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the periodic tx fifo empty interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_ptxfifo_empty (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
uint8_t channel_num = 0U;
|
||
|
uint32_t dword_len = 0U, len = 0U;
|
||
|
usb_hostchannel_struct *puhc;
|
||
|
|
||
|
channel_num = (uint8_t)((USB_HPTFQSTAT & HPTFQSTAT_CNUM) >> 27U);
|
||
|
puhc = &pudev->host.host_channel[channel_num];
|
||
|
dword_len = (puhc->xfer_len + 3U) / 4U;
|
||
|
|
||
|
while (((USB_HPTFQSTAT & HPTFQSTAT_PTXFS) > dword_len) && (0U != puhc->xfer_len)) {
|
||
|
len = (USB_HPTFQSTAT & HPTFQSTAT_PTXFS) * 4U;
|
||
|
|
||
|
if (len > puhc->xfer_len) {
|
||
|
len = puhc->xfer_len;
|
||
|
|
||
|
/* last packet */
|
||
|
USB_GINTEN &= ~GINTF_PTXFEIF;
|
||
|
}
|
||
|
|
||
|
dword_len = (puhc->xfer_len + 3U) / 4U;
|
||
|
usb_fifo_write (puhc->xfer_buff, channel_num, (uint16_t)len);
|
||
|
|
||
|
puhc->xfer_buff += len;
|
||
|
puhc->xfer_len -= len;
|
||
|
puhc->xfer_count += len;
|
||
|
}
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the host port interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_port (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
uint8_t port_speed = 0U;
|
||
|
uint8_t port_reset = 0U;
|
||
|
uint32_t retval = 0U;
|
||
|
__IO uint32_t hostportdup = USB_HPCS;
|
||
|
|
||
|
/* clear the interrupt bits in gintsts */
|
||
|
hostportdup &= ~HPCS_PE;
|
||
|
hostportdup &= ~HPCS_PCD;
|
||
|
hostportdup &= ~HPCS_PEDC;
|
||
|
|
||
|
/* port connect detected */
|
||
|
if (USB_HPCS & HPCS_PCD) {
|
||
|
hostportdup |= HPCS_PCD;
|
||
|
usbh_hcd_int_fops->device_connected(pudev);
|
||
|
retval |= 1U;
|
||
|
}
|
||
|
|
||
|
/* port enable changed */
|
||
|
if (USB_HPCS & HPCS_PEDC) {
|
||
|
hostportdup |= HPCS_PEDC;
|
||
|
|
||
|
if (USB_HPCS & HPCS_PE) {
|
||
|
port_speed = (uint8_t)((USB_HPCS & HPCS_PS) >> 17U);
|
||
|
|
||
|
if (HPRT_PRTSPD_LOW_SPEED == port_speed) {
|
||
|
USB_HFT = 6000U;
|
||
|
|
||
|
if (HCTLR_6_MHZ != (USB_HCTL & HCTL_CLKSEL)) {
|
||
|
if (USB_CORE_EMBEDDED_PHY == pudev->cfg.phy_interface) {
|
||
|
USB_FSLSCLOCK_INIT(HCTLR_6_MHZ);
|
||
|
}
|
||
|
port_reset = 1U;
|
||
|
}
|
||
|
} else if(HPRT_PRTSPD_FULL_SPEED == port_speed) {
|
||
|
USB_HFT = 48000U;
|
||
|
|
||
|
if (HCTLR_48_MHZ != (USB_HCTL & HCTL_CLKSEL)) {
|
||
|
if (USB_CORE_EMBEDDED_PHY == pudev->cfg.phy_interface) {
|
||
|
USB_FSLSCLOCK_INIT(HCTLR_48_MHZ);
|
||
|
}
|
||
|
port_reset = 1U;
|
||
|
}
|
||
|
} else {
|
||
|
/* for high speed device and others */
|
||
|
port_reset = 1U;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (port_reset) {
|
||
|
usb_port_reset(pudev);
|
||
|
}
|
||
|
|
||
|
/* clear port interrupts */
|
||
|
USB_HPCS = hostportdup;
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the OUT channel interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[in] channel_num: host channel number which is in (0..7)
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_hc_out (usb_core_handle_struct *pudev, uint8_t channel_num)
|
||
|
{
|
||
|
uint32_t channel_intr = USB_HCHxINTF((uint16_t)channel_num);
|
||
|
usb_hostchannel_struct *puhc = &pudev->host.host_channel[channel_num];
|
||
|
|
||
|
channel_intr &= USB_HCHxINTEN((uint16_t)channel_num);
|
||
|
|
||
|
if (channel_intr & HCHINTF_ACK) {
|
||
|
if (URB_PING == puhc->urb_state) {
|
||
|
puhc->err_count = 0U;
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_TF;
|
||
|
puhc->status = HC_XF;
|
||
|
}
|
||
|
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_ACK;
|
||
|
} else if (channel_intr & HCHINTF_REQOVR) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_REQOVR;
|
||
|
} else if (channel_intr & HCHINTF_TF) {
|
||
|
puhc->err_count = 0U;
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_TF;
|
||
|
puhc->status = HC_XF;
|
||
|
} else if (channel_intr & HCHINTF_STALL) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_STALL;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
puhc->status = HC_STALL;
|
||
|
} else if (channel_intr & HCHINTF_NAK) {
|
||
|
puhc->err_count = 0U;
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_NAK;
|
||
|
puhc->status = HC_NAK;
|
||
|
} else if (channel_intr & HCHINTF_USBER) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
puhc->err_count ++;
|
||
|
puhc->status = HC_TRACERR;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_USBER;
|
||
|
} else if (channel_intr & HCHINTF_NYET) {
|
||
|
puhc->err_count = 0U;
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
puhc->status = HC_NYET;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_NYET;
|
||
|
} else if (channel_intr & HCHINTF_DTER) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
puhc->status= HC_DTGERR;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_DTER;
|
||
|
} else if (channel_intr & HCHINTF_CH) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) &= ~HCHINTEN_CHIE;
|
||
|
|
||
|
switch (puhc->status) {
|
||
|
case HC_XF:
|
||
|
puhc->urb_state = URB_DONE;
|
||
|
|
||
|
if (USB_EPTYPE_BULK == ((USB_HCHxCTL((uint16_t)channel_num) & HCHCTL_EPTYPE) >> 18)) {
|
||
|
puhc->data_tg_out ^= 1U;
|
||
|
}
|
||
|
break;
|
||
|
case HC_NAK:
|
||
|
puhc->urb_state = URB_NOTREADY;
|
||
|
break;
|
||
|
case HC_NYET:
|
||
|
break;
|
||
|
case HC_STALL:
|
||
|
puhc->urb_state = URB_STALL;
|
||
|
break;
|
||
|
case HC_TRACERR:
|
||
|
if (3U == puhc->err_count) {
|
||
|
puhc->urb_state = URB_ERROR;
|
||
|
puhc->err_count = 0U;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_CH;
|
||
|
} else {
|
||
|
/* no operation */
|
||
|
}
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the IN channel interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[in] channel_num: host channel number which is in (0..7)
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_hc_in (usb_core_handle_struct *pudev, uint8_t channel_num)
|
||
|
{
|
||
|
uint8_t endp_type = 0U;
|
||
|
usb_hostchannel_struct *puhc = &pudev->host.host_channel[channel_num];
|
||
|
|
||
|
uint32_t channle_intf = USB_HCHxINTF((uint16_t)channel_num);
|
||
|
__IO uint32_t channel_ctrl = USB_HCHxCTL((uint16_t)channel_num);
|
||
|
|
||
|
channle_intf &= USB_HCHxINTEN((uint16_t)channel_num);
|
||
|
|
||
|
endp_type = (uint8_t)((channel_ctrl & HCHCTL_EPTYPE) >> 18U);
|
||
|
|
||
|
if (channle_intf & HCHINTF_ACK) {
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_ACK;
|
||
|
} else if (channle_intf & HCHINTF_STALL) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
puhc->status = HC_STALL;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_NAK;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_STALL;
|
||
|
|
||
|
/* NOTE: When there is a 'stall', reset also nak,
|
||
|
else, the pudev->host.status = HC_STALL
|
||
|
will be overwritten by 'nak' in code below */
|
||
|
channle_intf &= ~HCHINTF_NAK;
|
||
|
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
} else if (channle_intf & HCHINTF_DTER) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_NAK;
|
||
|
puhc->status = HC_DTGERR;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_DTER;
|
||
|
} else {
|
||
|
/* no operation */
|
||
|
}
|
||
|
|
||
|
if (channle_intf & HCHINTF_REQOVR) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_REQOVR;
|
||
|
} else if (channle_intf & HCHINTF_TF) {
|
||
|
puhc->status = HC_XF;
|
||
|
puhc->err_count = 0U;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_TF;
|
||
|
|
||
|
if ((USB_EPTYPE_CTRL == endp_type) || (USB_EPTYPE_BULK == endp_type)) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_NAK;
|
||
|
puhc->data_tg_in ^= 1U;
|
||
|
} else if (USB_EPTYPE_INTR == endp_type) {
|
||
|
channel_ctrl |= HCHCTL_ODDFRM;
|
||
|
USB_HCHxCTL((uint16_t)channel_num) = channel_ctrl;
|
||
|
puhc->urb_state = URB_DONE;
|
||
|
} else {
|
||
|
/* no operation */
|
||
|
}
|
||
|
} else if (channle_intf & HCHINTF_CH) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) &= ~HCHINTEN_CHIE;
|
||
|
|
||
|
switch (puhc->status) {
|
||
|
case HC_XF:
|
||
|
puhc->urb_state = URB_DONE;
|
||
|
break;
|
||
|
case HC_TRACERR:
|
||
|
case HC_DTGERR:
|
||
|
puhc->err_count = 0U;
|
||
|
puhc->urb_state = URB_ERROR;
|
||
|
break;
|
||
|
case HC_STALL:
|
||
|
puhc->urb_state = URB_STALL;
|
||
|
break;
|
||
|
default:
|
||
|
if (USB_EPTYPE_INTR == endp_type) {
|
||
|
puhc->data_tg_in ^= 1U;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_CH;
|
||
|
} else if (channle_intf & HCHINTF_USBER) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
(puhc->err_count)++;
|
||
|
puhc->status = HC_TRACERR;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_USBER;
|
||
|
} else if (channle_intf & HCHINTF_NAK) {
|
||
|
if (USB_EPTYPE_INTR == endp_type) {
|
||
|
USB_HCHxINTEN((uint16_t)channel_num) |= HCHINTEN_CHIE;
|
||
|
usb_hostchannel_halt(pudev, channel_num);
|
||
|
} else if ((USB_EPTYPE_CTRL == endp_type) || (USB_EPTYPE_BULK == endp_type)) {
|
||
|
/* re-activate the channel */
|
||
|
channel_ctrl |= HCHCTL_CEN;
|
||
|
channel_ctrl &= ~HCHCTL_CDIS;
|
||
|
USB_HCHxCTL((uint16_t)channel_num) = channel_ctrl;
|
||
|
} else {
|
||
|
/* no operation */
|
||
|
}
|
||
|
|
||
|
puhc->status = HC_NAK;
|
||
|
USB_HCHxINTF((uint16_t)channel_num) = HCHINTF_NAK;
|
||
|
} else {
|
||
|
/* no operation */
|
||
|
}
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the rx fifo non-empty interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_rxfifo_noempty (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
uint32_t count = 0U;
|
||
|
__IO uint8_t channel_num = 0U;
|
||
|
__IO uint32_t rx_status = 0U;
|
||
|
uint32_t usbh_ch_ctl_reg = 0U;
|
||
|
usb_hostchannel_struct *puhc;
|
||
|
|
||
|
/* disable the Rx status queue level interrupt */
|
||
|
USB_GINTEN &= ~GINTF_RXFNEIF;
|
||
|
|
||
|
rx_status = USB_GRSTATP;
|
||
|
channel_num = (uint8_t)(rx_status & GRSTATRP_CNUM);
|
||
|
puhc = &pudev->host.host_channel[channel_num];
|
||
|
|
||
|
switch ((rx_status & GRSTATRP_RPCKST) >> 17) {
|
||
|
case GRSTATR_RPCKST_IN:
|
||
|
count = (rx_status & GRSTATRP_BCOUNT) >> 4;
|
||
|
|
||
|
/* read the data into the host buffer. */
|
||
|
if ((count > 0U) && (puhc->xfer_buff != (void *)0)) {
|
||
|
usb_fifo_read(puhc->xfer_buff, (uint16_t)count);
|
||
|
|
||
|
/* manage multiple Xfer */
|
||
|
puhc->xfer_buff += count;
|
||
|
puhc->xfer_count += count;
|
||
|
|
||
|
if (USB_HCHxLEN((uint16_t)channel_num) & HCHLEN_PCNT) {
|
||
|
/* re-activate the channel when more packets are expected */
|
||
|
usbh_ch_ctl_reg = USB_HCHxCTL((uint16_t)channel_num);
|
||
|
usbh_ch_ctl_reg |= HCHCTL_CEN;
|
||
|
usbh_ch_ctl_reg &= ~HCHCTL_CDIS;
|
||
|
USB_HCHxCTL((uint16_t)channel_num) = usbh_ch_ctl_reg;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GRSTATR_RPCKST_IN_XFER_COMP:
|
||
|
break;
|
||
|
case GRSTATR_RPCKST_DATA_TOGGLE_ERR:
|
||
|
count = (rx_status & GRSTATRP_BCOUNT) >> 4;
|
||
|
|
||
|
while (count > 0) {
|
||
|
rx_status = USB_GRSTATP;
|
||
|
count--;
|
||
|
}
|
||
|
break;
|
||
|
case GRSTATR_RPCKST_CH_HALTED:
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* enable the Rx status queue level interrupt */
|
||
|
USB_GINTEN |= GINTF_RXFNEIF;
|
||
|
|
||
|
return 1U;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief handle the incomplete periodic transfer interrupt
|
||
|
\param[in] pudev: pointer to usb device instance
|
||
|
\param[out] none
|
||
|
\retval operation status
|
||
|
*/
|
||
|
static uint32_t usbh_intf_iso_incomplete_xfer (usb_core_handle_struct *pudev)
|
||
|
{
|
||
|
__IO uint32_t gint_flag = 0U;
|
||
|
|
||
|
gint_flag = USB_HCHxCTL(0U);
|
||
|
USB_HCHxCTL(0U) = 0U;
|
||
|
|
||
|
gint_flag = 0U;
|
||
|
|
||
|
/* clear interrupt */
|
||
|
gint_flag |= GINTF_ISOONCIF;
|
||
|
USB_GINTF = gint_flag;
|
||
|
|
||
|
return 1U;
|
||
|
}
|