#include "fsusb.h" #include "ch32fun.h" #include #ifdef __DMA_SAFE // CH573 needs all buffers that will touch DMA be allocated at specific memory location // Since we have EP buffers inside the context struct we put it all there. // If you want to use your own external buffers, be sure to use this macro before their definitions. __DMA_SAFE #endif struct _USBState USBFSCTX; volatile uint8_t usb_debug = 0; #if !defined CH5xx && FUSB_USE_DMA7_COPYs static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len ) { while( DMA1_Channel7->CNTR ); DMA1_Channel7->CFGR = 0; DMA1_Channel7->MADDR = (uintptr_t)src; DMA1_Channel7->PADDR = (uintptr_t)dest; DMA1_Channel7->CNTR = (len+3)/4; DMA1_Channel7->CFGR = DMA_M2M_Enable | DMA_DIR_PeripheralDST | DMA_Priority_Low | DMA_MemoryDataSize_Word | DMA_PeripheralDataSize_Word | DMA_MemoryInc_Enable | DMA_PeripheralInc_Enable | DMA_Mode_Normal | DMA_CFGR1_EN; #if !( FUSB_CURSED_TURBO_DMA == 1 ) // Somehow, it seems to work (unsafely) without this. // Really, though, it's probably fine. while( DMA1_Channel7->CNTR ); #endif } static inline void copyBufferComplete() { while( DMA1_Channel7->CNTR ); } #else #define copyBuffer memcpy #define copyBufferComplete() ((void)0) #endif #if defined (CH5xx) #define USBFS_IRQHandler USB_IRQHandler #endif #if FUSB_USE_HPE // There is an issue with some registers apparently getting lost with HPE, just do it the slow way. void USBFS_IRQHandler() __attribute__((section(".text.vector_handler"))) __attribute((interrupt)); // void USBHD_IRQHandler() __attribute__((section(".text.vector_handler"))) __attribute((naked)); #else #if defined(FUSB_FROM_RAM) && (FUSB_FROM_RAM) void USBFS_IRQHandler() __USBFS_FUN_ATTRIBUTE __attribute((interrupt)); #else void USBFS_IRQHandler() __attribute__((section(".text.vector_handler"))) __attribute((interrupt)); #endif #endif void USBFS_InternalFinishSetup(); void USBFS_IRQHandler() { #if FUSB_IO_PROFILE funDigitalWrite( DEBUG_PIN, 1 ); #endif // Combined FG + ST flag. uint16_t intfgst = *(uint16_t*)(&USBFS->INT_FG); int len = 0; struct _USBState * ctx = &USBFSCTX; uint8_t * ctrl0buff = CTRL0BUFF; // TODO: Check if needs to be do-while to re-check. if( intfgst & CRB_UIF_TRANSFER ) { int token = ( intfgst & CMASK_UIS_TOKEN) >> 12; int ep = ( intfgst & CMASK_UIS_ENDP ) >> 8; if( usb_debug ) printf("[USB] TRANSFER, token = %02x, ep = %d, bmRequestType = %02x, bRequest = %02x\n", token, ep, pUSBFS_SetupReqPak->bmRequestType, pUSBFS_SetupReqPak->bRequest); switch ( token ) { case CUIS_TOKEN_IN: if( ep ) { if( ep < FUSB_CONFIG_EPS ) { #if FUSB_USER_HANDLERS len = HandleInRequest( ctx, ep, ctx->ENDPOINTS[ ep ], 0 ); #endif UEP_CTRL_TX(ep) ^= USBFS_UEP_T_TOG; if( len ) { if( len < 0 ) len = 0; UEP_CTRL_LEN( ep ) = len; UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK; } else { UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK; } ctx->USBFS_Endp_Busy[ ep ] = 0; } } else { /* end-point 0 data in interrupt */ if( ctx->USBFS_SetupReqLen == 0 ) { #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG; // R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES ) | UEP_R_RES_ACK; #else UEP_CTRL_RX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG; #endif } ctx->USBFS_errata_dont_send_endpoint_in_window = 0; if( ctx->pCtrlPayloadPtr ) { // Shortcut mechanism, for descriptors or if the user wants it. len = ctx->USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBFS_SetupReqLen; copyBuffer( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA ctx->USBFS_SetupReqLen -= len; if( ctx->USBFS_SetupReqLen > 0 ) ctx->pCtrlPayloadPtr += len; else ctx->pCtrlPayloadPtr = 0; UEP_CTRL_LEN(0) = len; UEP_CTRL_TX(0) ^= USBFS_UEP_T_TOG; } else if ( ( ctx->USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD ) { len = ctx->USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBFS_SetupReqLen; #if FUSB_HID_USER_REPORTS if( len && USBFSCTX.USBFS_SetupReqCode == HID_GET_REPORT ) { len = HandleHidUserReportDataIn( ctx, ctrl0buff, len ); UEP_CTRL_LEN(0) = len; UEP_CTRL_TX(0) ^= USBFS_UEP_T_TOG; ctx->USBFS_SetupReqLen -= len; ctx->pCtrlPayloadPtr += len; } #endif #if FUSB_USER_HANDLERS if( len && USBFSCTX.USBFS_SetupReqCode != HID_GET_REPORT ) { len = HandleInRequest( ctx, 0, ctrl0buff, len ); UEP_CTRL_LEN(0) = len; UEP_CTRL_TX(0) ^= USBFS_UEP_T_TOG; ctx->USBFS_SetupReqLen -= len; ctx->pCtrlPayloadPtr += len; } #endif } else { switch( USBFSCTX.USBFS_SetupReqCode ) { case USB_GET_DESCRIPTOR: break; case USB_SET_ADDRESS: USBFS->DEV_ADDR = ( USBFS->DEV_ADDR & USBFS_UDA_GP_BIT ) | ctx->USBFS_DevAddr; break; default: break; } } } break; /* data-out stage processing */ case CUIS_TOKEN_OUT: len = USBFS->RX_LEN; switch( ep ) { /* end-point 0 data out interrupt */ case DEF_UEP0: if( intfgst & CRB_UIS_TOG_OK ) { #if FUSB_HID_USER_REPORTS if( ctx->USBFS_SetupReqCode == HID_SET_REPORT ) { uint8_t * cptr = ctx->pCtrlPayloadPtr; if( !cptr ) { HandleHidUserReportDataOut( ctx, ctrl0buff, len ); } else { int remain = ctx->USBFS_SetupReqLen - len; if( remain < 0 ) { len += remain; remain = 0; } copyBuffer( cptr, ctrl0buff, len ); ctx->USBFS_SetupReqLen = remain; if( remain > 0 ) ctx->pCtrlPayloadPtr = cptr + len; else ctx->pCtrlPayloadPtr = 0; } } #endif #if FUSB_USER_HANDLERS if ( ctx->USBFS_SetupReqCode != HID_SET_REPORT ) { HandleDataOut( ctx, ep, ctrl0buff, len ); } #endif if( ctx->USBFS_SetupReqLen == 0 ) { #if FUSB_HID_USER_REPORTS copyBufferComplete(); if( ctx->USBFS_SetupReqCode == HID_SET_REPORT ) HandleHidUserReportOutComplete( ctx ); #endif // Only set this flag for OUT requests (e.g. SET_LINE_CODING). // For IN requests (e.g. GET_DESCRIPTOR), don't set it. if ( ( ctx->USBFS_SetupReqType & USB_REQ_TYP_IN ) == 0 ) { ctx->USBFS_errata_dont_send_endpoint_in_window = 1; } UEP_CTRL_LEN(0) = 0; UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_ACK; } else { #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(0) ^= USBFS_UEP_R_TOG; #else UEP_CTRL_RX(0) ^= USBFS_UEP_R_TOG; #endif } } break; default: #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(ep) ^= USBFS_UEP_R_TOG; #else UEP_CTRL_RX(ep) ^= USBFS_UEP_R_TOG; #endif #if FUSB_USER_HANDLERS HandleDataOut( ctx, ep, ctx->ENDPOINTS[ep], len ); #endif break; } break; /* Setup stage processing */ case CUIS_TOKEN_SETUP: #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) #if !defined (CH32V10x) if (!(USBFS->INT_ST & 0x80)) goto replycomplete; #endif UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | USBFS_UEP_T_TOG | USBFS_UEP_R_RES_NAK | USBFS_UEP_R_TOG | CHECK_USBFS_UEP_AUTO_TOG; #else UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG; UEP_CTRL_RX(0) = USBFS_UEP_R_RES_NAK | CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_TOG; #endif /* Store All Setup Values */ int USBFS_SetupReqType = USBFSCTX.USBFS_SetupReqType = pUSBFS_SetupReqPak->bmRequestType; int USBFS_SetupReqCode = USBFSCTX.USBFS_SetupReqCode = pUSBFS_SetupReqPak->bRequest; int USBFS_SetupReqLen = USBFSCTX.USBFS_SetupReqLen = pUSBFS_SetupReqPak->wLength; int USBFS_SetupReqIndex = pUSBFS_SetupReqPak->wIndex; int USBFS_IndexValue = USBFSCTX.USBFS_IndexValue = ( pUSBFS_SetupReqPak->wIndex << 16 ) | pUSBFS_SetupReqPak->wValue; if( usb_debug ) printf( "[USB] SETUP: %02x %02x %02d %02x %04x\n", USBFS_SetupReqType, USBFS_SetupReqCode, USBFS_SetupReqLen, USBFS_SetupReqIndex, USBFS_IndexValue ); len = 0; if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD ) { #if FUSB_HID_INTERFACES > 0 || FUSB_USER_HANDLERS if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS ) { /* Class Request */ switch( USBFS_SetupReqCode ) { #if FUSB_HID_INTERFACES > 0 case HID_SET_REPORT: #if FUSB_HID_USER_REPORTS len = HandleHidUserSetReportSetup( ctx, pUSBFS_SetupReqPak ); if( len < 0 ) goto sendstall; ctx->USBFS_SetupReqLen = len; UEP_CTRL_LEN(0) = 0; // Previously would have been a CTRL_RX = ACK && TOG, but not here on the 203. #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG; // R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK ; #else UEP_CTRL_RX(0) = CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG; UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG; #endif goto replycomplete; case HID_GET_REPORT: len = HandleHidUserGetReportSetup( ctx, pUSBFS_SetupReqPak ); if( len < 0 ) goto sendstall; ctx->USBFS_SetupReqLen = len; len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len; if( !ctx->pCtrlPayloadPtr ) { len = HandleHidUserReportDataIn( ctx, ctrl0buff, len ); } else { copyBuffer( ctrl0buff, ctx->pCtrlPayloadPtr, len ); ctx->pCtrlPayloadPtr += len; } UEP_CTRL_LEN(0) = len; UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG; ctx->USBFS_SetupReqLen -= len; goto replycomplete; #endif break; case HID_SET_IDLE: if( USBFS_SetupReqIndex < FUSB_HID_INTERFACES ) USBFSCTX.USBFS_HidIdle[ USBFS_SetupReqIndex ] = (uint8_t)( USBFS_IndexValue >> 8 ); break; case HID_SET_PROTOCOL: if ( USBFS_SetupReqIndex < FUSB_HID_INTERFACES ) USBFSCTX.USBFS_HidProtocol[USBFS_SetupReqIndex] = (uint8_t)USBFS_IndexValue; break; case HID_GET_IDLE: if( USBFS_SetupReqIndex < FUSB_HID_INTERFACES ) { ctrl0buff[0] = USBFSCTX.USBFS_HidIdle[ USBFS_SetupReqIndex ]; len = 1; } break; case HID_GET_PROTOCOL: if( USBFS_SetupReqIndex < FUSB_HID_INTERFACES ) { ctrl0buff[0] = USBFSCTX.USBFS_HidProtocol[ USBFS_SetupReqIndex ]; len = 1; } break; #endif default: #if FUSB_USER_HANDLERS len = HandleSetupCustom( ctx, USBFS_SetupReqCode ); if( len ) { if( len < 0 ) { len = 0; ctx->USBFS_SetupReqLen = 0; } else { ctx->USBFS_SetupReqLen = len; copyBuffer( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // printf("%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", ctrl0buff[0], ctrl0buff[1], ctrl0buff[2], ctrl0buff[3], ctrl0buff[4], ctrl0buff[5], ctrl0buff[6]); ctx->pCtrlPayloadPtr += len; } if( ctx->USBFS_SetupReqType & DEF_UEP_IN || ctx->USBFS_SetupReqLen == 0) { len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len; UEP_CTRL_LEN(0) = len; UEP_CTRL_TX(0) = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_ACK; ctx->USBFS_SetupReqLen -= len; } #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) else UEP_CTRL_TX(0)= USBFS_UEP_R_TOG|USBFS_UEP_R_RES_ACK; #else else UEP_CTRL_RX(0)= USBFS_UEP_R_TOG|USBFS_UEP_R_RES_ACK; #endif // UEP_CTRL_LEN(0) = len; // UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG; // ctx->USBFS_SetupReqLen -= len; // goto epzero_rxtx; goto replycomplete; } else #endif { goto sendstall; } break; } } #else ; #endif } else { /* usb standard request processing */ switch( USBFS_SetupReqCode ) { /* get device/configuration/string/report/... descriptors */ case USB_GET_DESCRIPTOR: { const struct descriptor_list_struct * e = descriptor_list; const struct descriptor_list_struct * e_end = e + DESCRIPTOR_LIST_ENTRIES; for( ; e != e_end; e++ ) { if( e->lIndexValue == (uint32_t)USBFS_IndexValue ) { ctx->pCtrlPayloadPtr = (uint8_t*)e->addr; len = e->length; break; } } if( e == e_end ) goto sendstall; if( len > USBFS_SetupReqLen ) len = USBFS_SetupReqLen; ctx->USBFS_SetupReqLen = len; break; } /* Set usb address */ case USB_SET_ADDRESS: ctx->USBFS_DevAddr = (uint8_t)( ctx->USBFS_IndexValue & 0xFF ); // NOTE: Do not actually set addres here! If we do, we won't get the PID_IN associated with this SETUP. break; /* Get usb configuration now set */ case USB_GET_CONFIGURATION: ctrl0buff[0] = ctx->USBFS_DevConfig; if( ctx->USBFS_SetupReqLen > 1 ) ctx->USBFS_SetupReqLen = 1; break; /* Set usb configuration to use */ case USB_SET_CONFIGURATION: ctx->USBFS_DevConfig = (uint8_t)( ctx->USBFS_IndexValue & 0xFF ); ctx->USBFS_DevEnumStatus = 0x01; break; /* Clear or disable one usb feature */ case USB_CLEAR_FEATURE: #if FUSB_SUPPORTS_SLEEP if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE ) { /* clear one device feature */ if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP ) { /* clear usb sleep status, device not prepare to sleep */ ctx->USBFS_DevSleepStatus &= ~0x01; } else { goto sendstall; } } else #endif if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP ) { if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT ) { /* Clear End-point Feature */ if( ep < FUSB_CONFIG_EPS ) { // UEP_CTRL_TX(ep) = USBFS_UEP_T_RES_STALL | CHECK_USBFS_UEP_T_AUTO_TOG; if( USBFS_SetupReqIndex & DEF_UEP_IN && ctx->endpoint_mode[ep] == -1 ) UEP_CTRL_TX(ep) = USBFS_UEP_T_RES_NAK; #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) UEP_CTRL_TX(ep) = USBFS_UEP_R_RES_ACK; #else else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) UEP_CTRL_RX(ep) = USBFS_UEP_R_RES_ACK; #endif else goto sendstall; } else { goto sendstall; } } else { goto sendstall; } } else { goto sendstall; } break; /* set or enable one usb feature */ case USB_SET_FEATURE: if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE ) { #if FUSB_SUPPORTS_SLEEP /* Set Device Feature */ if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP ) { /* Set Wake-up flag, device prepare to sleep */ USBFS_DevSleepStatus |= 0x01; } else #endif { goto sendstall; } } else if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP ) { /* Set Endpoint Feature */ if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT ) { if( ep < FUSB_CONFIG_EPS ) { if( (USBFS_SetupReqIndex & DEF_UEP_IN) && ctx->endpoint_mode[ep] == -1 )UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_STALL; #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) else if( (USBFS_SetupReqIndex & DEF_UEP_OUT) && ctx->endpoint_mode[ep] == 1 )UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_STALL; #else else if( (USBFS_SetupReqIndex & DEF_UEP_OUT) && ctx->endpoint_mode[ep] == 1 )UEP_CTRL_RX(ep) = ( UEP_CTRL_RX(ep) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_STALL; #endif else goto sendstall; } } else goto sendstall; } else goto sendstall; break; /* This request allows the host to select another setting for the specified interface */ case USB_GET_INTERFACE: ctrl0buff[0] = 0x00; if( USBFS_SetupReqLen > 1 ) USBFS_SetupReqLen = 1; break; case USB_SET_INTERFACE: break; /* host get status of specified device/interface/end-points */ case USB_GET_STATUS: ctrl0buff[0] = 0x00; ctrl0buff[1] = 0x00; if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE ) { #if FUSB_SUPPORTS_SLEEP ctrl0buff[0] = (ctx->USBFS_DevSleepStatus & 0x01)<<1; #else ctrl0buff[0] = 0x00; #endif } else if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP ) { if( ep < FUSB_CONFIG_EPS ) { if( USBFS_SetupReqIndex & DEF_UEP_IN && ctx->endpoint_mode[ep] == -1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_T_RES_MASK ) == USBFS_UEP_T_RES_STALL; #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_R_RES_MASK ) == USBFS_UEP_R_RES_STALL; #else else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_R_RES_MASK ) == USBFS_UEP_R_RES_STALL; #endif else goto sendstall; } else goto sendstall; } else goto sendstall; if( USBFS_SetupReqLen > 2 ) USBFS_SetupReqLen = 2; break; default: goto sendstall; break; } } // epzero_rxtx: { /* end-point 0 data Tx/Rx */ if( USBFS_SetupReqType & DEF_UEP_IN ) { len = ( USBFS_SetupReqLen > DEF_USBD_UEP0_SIZE )? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen; USBFS_SetupReqLen -= len; UEP_CTRL_LEN(0) = len; UEP_CTRL_TX(0) = USBFS_UEP_T_RES_ACK; // R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; } else { if( USBFS_SetupReqLen == 0 ) { UEP_CTRL_LEN(0) = 0; UEP_CTRL_TX(0) = USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG; // R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; } else { #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG; // R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK ; #else UEP_CTRL_RX(0) = CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG; #endif } } } break; // This might look a little weird, for error handling but it saves a nontrivial amount of storage, and simplifies // control flow to hard-abort here. sendstall: // if one request not support, return stall. Stall means permanent error. #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL | USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL; #else UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL; UEP_CTRL_RX(0) = USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL; #endif replycomplete: break; /* Sof pack processing */ //case CUIS_TOKEN_SOF: // break; default : break; } // printf("clear transfer int flag\n"); USBFS->INT_FG = CRB_UIF_TRANSFER; } else if( intfgst & CRB_UIF_BUS_RST ) { if( usb_debug ) printf("[USB] RESET\n"); /* usb reset interrupt processing */ ctx->USBFS_DevConfig = 0; ctx->USBFS_DevAddr = 0; ctx->USBFS_DevSleepStatus = 0; ctx->USBFS_DevEnumStatus = 0; USBFS->DEV_ADDR = 0; USBFS_InternalFinishSetup(); USBFS->INT_FG = CRB_UIF_BUS_RST; } else if( intfgst & CRB_UIF_SUSPEND ) { if( usb_debug ) printf("[USB] SUSPEND\n"); USBFS->INT_FG = USBFS_UMS_SUSPEND; Delay_Us(10); /* usb suspend interrupt processing */ if( USBFS->MIS_ST & USBFS_UMS_SUSPEND ) { ctx->USBFS_DevSleepStatus |= 0x02; if( ctx->USBFS_DevSleepStatus == 0x03 ) { /* Handling usb sleep here */ //TODO: MCU_Sleep_Wakeup_Operate( ); } } else { ctx->USBFS_DevSleepStatus &= ~0x02; } } else { /* other interrupts */ USBFS->INT_FG = intfgst & 0xff; if( usb_debug) printf("[USB] intfgst = %04x\n",intfgst); } #if FUSB_IO_PROFILE funDigitalWrite( DEBUG_PIN, 0 ); #endif #if FUSB_USE_HPE // asm volatile( "mret" ); #endif } void USBFS_InternalFinishSetup() { #if FUSB_EP1_MODE USBFSCTX.endpoint_mode[1] = FUSB_EP1_MODE; #if FUSB_EP1_MODE > 0 USBFS->UEP4_1_MOD = USBFS_UEP1_TX_EN; #else USBFS->UEP4_1_MOD = USBFS_UEP1_RX_EN; #endif #endif #if FUSB_EP4_MODE USBFSCTX.endpoint_mode[4] = FUSB_EP4_MODE; #if FUSB_EP4_MODE > 0 USBFS->UEP4_1_MOD |= USBFS_UEP4_TX_EN; #else USBFS->UEP4_1_MOD |= USBFS_UEP4_RX_EN; #endif #endif #if FUSB_EP2_MODE USBFSCTX.endpoint_mode[2] = FUSB_EP2_MODE; #if FUSB_EP2_MODE > 0 USBFS->UEP2_3_MOD = USBFS_UEP2_TX_EN; #else USBFS->UEP2_3_MOD = USBFS_UEP2_RX_EN; #endif #endif #if FUSB_EP3_MODE USBFSCTX.endpoint_mode[3] = FUSB_EP3_MODE; #if FUSB_EP3_MODE > 0 USBFS->UEP2_3_MOD |= USBFS_UEP3_TX_EN; #else USBFS->UEP2_3_MOD |= USBFS_UEP3_RX_EN; #endif #endif #if FUSB_EP5_MODE USBFSCTX.endpoint_mode[5] = FUSB_EP5_MODE; #if FUSB_EP5_MODE > 0 #if defined (CH5xx) || defined (CH32X03x) USBFS->UEP567_MOD = USBFS_UEP5_TX_EN; #else USBFS->UEP5_6_MOD = USBFS_UEP5_TX_EN; #endif #else #if defined (CH5xx) || defined (CH32X03x) USBFS->UEP567_MOD = USBFS_UEP5_RX_EN; #else USBFS->UEP5_6_MOD = USBFS_UEP5_RX_EN; #endif #endif #endif #if FUSB_EP6_MODE USBFSCTX.endpoint_mode[6] = FUSB_EP6_MODE; #if FUSB_EP6_MODE > 0 #if defined (CH5xx) || defined (CH32X03x) USBFS->UEP567_MOD = USBFS_UEP6_TX_EN; #else USBFS->UEP5_6_MOD |= USBFS_UEP6_TX_EN; #endif #else #if defined (CH5xx) || defined (CH32X03x) USBFS->UEP567_MOD |= USBFS_UEP6_RX_EN; #else USBFS->UEP5_6_MOD |= USBFS_UEP6_RX_EN; #endif #endif #endif #if FUSB_EP7_MODE USBFSCTX.endpoint_mode[7] = FUSB_EP7_MODE; #if FUSB_EP7_MODE > 0 #if defined (CH5xx) || defined (CH32X03x) USBFS->UEP567_MOD |= USBFS_UEP7_TX_EN; #else USBFS->UEP7_MOD = USBFS_UEP1_TX_EN; #endif #else #if defined (CH5xx) || defined (CH32X03x) USBFS->UEP567_MOD |= USBFS_UEP7_RX_EN; #else USBFS->UEP7_MOD = USBFS_UEP1_RX_EN; #endif #endif #endif #if !defined (FUSB_CONFIG_EPS) || !FUSB_CONFIG_EPS #error You must have at least EP0! #endif for( int i = 0; i < FUSB_CONFIG_EPS; i++ ) { UEP_DMA(i) = (uintptr_t)USBFSCTX.ENDPOINTS[i]; } #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | USBFS_UEP_R_RES_ACK | CHECK_USBFS_UEP_T_AUTO_TOG; #else UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | CHECK_USBFS_UEP_T_AUTO_TOG; UEP_CTRL_RX(0) = USBFS_UEP_R_RES_ACK | CHECK_USBFS_UEP_R_AUTO_TOG; #endif for( int i = 1; i < FUSB_CONFIG_EPS; i++ ) { if( USBFSCTX.endpoint_mode[i] > 0 ) { UEP_CTRL_TX(i) = USBFS_UEP_T_RES_NAK; } else if( USBFSCTX.endpoint_mode[i] < 0 ) { #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) UEP_CTRL_TX(i) = USBFS_UEP_R_RES_ACK; #else UEP_CTRL_RX(i) = USBFS_UEP_R_RES_ACK; #endif } USBFSCTX.USBFS_Endp_Busy[i] = 0; } } int USBFSSetup() { #if defined (CH32V10x) #if (FUNCONF_SYSTEM_CORE_CLOCK != 72000000) && (FUNCONF_SYSTEM_CORE_CLOCK != 48000000) #error CH32V103 needs 72MHz or 48MHz main clock for USB to work #endif #if FUNCONF_SYSTEM_CORE_CLOCK == 48000000 RCC->CFGR0 |= RCC_USBPRE; // Disable 1.5 divider for USB clock #endif #if defined (FUSB_VDD_5V) && FUSB_VDD_5V EXTEN->EXTEN_CTR |= EXTEN_USB_5V_SEL; #endif EXTEN->EXTEN_CTR |= EXTEN_USBFS_IO_EN; #endif #if defined (CH32V20x) || defined (CH32V30x) || defined(CH32L103) #ifdef CH32V30x_D8C RCC->CFGR2 = RCC_USBHSSRC | RCC_USBHSPLL | 1<< RCC_USBHSCLK_OFFSET | RCC_USBHSPLLSRC | 1 << RCC_USBHSDIV_OFFSET; RCC->AHBPCENR |= RCC_USBHSEN; #else // USBPRE[1:0] = 10: Divided by 3 (when PLLCLK=144MHz); // Must be done before enabling clock to USBFS tree. #if FUNCONF_SYSTEM_CORE_CLOCK == 144000000 RCC->CFGR0 = (RCC->CFGR0 & ~(3<<22)) | (2<<22); #elif FUNCONF_SYSTEM_CORE_CLOCK == 96000000 RCC->CFGR0 = (RCC->CFGR0 & ~(3<<22)) | (1<<22); #elif FUNCONF_SYSTEM_CORE_CLOCK == 48000000 RCC->CFGR0 = (RCC->CFGR0 & ~(3<<22)); #elif FUNCONF_SYSTEM_CORE_CLOCK == 240000000 #error CH32V20x/30x is unstable at 240MHz #else #error CH32V20x/30x need 144/96/48MHz main clock for USB to work #endif #endif #endif #if defined (CH32X03x) RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC; // #ifdef FUSB_VDD_5V // AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK | USB_PHY_V33)) | UDP_PUE_10K | USB_IOEN; // #else AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK )) | USB_PHY_V33 | UDP_PUE_1K5 | USB_IOEN; // #endif // Enable PC16/17 Alternate Function (USB) // According to EVT, GPIO16 = GPIO_Mode_IN_FLOATING, GPIO17 = GPIO_Mode_IPU GPIOC->CFGXR = ( GPIOC->CFGXR & ~( (0xf<<(4*0)) | (0xf<<(4*1)) ) ) | (((GPIO_CFGLR_IN_FLOAT)<<(4*0)) | (((GPIO_CFGLR_IN_PUPD)<<(4*1)))); // MSBs are CNF, LSBs are MODE GPIOC->BSXR = 1<<1; // PC17 on. #endif #if defined (CH5xx) #if defined (CH570_CH572) R16_PIN_ALTERNATE |= RB_PIN_USB_EN | RB_UDP_PU_EN; #elif defined (CH584_CH585) R16_PIN_CONFIG |= RB_PIN_USB_EN | RB_UDP_PU_EN; #else R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU; #endif #else #if defined (CH32V10x) || defined (CH32V30x) || defined(CH32L103) RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA; #endif #if defined (CH32V20x) RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB; #endif RCC->AHBPCENR |= RCC_USBFS | RCC_AHBPeriph_DMA1; #endif // Force module to reset. USBFS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; USBFS->BASE_CTRL = 0x00; Delay_Us(10); // Enter device mode. USBFS->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_TRANSFER | USBFS_UIE_BUS_RST; USBFS->DEV_ADDR = 0x00; USBFS->BASE_CTRL = USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN | USBFS_UC_DEV_PU_EN; USBFS->INT_FG = 0xff; USBFS_InternalFinishSetup(); USBFS->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN; NVIC_EnableIRQ( USB_IRQn ); #if defined (CH32V30x) USBFS->OTG_CR = 0; //Note says only valid on 305, 307. #endif // #ifndef CH32X03x // // Actually go on-bus. // USBFS->BASE_CTRL |= USBFS_UC_DEV_PU_EN; // #endif #if FUSB_IO_PROFILE funPinMode( DEBUG_PIN, GPIO_CFGLR_OUT_50Mhz_PP ); #endif // Go on-bus. return 0; } #ifdef CH5xx void USBFSReset() { NVIC_DisableIRQ( USB_IRQn ); #if defined (CH570_CH572) R16_PIN_ALTERNATE &= ~(RB_PIN_USB_EN | RB_UDP_PU_EN); #elif defined (CH584_CH585) R16_PIN_CONFIG &= ~(RB_PIN_USB_EN | RB_UDP_PU_EN); #else R16_PIN_ANALOG_IE &= ~(RB_PIN_USB_IE | RB_PIN_USB_DP_PU); #endif USBFS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; USBFS->BASE_CTRL = 0x00; Delay_Us(10); } #endif static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp ) { if( USBFSCTX.USBFS_Endp_Busy[ endp ] ) return 0; return USBFSCTX.ENDPOINTS[ endp ]; } static inline int USBFS_SendEndpoint( int endp, int len ) { if( USBFSCTX.USBFS_errata_dont_send_endpoint_in_window || USBFSCTX.USBFS_Endp_Busy[ endp ] ) return -1; // This prevents sending while ep0 is receiving if( USBFSCTX.USBFS_SetupReqLen > 0 ) return -2; #if defined (CH5xx) || defined (CH32X03x) // Check RB_UIS_SETUP_ACT if( (USBFS->INT_ST & 0x80) ) return -3; #endif NVIC_DisableIRQ( USB_IRQn ); UEP_CTRL_LEN( endp ) = len; UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK; USBFSCTX.USBFS_Endp_Busy[ endp ] = 1; NVIC_EnableIRQ( USB_IRQn ); return 0; } int USBFS_SendEndpointNEW( int endp, uint8_t* data, int len, int copy) { if( USBFSCTX.USBFS_errata_dont_send_endpoint_in_window || USBFSCTX.USBFS_Endp_Busy[ endp ] ) return -1; // This prevents sending while ep0 is receiving if( USBFSCTX.USBFS_SetupReqLen > 0 ) return USBFSCTX.USBFS_SetupReqLen; #if defined (CH5xx) || defined (CH32X03x) // Check RB_UIS_SETUP_ACT if( (USBFS->INT_ST & 0x80) ) return -3; #endif if ( len ) { if( copy ) { UEP_DMA( endp ) = (uintptr_t)USBFSCTX.ENDPOINTS[endp]; copyBuffer( USBFSCTX.ENDPOINTS[endp], data, len ); copyBufferComplete(); } else UEP_DMA( endp ) = (uintptr_t)data; } // NVIC_DisableIRQ( USB_IRQn ); UEP_CTRL_LEN( endp ) = len; UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK; USBFSCTX.USBFS_Endp_Busy[ endp ] = 1; // NVIC_EnableIRQ( USB_IRQn ); return 0; } static inline int USBFS_SendACK( int endp, int tx ) { if( tx ) UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK; #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) else UEP_CTRL_TX(endp) = ( UEP_CTRL_TX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_ACK; #else else UEP_CTRL_RX(endp) = ( UEP_CTRL_RX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_ACK; #endif return 0; } static inline int USBFS_SendNAK( int endp, int tx ) { if( tx ) UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK; #if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x) else UEP_CTRL_TX(endp) = ( UEP_CTRL_TX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_NAK; #else else UEP_CTRL_RX(endp) = ( UEP_CTRL_RX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_NAK; #endif return 0; } #if defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF int HandleInRequest( struct _USBState *ctx, int endp, uint8_t *data, int len ) { return 0; } void HandleDataOut( struct _USBState *ctx, int endp, uint8_t *data, int len ) { if ( endp == 0 ) { ctx->USBFS_SetupReqLen = 0; // To ACK } } int HandleSetupCustom( struct _USBState *ctx, int setup_code ) { int ret = -1; if ( ctx->USBFS_SetupReqType & USB_REQ_TYP_CLASS ) { switch ( setup_code ) { case CDC_SET_LINE_CODING: case CDC_SET_LINE_CTLSTE: case CDC_SEND_BREAK: ret = ( ctx->USBFS_SetupReqLen ) ? ctx->USBFS_SetupReqLen : -1; break; case CDC_GET_LINE_CODING: ret = ctx->USBFS_SetupReqLen; break; default: ret = 0; break; } } else { ret = 0; // Go to STALL } return ret; } #endif // FUNCONF_USE_USBPRINTF