/*! \file usbd_int.c \brief USB device power interrupt routines */ /* Copyright (C) 2017 GigaDevice 2017-02-10, V1.0.0, firmware for GD32F30x */ #include "usbd_int.h" extern uint32_t g_interrupt_mask; extern __IO uint8_t g_suspend_enabled; extern __IO uint8_t g_remote_wakeup_on; extern __IO uint8_t g_ESOF_count; #ifdef LPM_ENABLED __IO uint32_t L1_remote_wakeup = 0U; __IO uint32_t L1_resume = 0U; __IO uint32_t besl = 0U; #endif /* LPM_ENABLED */ static uint8_t usbd_intf_lpst (usbd_core_handle_struct *pudev); static uint8_t usbd_intf_sof (usbd_core_handle_struct *pudev); static uint8_t usbd_intf_esof (usbd_core_handle_struct *pudev); static uint8_t usbd_intf_reset (usbd_core_handle_struct *pudev); static uint8_t usbd_intf_suspend (usbd_core_handle_struct *pudev); static uint8_t usbd_intf_wakeup (usbd_core_handle_struct *pudev); /*! \brief USB interrupt events service routine \param[in] none \param[out] none \retval none */ void usbd_isr (void) { __IO uint16_t interrupt_flag = 0U; __IO uint16_t ctlr = 0U; interrupt_flag = USBD_REG_GET(USBD_INTF); if (g_interrupt_mask & INTF_STIF & interrupt_flag) { /* the endpoint successful transfer interrupt service */ usbd_intf_lpst(&usb_device_dev); } if (g_interrupt_mask & INTF_WKUPIF & interrupt_flag) { /* clear wakeup interrupt flag in INTF */ USBD_REG_SET(USBD_INTF, (uint16_t)CLR_WKUPIF); /* USB wakeup interrupt handle */ usbd_intf_wakeup(&usb_device_dev); #ifdef LPM_ENABLED /* clear L1 remote wakeup flag */ L1_remote_wakeup = 0; #endif /* LPM_ENABLED */ } if (g_interrupt_mask & INTF_SPSIF & interrupt_flag) { if(!(USBD_REG_GET(USBD_CTL) & CTL_RSREQ)) { /* process library core layer suspend routine*/ usbd_intf_suspend(&usb_device_dev); /* clear of suspend interrupt flag bit must be done after setting of CTLR_SETSPS */ USBD_REG_SET(USBD_INTF, (uint16_t)CLR_SPSIF); } } if (g_interrupt_mask & INTF_SOFIF & interrupt_flag) { /* clear SOF interrupt flag in INTF */ USBD_REG_SET(USBD_INTF, (uint16_t)CLR_SOFIF); /* USB SOF interrupt handle */ usbd_intf_sof(&usb_device_dev); } if (g_interrupt_mask & INTF_ESOFIF & interrupt_flag) { /* clear ESOF interrupt flag in INTF */ USBD_REG_SET(USBD_INTF, (uint16_t)CLR_ESOFIF); /* USB ESOF interrupt handle */ usbd_intf_esof(&usb_device_dev); } if (g_interrupt_mask & INTF_RSTIF & interrupt_flag) { /* clear reset interrupt flag in INTF */ USBD_REG_SET(USBD_INTF, (uint16_t)CLR_RSTIF); /* USB reset interrupt handle */ usbd_intf_reset(&usb_device_dev); } #ifdef LPM_ENABLED if (g_interrupt_mask & INTF_L1REQ & interrupt_flag) { /* clear L1 ST bit in LPM INTF */ USBD_REG_SET(USBD_INTF, CLR_L1REQ); /* read BESL field from subendpoint0 register which coressponds to HIRD parameter in LPM spec */ besl = (USBD_REG_GET(USBD_LPMCS) & LPMCS_BLSTAT) >> 4; /* read BREMOTEWAKE bit from subendpoint0 register which corresponding to bRemoteWake bit in LPM request */ L1_remote_wakeup = (USBD_REG_GET(USBD_LPMCS) & LPMCS_REMWK) >> 8; /* process USB device core layer suspend routine */ /* enter USB model in suspend and system in low power mode (DEEP_SLEEP mode) */ usbd_intf_suspend(&usb_device_dev); } #endif /* LPM_ENABLED */ } /*! \brief handle USB low priority successful transfer event \param[in] pudev: pointer to USB device instance \param[out] none \retval USB device operation status */ static uint8_t usbd_intf_lpst (usbd_core_handle_struct *pudev) { uint8_t ep_num = 0U; __IO uint16_t int_status = 0U; __IO uint16_t ep_value = 0U; usb_ep_struct *ep = NULL; /* wait till interrupts are not pending */ while (0U != ((int_status = USBD_REG_GET(USBD_INTF)) & (uint16_t)INTF_STIF)) { /* get endpoint number and the value of control and state register */ ep_num = (uint8_t)(int_status & INTF_EPNUM); ep_value = USBD_REG_GET(USBD_EPxCS(ep_num)); if (0U == (int_status & INTF_DIR)) { /* handle the in direction transaction */ ep = &(pudev->in_ep[ep_num]); if (0U != (ep_value & EPxCS_TX_ST)) { /* clear successful transmit interrupt flag */ USBD_ENDP_TX_STAT_CLEAR(ep_num); /* just handle single buffer situation */ ep->trs_count = (pbuf_reg + ep_num)->tx_count & EPTCNT_CNT; /* maybe mutiple packets */ ep->trs_buf += ep->trs_count; usbd_in_transaction(pudev, ep_num); } } else { /* handle the out direction transaction */ uint16_t count = 0U; ep = &(pudev->out_ep[ep_num]); if (0U != (ep_value & EPxCS_RX_ST)) { /* clear successful receive interrupt flag */ USBD_ENDP_RX_STAT_CLEAR(ep_num); count = (pbuf_reg + ep_num)->rx_count & (uint16_t)EPRCNT_CNT; if (0U != count) { if (0U != (ep_value & EPxCS_SETUP)) { /* handle setup packet */ usbd_ep_data_read(&(pudev->setup_packet[0]), pbuf_reg->rx_addr, count); /* enter setup status */ usbd_setup_transaction(pudev); return USBD_OK; } else { usbd_ep_data_read(ep->trs_buf, (pbuf_reg + ep_num)->rx_addr, count); } } /* maybe mutiple packets */ ep->trs_count += count; ep->trs_buf += count; ep->trs_len -= count; if ((0U == ep->trs_len) || (count < ep->maxpacket)) { /* enter data OUT status */ usbd_out_transaction(pudev, ep_num); ep->trs_count = 0U; } else { usbd_ep_rx(pudev, ep_num, ep->trs_buf, (uint16_t)ep->trs_len); } } } } return USBD_OK; } /*! \brief handle USB SOF event \param[in] pudev: pointer to USB device instance \param[out] none \retval USB device operation status */ static uint8_t usbd_intf_sof (usbd_core_handle_struct *pudev) { /* if necessary, user can add code here */ if (NULL != usbd_int_fops) { usbd_int_fops->SOF(pudev); } return USBD_OK; } /*! \brief handle USB expect SOF event \param[in] pudev: pointer to USB device instance \param[out] none \retval USB device operation status */ static uint8_t usbd_intf_esof (usbd_core_handle_struct *pudev) { /* control resume time by ESOFs */ if (g_ESOF_count > 0U) { g_ESOF_count--; if (0U == g_ESOF_count) { if (1U == g_remote_wakeup_on) { USBD_REG_SET(USBD_CTL, USBD_REG_GET(USBD_CTL) & ~CTL_RSREQ); g_remote_wakeup_on = 0U; } else { USBD_REG_SET(USBD_CTL, USBD_REG_GET(USBD_CTL) | CTL_RSREQ); g_ESOF_count = 3U; g_remote_wakeup_on = 1U; } } } return USBD_OK; } /*! \brief handle USB reset event \param[in] pudev: pointer to USB device instance \param[out] none \retval USB device operation status */ static uint8_t usbd_intf_reset (usbd_core_handle_struct *pudev) { // uint8_t i; g_free_buf_addr = ENDP_BUF_ADDR; /* configure endpoint 0 buffer */ pbuf_reg->tx_addr = (uint16_t)g_free_buf_addr; g_free_buf_addr += USBD_EP0_MAX_SIZE; pbuf_reg->rx_addr = (uint16_t)g_free_buf_addr; g_free_buf_addr += USBD_EP0_MAX_SIZE; /* configure endpoint 0 Rx count */ pbuf_reg->rx_count = ((USBD_EP0_MAX_SIZE << 5) - 1) | 0x8000; pudev->in_ep[EP0].maxpacket = USBD_EP0_MAX_SIZE; pudev->out_ep[EP0].maxpacket = USBD_EP0_MAX_SIZE; USBD_REG_SET(USBD_EPxCS(EP0), EP_CONTROL | EPRX_VALID | EPTX_NAK); /* set device address as default address 0 */ USBD_REG_SET(USBD_DADDR, DADDR_USBEN); pudev->status = USBD_DEFAULT; return USBD_OK; } /*! \brief handle USB suspend event \param[in] pudev: pointer to USB device instance \param[out] none \retval USB device operation status */ static uint8_t usbd_intf_suspend (usbd_core_handle_struct *pudev) { /* store the device current status */ pudev->prev_status = pudev->status; /* set device in suspended state */ pudev->status = USBD_SUSPENDED; /* enter USB in suspend and mcu system in low power mode */ if (g_suspend_enabled) { usbd_suspend(); } else { /* if not possible then resume after xx ms */ g_ESOF_count = 3U; } return USBD_OK; } /*! \brief handle USB wakeup event \param[in] pudev: pointer to USB device instance \param[out] none \retval USB device operation status */ static uint8_t usbd_intf_wakeup (usbd_core_handle_struct *pudev) { /* restore the old status */ pudev->status = pudev->prev_status; #ifdef LPM_ENABLED if ((0U == g_remote_wakeup_on) && (0U == L1_resume)) { resume_mcu(); } else if (1U == g_remote_wakeup_on) { /* no operation */ } else { L1_resume = 0U; } #else if (0U == g_remote_wakeup_on) { resume_mcu(); } #endif /* LPM_ENABLED */ return USBD_OK; }