/** ************************************************************************** * @file usbh_int.c * @version v2.0.9 * @date 2022-06-28 * @brief usb host interrupt request ************************************************************************** * Copyright notice & Disclaimer * * The software Board Support Package (BSP) that is made available to * download from Artery official website is the copyrighted work of Artery. * Artery authorizes customers to use, copy, and distribute the BSP * software and its related documentation for the purpose of design and * development in conjunction with Artery microcontrollers. Use of the * software is governed by this copyright notice and the following disclaimer. * * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * ************************************************************************** */ #include "usbh_int.h" /** @addtogroup AT32F435_437_middlewares_usbh_drivers * @{ */ /** @defgroup USBH_drivers_interrupt * @brief usb host interrupt * @{ */ /** @defgroup USBH_int_private_functions * @{ */ /** * @brief usb host interrupt handler * @param otgdev: to the structure of otg_core_type * @retval none */ void usbh_irq_handler(otg_core_type *otgdev) { otg_global_type *usbx = otgdev->usb_reg; usbh_core_type *uhost = &otgdev->host; uint32_t intsts = usb_global_get_all_interrupt(usbx); if(usbx->gintsts_bit.curmode == 1) { if(intsts & USB_OTG_HCH_FLAG) { usbh_hch_handler(uhost); usb_global_clear_interrupt(usbx, USB_OTG_HCH_FLAG); } if(intsts & USB_OTG_SOF_FLAG) { usbh_sof_handler(uhost); usb_global_clear_interrupt(usbx, USB_OTG_SOF_FLAG); } if(intsts & USB_OTG_MODEMIS_FLAG) { usb_global_clear_interrupt(usbx, USB_OTG_MODEMIS_FLAG); } if(intsts & USB_OTG_WKUP_FLAG) { usbh_wakeup_handler(uhost); usb_global_clear_interrupt(usbx, USB_OTG_WKUP_FLAG); } if(intsts & USB_OTG_RXFLVL_FLAG) { usbh_rx_qlvl_handler(uhost); usb_global_clear_interrupt(usbx, USB_OTG_RXFLVL_FLAG); } if(intsts & USB_OTG_DISCON_FLAG) { usbh_disconnect_handler(uhost); usb_global_clear_interrupt(usbx, USB_OTG_DISCON_FLAG); } if(intsts & USB_OTG_PRT_FLAG) { usbh_port_handler(uhost); } if(intsts & USB_OTG_INCOMPIP_INCOMPISOOUT_FLAG) { usb_global_clear_interrupt(usbx, USB_OTG_INCOMPIP_INCOMPISOOUT_FLAG); } if(intsts & USB_OTG_INCOMISOIN_FLAG) { usb_global_clear_interrupt(usbx, USB_OTG_INCOMISOIN_FLAG); } if(intsts & USB_OTG_PTXFEMP_FLAG) { usb_global_clear_interrupt(usbx, USB_OTG_PTXFEMP_FLAG); } if(intsts & USB_OTG_ISOOUTDROP_FLAG) { usb_global_clear_interrupt(usbx, USB_OTG_ISOOUTDROP_FLAG); } } } /** * @brief usb host wakeup handler * @param uhost: to the structure of usbh_core_type * @retval none */ void usbh_wakeup_handler(usbh_core_type *uhost) { uhost->global_state = USBH_WAKEUP; } /** * @brief usb host sof handler * @param uhost: to the structure of usbh_core_type * @retval none */ void usbh_sof_handler(usbh_core_type *uhost) { uhost->timer ++; } /** * @brief usb host disconnect handler * @param uhost: to the structure of usbh_core_type * @retval none */ void usbh_disconnect_handler(usbh_core_type *uhost) { otg_global_type *usbx = uhost->usb_reg; uint8_t i_index; usb_host_disable(usbx); uhost->conn_sts = 0; uhost->global_state = USBH_DISCONNECT; for(i_index = 0; i_index < USB_HOST_CHANNEL_NUM; i_index ++) { usbh_free_channel(uhost, i_index); } usbh_fsls_clksel(usbx, USB_HCFG_CLK_48M); } /** * @brief usb host in transfer request handler * @param uhost: to the structure of usbh_core_type * @param chn: channel number * @retval none */ void usbh_hch_in_handler(usbh_core_type *uhost, uint8_t chn) { otg_global_type *usbx = uhost->usb_reg; otg_hchannel_type *usb_chh = USB_CHL(usbx, chn); uint32_t hcint_value = usb_chh->hcint & usb_chh->hcintmsk; if( hcint_value & USB_OTG_HC_ACK_FLAG) { usb_chh->hcint = USB_OTG_HC_ACK_FLAG; } else if(hcint_value & USB_OTG_HC_STALL_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_chh->hcint = USB_OTG_HC_NAK_FLAG | USB_OTG_HC_STALL_FLAG; uhost->hch[chn].state = HCH_STALL; usb_hch_halt(usbx, chn); } else if(hcint_value & USB_OTG_HC_DTGLERR_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); usb_chh->hcint = USB_OTG_HC_DTGLERR_FLAG | USB_OTG_HC_NAK_FLAG; uhost->hch[chn].state = HCH_DATATGLERR; } else if(hcint_value & USB_OTG_HC_FRMOVRRUN_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); usb_chh->hcint = USB_OTG_HC_FRMOVRRUN_FLAG; } else if(hcint_value & USB_OTG_HC_XFERC_FLAG) { uhost->hch[chn].state = HCH_XFRC; usb_chh->hcint = USB_OTG_HC_XFERC_FLAG; if(usb_chh->hcchar_bit.eptype == EPT_BULK_TYPE || usb_chh->hcchar_bit.eptype == EPT_CONTROL_TYPE) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); usb_chh->hcint = USB_OTG_HC_NAK_FLAG; } else if(usb_chh->hcchar_bit.eptype == EPT_INT_TYPE) { usb_chh->hcchar_bit.oddfrm = TRUE; uhost->urb_state[chn] = URB_DONE; } else if(usb_chh->hcchar_bit.eptype == EPT_ISO_TYPE) { uhost->urb_state[chn] = URB_DONE; } uhost->hch[chn].toggle_in ^= 1; } else if(hcint_value & USB_OTG_HC_CHHLTD_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = FALSE; if(uhost->hch[chn].state == HCH_XFRC ) { uhost->urb_state[chn] = URB_DONE; } else if(uhost->hch[chn].state == HCH_STALL) { uhost->urb_state[chn] = URB_STALL; } else if(uhost->hch[chn].state == HCH_XACTERR || uhost->hch[chn].state == HCH_DATATGLERR) { uhost->err_cnt[chn] ++; if(uhost->err_cnt[chn] > 3) { uhost->urb_state[chn] = URB_ERROR; uhost->err_cnt[chn] = 0; } else { uhost->urb_state[chn] = URB_NOTREADY; } usb_chh->hcchar_bit.chdis = FALSE; usb_chh->hcchar_bit.chena = TRUE; } else if(uhost->hch[chn].state == HCH_NAK) { usb_chh->hcchar_bit.chdis = FALSE; usb_chh->hcchar_bit.chena = TRUE; uhost->urb_state[chn] = URB_NOTREADY; } usb_chh->hcint = USB_OTG_HC_CHHLTD_FLAG; } else if(hcint_value & USB_OTG_HC_XACTERR_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; uhost->hch[chn].state = HCH_XACTERR; usb_hch_halt(usbx, chn); uhost->err_cnt[chn] ++; usb_chh->hcint = USB_OTG_HC_XACTERR_FLAG; } else if(hcint_value & USB_OTG_HC_NAK_FLAG) { if(usb_chh->hcchar_bit.eptype == EPT_INT_TYPE) { uhost->err_cnt[chn] = 0; usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); } else if(usb_chh->hcchar_bit.eptype == EPT_BULK_TYPE || usb_chh->hcchar_bit.eptype == EPT_CONTROL_TYPE) { uhost->err_cnt[chn] = 0; usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_chh->hcchar_bit.chdis = FALSE; usb_chh->hcchar_bit.chena = TRUE; } uhost->hch[chn].state = HCH_NAK; usb_chh->hcint = USB_OTG_HC_NAK_FLAG; } else if(hcint_value & USB_OTG_HC_BBLERR_FLAG) { usb_chh->hcint = USB_OTG_HC_BBLERR_FLAG; } } /** * @brief usb host out transfer request handler * @param uhost: to the structure of usbh_core_type * @param chn: channel number * @retval none */ void usbh_hch_out_handler(usbh_core_type *uhost, uint8_t chn) { otg_global_type *usbx = uhost->usb_reg; otg_hchannel_type *usb_chh = USB_CHL(usbx, chn); uint32_t hcint_value = usb_chh->hcint & usb_chh->hcintmsk; if( hcint_value & USB_OTG_HC_ACK_FLAG) { usb_chh->hcint = USB_OTG_HC_ACK_FLAG; } else if( hcint_value & USB_OTG_HC_FRMOVRRUN_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); usb_chh->hcint = USB_OTG_HC_FRMOVRRUN_FLAG; } else if( hcint_value & USB_OTG_HC_XFERC_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); uhost->hch[chn].state = HCH_XFRC; usb_chh->hcint = USB_OTG_HC_XFERC_FLAG; } else if( hcint_value & USB_OTG_HC_STALL_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_chh->hcint = USB_OTG_HC_STALL_FLAG; uhost->hch[chn].state = HCH_STALL; usb_hch_halt(usbx, chn); } else if( hcint_value & USB_OTG_HC_DTGLERR_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; usb_hch_halt(usbx, chn); usb_chh->hcint = USB_OTG_HC_DTGLERR_FLAG | USB_OTG_HC_NAK_FLAG; uhost->hch[chn].state = HCH_DATATGLERR; } else if( hcint_value & USB_OTG_HC_CHHLTD_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = FALSE; if(uhost->hch[chn].state == HCH_XFRC) { uhost->urb_state[chn] = URB_DONE; if(uhost->hch[chn].ept_type == EPT_BULK_TYPE || uhost->hch[chn].ept_type == EPT_INT_TYPE) { uhost->hch[chn].toggle_out ^= 1; } } else if(uhost->hch[chn].state == HCH_NAK) { uhost->urb_state[chn] = URB_NOTREADY; } else if(uhost->hch[chn].state == HCH_STALL) { uhost->hch[chn].urb_sts = URB_STALL; } else if(uhost->hch[chn].state == HCH_XACTERR || uhost->hch[chn].state == HCH_DATATGLERR) { uhost->err_cnt[chn] ++; if(uhost->err_cnt[chn] > 3) { uhost->urb_state[chn] = URB_ERROR; uhost->err_cnt[chn] = 0; } else { uhost->urb_state[chn] = URB_NOTREADY; } usb_chh->hcchar_bit.chdis = FALSE; usb_chh->hcchar_bit.chena = TRUE; } usb_chh->hcint = USB_OTG_HC_CHHLTD_FLAG; } else if( hcint_value & USB_OTG_HC_XACTERR_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; uhost->err_cnt[chn] ++; uhost->hch[chn].state = HCH_XACTERR; usb_hch_halt(usbx, chn); usb_chh->hcint = USB_OTG_HC_XACTERR_FLAG | USB_OTG_HC_NAK_FLAG; } else if( hcint_value & USB_OTG_HC_NAK_FLAG) { usb_chh->hcintmsk_bit.chhltdmsk = TRUE; uhost->err_cnt[chn] = 0; usb_hch_halt(usbx, chn); uhost->hch[chn].state = HCH_NAK; usb_chh->hcint = USB_OTG_HC_NAK_FLAG; } } /** * @brief usb host channel request handler * @param uhost: to the structure of usbh_core_type * @retval none */ void usbh_hch_handler(usbh_core_type *uhost) { otg_global_type *usbx = uhost->usb_reg; otg_host_type *usb_host = OTG_HOST(usbx); uint32_t intsts, i_index; intsts = usb_host->haint & 0xFFFF; for(i_index = 0; i_index < 16; i_index ++) { if(intsts & (1 << i_index)) { if(USB_CHL(usbx, i_index)->hcchar_bit.eptdir) { //hc in usbh_hch_in_handler(uhost, i_index); } else { //hc out usbh_hch_out_handler(uhost, i_index); } } } } /** * @brief usb host rx buffer not empty request handler * @param uhost: to the structure of usbh_core_type * @retval none */ void usbh_rx_qlvl_handler(usbh_core_type *uhost) { uint8_t chn; uint32_t pktsts; uint32_t pktcnt; uint32_t tmp; otg_hchannel_type *ch; otg_global_type *usbx = uhost->usb_reg; usbx->gintmsk_bit.rxflvlmsk = 0; tmp = usbx->grxstsp; chn = tmp & 0xF; pktsts = (tmp >> 17) & 0xF; pktcnt = (tmp >> 4) & 0x7FF; ch = USB_CHL(usbx, chn); switch(pktsts) { case PKTSTS_IN_DATA_PACKET_RECV: if(pktcnt > 0 && (uhost->hch[chn].trans_buf) != 0) { usb_read_packet(usbx, uhost->hch[chn].trans_buf, chn, pktcnt); uhost->hch[chn].trans_buf += pktcnt; uhost->hch[chn].trans_count += pktcnt; if(ch->hctsiz_bit.pktcnt > 0) { ch->hcchar_bit.chdis = FALSE; ch->hcchar_bit.chena = TRUE; uhost->hch[chn].toggle_in ^= 1; } } break; case PKTSTS_IN_TRANSFER_COMPLETE: break; case PKTSTS_DATA_BIT_ERROR: break; case PKTSTS_CHANNEL_STOP: break; default: break; } usbx->gintmsk_bit.rxflvlmsk = 1; } /** * @brief usb host port request handler * @param uhost: to the structure of usbh_core_type * @retval none */ void usbh_port_handler(usbh_core_type *uhost) { otg_global_type *usbx = uhost->usb_reg; otg_host_type *usb_host = OTG_HOST(usbx); uint32_t prt = 0, prt_0; prt = usb_host->hprt; prt_0 = prt; prt_0 &= ~(USB_OTG_HPRT_PRTENA | USB_OTG_HPRT_PRTENCHNG | USB_OTG_HPRT_PRTOVRCACT | USB_OTG_HPRT_PRTCONDET); if(prt & USB_OTG_HPRT_PRTCONDET) { if(prt & USB_OTG_HPRT_PRTCONSTS) { /* connect callback */ uhost->conn_sts = 1; } prt_0 |= USB_OTG_HPRT_PRTCONDET; } if(prt & USB_OTG_HPRT_PRTENCHNG) { prt_0 |= USB_OTG_HPRT_PRTENCHNG; if(prt & USB_OTG_HPRT_PRTENA) { if((prt & USB_OTG_HPRT_PRTSPD) == (USB_PRTSPD_LOW_SPEED << 17)) { usbh_fsls_clksel(usbx, USB_HCFG_CLK_6M); } else { usbh_fsls_clksel(usbx, USB_HCFG_CLK_48M); } /* connect callback */ uhost->port_enable = 1; } else { /* clean up hprt */ uhost->port_enable = 0; } } if(prt & USB_OTG_HPRT_PRTOVRCACT) { prt_0 |= USB_OTG_HPRT_PRTOVRCACT; } usb_host->hprt = prt_0; } /** * @} */ /** * @} */ /** * @} */