663 lines
19 KiB
C
663 lines
19 KiB
C
#include "hsusb_v30x.h"
|
|
#include "ch32fun.h"
|
|
#include <string.h>
|
|
|
|
#define UEP_CTRL_H(n) (((uint16_t*)&USBHSD->UEP0_TX_CTRL)[n*2])
|
|
|
|
struct _USBState HSUSBCTX;
|
|
|
|
// based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM
|
|
|
|
// Mask for the combined USBHSD->INT_FG + USBHSD->INT_ST
|
|
#define CRB_U_IS_NAK (1<<7)
|
|
#define CTOG_MATCH_SYNC (1<<6)
|
|
#define CRB_UIF_SETUP_ACT (1<<5) // CRB_U_SIE_FREE on USBFS
|
|
#define CRB_UIF_FIFO_OV (1<<4)
|
|
#define CRB_UIF_HST_SOF (1<<3)
|
|
#define CRB_UIF_SUSPEND (1<<2)
|
|
#define CRB_UIF_TRANSFER (1<<1)
|
|
#define CRB_UIF_BUS_RST (1<<0)
|
|
#define CSETUP_ACT (1<<15)
|
|
#define CRB_UIS_TOG_OK (1<<14)
|
|
#define CMASK_UIS_TOKEN (3<<12)
|
|
#define CMASK_UIS_ENDP (0xf<<8)
|
|
|
|
#define CUIS_TOKEN_OUT 0x0
|
|
#define CUIS_TOKEN_SOF 0x1
|
|
#define CUIS_TOKEN_IN 0x2
|
|
#define CUIS_TOKEN_SETUP 0x3
|
|
|
|
#if 0
|
|
static inline void DMA7FastCopy( 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 DMA7FastCopyComplete() { while( DMA1_Channel7->CNTR ); }
|
|
|
|
#endif
|
|
|
|
void USBHS_InternalFinishSetup();
|
|
|
|
//void USBHSWakeUp_IRQHandler(void) __attribute((interrupt));
|
|
//void USBHSWakeUp_IRQHandler(void)
|
|
//{
|
|
// printf( "USBHSWakeUp MSTATUS:%08x MTVAL:%08x MCAUSE:%08x MEPC:%08x\n", (int)__get_MSTATUS(), (int)__get_MTVAL(), (int)__get_MCAUSE(), (int)__get_MEPC() );
|
|
//}
|
|
extern uint8_t scratchpad[];
|
|
|
|
void USBHS_IRQHandler(void) __attribute((interrupt));
|
|
void USBHS_IRQHandler(void)
|
|
{
|
|
// Based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM/User/ch32v30x_usbhs_device.c
|
|
// Combined FG + ST flag
|
|
uint16_t intfgst = *(uint16_t*)(&USBHSD->INT_FG);
|
|
int len = 0;
|
|
struct _USBState * ctx = &HSUSBCTX;
|
|
uint8_t * ctrl0buff = CTRL0BUFF;
|
|
|
|
if( intfgst & ( CRB_UIF_SETUP_ACT ) )
|
|
{
|
|
// On the Chapter 22 USB, SETUP Requests are handled here instead of in UIF_TRANSFER, with TOKEN_SETUP.
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
|
|
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK;
|
|
|
|
/* Store All Setup Values */
|
|
int USBHS_SetupReqType = HSUSBCTX.USBHS_SetupReqType = pUSBHS_SetupReqPak->bmRequestType;
|
|
int USBHS_SetupReqCode = HSUSBCTX.USBHS_SetupReqCode = pUSBHS_SetupReqPak->bRequest;
|
|
int USBHS_SetupReqLen = HSUSBCTX.USBHS_SetupReqLen = pUSBHS_SetupReqPak->wLength;
|
|
int USBHS_SetupReqIndex = pUSBHS_SetupReqPak->wIndex;
|
|
int USBHS_IndexValue = HSUSBCTX.USBHS_IndexValue = ( pUSBHS_SetupReqPak->wIndex << 16 ) | pUSBHS_SetupReqPak->wValue;
|
|
len = 0;
|
|
|
|
//printf( "Setup: %d %d %d %d %d\n", USBHS_SetupReqType, USBHS_SetupReqCode, USBHS_SetupReqLen,
|
|
// USBHS_SetupReqIndex, USBHS_IndexValue );
|
|
|
|
if( ( USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
|
{
|
|
#if HUSB_HID_INTERFACES > 0
|
|
if( ( USBHS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS )
|
|
{
|
|
/* Class Request */
|
|
//printf( "REQ: %d [%02x %02x %04x %04x]\n", USBHS_SetupReqCode, pUSBHS_SetupReqPak->bmRequestType, pUSBHS_SetupReqPak->bRequest, pUSBHS_SetupReqPak->wValue, pUSBHS_SetupReqPak->wLength );
|
|
switch( USBHS_SetupReqCode )
|
|
{
|
|
case HID_SET_REPORT:
|
|
#if HUSB_HID_USER_REPORTS
|
|
len = HandleHidUserSetReportSetup( ctx, pUSBHS_SetupReqPak );
|
|
if( len < 0 ) goto sendstall;
|
|
ctx->USBHS_SetupReqLen = len;
|
|
USBHSD->UEP0_TX_LEN = 0;
|
|
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK;
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1;
|
|
goto replycomplete;
|
|
case HID_GET_REPORT:
|
|
len = HandleHidUserGetReportSetup( ctx, pUSBHS_SetupReqPak );
|
|
if( len < 0 ) goto sendstall;
|
|
ctx->USBHS_SetupReqLen = len;
|
|
len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len;
|
|
if( !ctx->pCtrlPayloadPtr )
|
|
{
|
|
len = HandleHidUserReportDataIn( ctx, ctrl0buff, len );
|
|
}
|
|
else
|
|
{
|
|
//DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
|
|
memcpy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
|
|
ctx->pCtrlPayloadPtr += len;
|
|
}
|
|
USBHSD->UEP0_TX_LEN = len;
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
|
|
ctx->USBHS_SetupReqLen -= len;
|
|
goto replycomplete;
|
|
#endif
|
|
break;
|
|
|
|
|
|
case HID_SET_IDLE:
|
|
if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
|
|
HSUSBCTX.USBHS_HidIdle[ USBHS_SetupReqIndex ] = (uint8_t)( USBHS_IndexValue >> 8 );
|
|
break;
|
|
case HID_SET_PROTOCOL:
|
|
if ( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
|
|
HSUSBCTX.USBHS_HidProtocol[USBHS_SetupReqIndex] = (uint8_t)USBHS_IndexValue;
|
|
break;
|
|
|
|
case HID_GET_IDLE:
|
|
if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
|
|
{
|
|
ctrl0buff[0] = HSUSBCTX.USBHS_HidIdle[ USBHS_SetupReqIndex ];
|
|
len = 1;
|
|
}
|
|
break;
|
|
|
|
case HID_GET_PROTOCOL:
|
|
if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
|
|
{
|
|
ctrl0buff[0] = HSUSBCTX.USBHS_HidProtocol[ USBHS_SetupReqIndex ];
|
|
len = 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
goto sendstall;
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* usb standard request processing */
|
|
switch( USBHS_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 == USBHS_IndexValue )
|
|
{
|
|
ctx->pCtrlPayloadPtr = (uint8_t*)e->addr;
|
|
len = e->length;
|
|
break;
|
|
}
|
|
}
|
|
if( e == e_end )
|
|
{
|
|
goto sendstall;
|
|
}
|
|
|
|
|
|
/* Copy Descriptors to Endp0 DMA buffer */
|
|
int totalLen = USBHS_SetupReqLen;
|
|
if( totalLen > len )
|
|
{
|
|
totalLen = len;
|
|
}
|
|
len = ( totalLen >= DEF_USBD_UEP0_SIZE ) ? DEF_USBD_UEP0_SIZE : totalLen;
|
|
//DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); //memcpy( CTRL0BUFF, ctx->pCtrlPayloadPtr, len );
|
|
memcpy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
|
|
ctx->USBHS_SetupReqLen = totalLen - len;
|
|
ctx->pCtrlPayloadPtr += len;
|
|
USBHSD->UEP0_TX_LEN = len;
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
|
|
goto replycomplete;
|
|
}
|
|
|
|
/* Set usb address */
|
|
case USB_SET_ADDRESS:
|
|
ctx->USBHS_DevAddr = (uint16_t)( ctx->USBHS_IndexValue & 0xFF );
|
|
break;
|
|
|
|
/* Get usb configuration now set */
|
|
case USB_GET_CONFIGURATION:
|
|
ctrl0buff[0] = ctx->USBHS_DevConfig;
|
|
if( ctx->USBHS_SetupReqLen > 1 )
|
|
ctx->USBHS_SetupReqLen = 1;
|
|
break;
|
|
|
|
/* Set usb configuration to use */
|
|
case USB_SET_CONFIGURATION:
|
|
ctx->USBHS_DevConfig = (uint8_t)( ctx->USBHS_IndexValue & 0xFF );
|
|
ctx->USBHS_DevEnumStatus = 0x01;
|
|
break;
|
|
|
|
/* Clear or disable one usb feature */
|
|
case USB_CLEAR_FEATURE:
|
|
#if HUSB_SUPPORTS_SLEEP
|
|
if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
|
|
{
|
|
/* clear one device feature */
|
|
if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
|
|
{
|
|
/* clear usb sleep status, device not prepare to sleep */
|
|
ctx->USBHS_DevSleepStatus &= ~0x01;
|
|
}
|
|
else
|
|
{
|
|
goto sendstall;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
|
{
|
|
if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
|
{
|
|
/* Clear End-point Feature */
|
|
int ep = USBHS_SetupReqIndex & 0xf;
|
|
if( ( USBHS_SetupReqIndex & DEF_UEP_IN ) && ep < HUSB_CONFIG_EPS )
|
|
{
|
|
UEP_CTRL_H(ep) = USBHS_UEP_T_TOG_DATA0 | USBHS_UEP_T_RES_NAK;
|
|
}
|
|
else
|
|
{
|
|
goto sendstall;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto sendstall;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto sendstall;
|
|
}
|
|
break;
|
|
|
|
/* set or enable one usb feature */
|
|
case USB_SET_FEATURE:
|
|
if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
|
|
{
|
|
#if HUSB_SUPPORTS_SLEEP
|
|
/* Set Device Feature */
|
|
if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
|
|
{
|
|
/* Set Wake-up flag, device prepare to sleep */
|
|
USBHS_DevSleepStatus |= 0x01;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
goto sendstall;
|
|
}
|
|
}
|
|
else if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
|
{
|
|
/* Set Endpoint Feature */
|
|
if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
|
{
|
|
int ep = USBHS_SetupReqIndex & 0xf;
|
|
if( ( USBHS_SetupReqIndex & DEF_UEP_IN ) && ep < HUSB_CONFIG_EPS )
|
|
UEP_CTRL_H(ep) = ( UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_STALL;
|
|
}
|
|
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( USBHS_SetupReqLen > 1 ) USBHS_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( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
|
|
{
|
|
#if FUSB_SUPPORTS_SLEEP
|
|
ctrl0buff[0] = (ctx->USBHS_DevSleepStatus & 0x01)<<1;
|
|
#else
|
|
ctrl0buff[0] = 0x00;
|
|
#endif
|
|
}
|
|
else if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
|
{
|
|
int ep = USBHS_SetupReqIndex & 0xf;
|
|
if( ( USBHS_SetupReqIndex & DEF_UEP_IN ) && ep < HUSB_CONFIG_EPS )
|
|
ctrl0buff[0] = ( UEP_CTRL_H(ep) & USBHS_UEP_T_RES_MASK ) == USBHS_UEP_T_RES_STALL;
|
|
else
|
|
goto sendstall;
|
|
}
|
|
else
|
|
goto sendstall;
|
|
if( USBHS_SetupReqLen > 2 )
|
|
USBHS_SetupReqLen = 2;
|
|
break;
|
|
|
|
default:
|
|
goto sendstall;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
{
|
|
/* end-point 0 data Tx/Rx */
|
|
if( USBHS_SetupReqType & DEF_UEP_IN )
|
|
{
|
|
len = ( USBHS_SetupReqLen > DEF_USBD_UEP0_SIZE )? DEF_USBD_UEP0_SIZE : USBHS_SetupReqLen;
|
|
USBHS_SetupReqLen -= len;
|
|
USBHSD->UEP0_TX_LEN = len;
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
|
|
}
|
|
else
|
|
{
|
|
if( USBHS_SetupReqLen == 0 )
|
|
{
|
|
USBHSD->UEP0_TX_LEN = 0;
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
|
|
}
|
|
else
|
|
{
|
|
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK;
|
|
}
|
|
}
|
|
}
|
|
|
|
goto replycomplete;
|
|
|
|
// 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.
|
|
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_STALL;
|
|
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_STALL;
|
|
replycomplete:
|
|
;
|
|
}
|
|
if( intfgst & ( CRB_UIF_TRANSFER ) )
|
|
{
|
|
int token = ( intfgst & CMASK_UIS_TOKEN) >> 12;
|
|
int ep = ( intfgst & CMASK_UIS_ENDP ) >> 8;
|
|
switch ( token )
|
|
{
|
|
case CUIS_TOKEN_IN:
|
|
if( ep )
|
|
{
|
|
if( ep < HUSB_CONFIG_EPS )
|
|
{
|
|
UEP_CTRL_H(ep) = ( UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_NAK;
|
|
UEP_CTRL_H(ep) ^= USBHS_UEP_T_TOG_DATA1;
|
|
ctx->USBHS_Endp_Busy[ ep ] = 0;
|
|
// Don't set EP in here. Wait for out.
|
|
// Optimization: Could we set EP here?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* end-point 0 data in interrupt */
|
|
if( ctx->USBHS_SetupReqLen == 0 )
|
|
{
|
|
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK;
|
|
}
|
|
|
|
if( ctx->pCtrlPayloadPtr )
|
|
{
|
|
// Shortcut mechanism, for descriptors or if the user wants it.
|
|
len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen;
|
|
//DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA
|
|
memcpy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
|
|
ctx->USBHS_SetupReqLen -= len;
|
|
if( ctx->USBHS_SetupReqLen > 0 )
|
|
ctx->pCtrlPayloadPtr += len;
|
|
else
|
|
ctx->pCtrlPayloadPtr = 0;
|
|
|
|
USBHSD->UEP0_TX_LEN = len;
|
|
USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1;
|
|
}
|
|
else if ( ( ctx->USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
|
{
|
|
|
|
#if HUSB_HID_USER_REPORTS
|
|
len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen;
|
|
if( len && HSUSBCTX.USBHS_SetupReqCode == HID_GET_REPORT )
|
|
{
|
|
len = HandleHidUserReportDataIn( ctx, ctrl0buff, len );
|
|
USBHSD->UEP0_TX_LEN = len;
|
|
USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1;
|
|
ctx->USBHS_SetupReqLen -= len;
|
|
ctx->pCtrlPayloadPtr += len;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
switch( HSUSBCTX.USBHS_SetupReqCode )
|
|
{
|
|
case USB_GET_DESCRIPTOR:
|
|
break;
|
|
|
|
case USB_SET_ADDRESS:
|
|
USBHSD->DEV_AD = ctx->USBHS_DevAddr;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* data-out stage processing */
|
|
case CUIS_TOKEN_OUT:
|
|
switch( ep )
|
|
{
|
|
/* end-point 0 data out interrupt */
|
|
case DEF_UEP0:
|
|
{
|
|
// XXX WARNINGS:
|
|
// 1. intfgst & CRB_UIS_TOG_OK is not set for non-odd transactions, i.e. first, third, etc, are all fine.
|
|
// 2. HandleHidUserReportOutComplete doesn't seem to work.
|
|
//if( intfgst & CRB_UIS_TOG_OK )
|
|
|
|
#if HUSB_HID_USER_REPORTS
|
|
int len = USBHSD->RX_LEN;
|
|
uint8_t * cptr = ctx->pCtrlPayloadPtr;
|
|
if( !cptr )
|
|
{
|
|
HandleHidUserReportDataOut( ctx, ctrl0buff, len );
|
|
}
|
|
else
|
|
{
|
|
int remain = ctx->USBHS_SetupReqLen - len;
|
|
if( remain < 0 )
|
|
{
|
|
len += remain;
|
|
remain = 0;
|
|
}
|
|
//DMA7FastCopy( cptr, ctrl0buff, len );
|
|
memcpy( cptr, ctrl0buff, len );
|
|
ctx->USBHS_SetupReqLen = remain;
|
|
if( remain > 0 )
|
|
ctx->pCtrlPayloadPtr = cptr + len;
|
|
else
|
|
ctx->pCtrlPayloadPtr = 0;
|
|
}
|
|
#endif
|
|
|
|
if( ctx->USBHS_SetupReqLen == 0 )
|
|
{
|
|
#if HUSB_HID_USER_REPORTS
|
|
//DMA7FastCopyComplete();
|
|
HandleHidUserReportOutComplete( ctx );
|
|
#endif
|
|
}
|
|
|
|
// See above comment
|
|
// //USBHSD->UEP0_RX_CTRL ^= USBFS_UEP_R_TOG;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
// Any other out. (also happens with In)
|
|
HSUSBCTX.USBHS_Endp_Busy[ ep ] = 0x02;
|
|
USBHSD_UEP_RXCTRL( ep ) = ((USBHSD_UEP_RXCTRL( ep )) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
|
|
#if HUSB_BULK_USER_REPORTS
|
|
HandleGotEPComplete( ctx, ep );
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
case CUIS_TOKEN_SETUP: // Not actually used on this chip (It's done as a separate flag)
|
|
case CUIS_TOKEN_SOF: // Sof pack processing
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
if(intfgst & USBHS_UIF_BUS_RST)
|
|
{
|
|
/* usb reset interrupt processing */
|
|
ctx->USBHS_DevConfig = 0;
|
|
ctx->USBHS_DevAddr = 0;
|
|
ctx->USBHS_DevSleepStatus = 0;
|
|
ctx->USBHS_DevEnumStatus = 0;
|
|
|
|
USBHSD->DEV_AD = 0;
|
|
USBHS_InternalFinishSetup( );
|
|
}
|
|
if(intfgst & USBHS_UIF_SUSPEND)
|
|
{
|
|
USBHSD->INT_FG = USBHS_UIF_SUSPEND;
|
|
Delay_Us(10);
|
|
|
|
// USB suspend interrupt processing
|
|
if(USBHSD->MIS_ST & USBHS_UMS_SUSPEND)
|
|
{
|
|
HSUSBCTX.USBHS_DevSleepStatus |= 0x02;
|
|
if(HSUSBCTX.USBHS_DevSleepStatus == 0x03)
|
|
{
|
|
// TODO: Handle usb sleep here
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HSUSBCTX.USBHS_DevSleepStatus &= ~0x02;
|
|
}
|
|
}
|
|
|
|
USBHSD->INT_FG = intfgst;
|
|
}
|
|
|
|
void USBHS_InternalFinishSetup()
|
|
{
|
|
|
|
// To reconfigure your endpoints for TX/RX do it here.
|
|
|
|
#if HUSB_CONFIG_EPS > 5
|
|
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
|
| USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN | USBHS_UEP5_R_EN;
|
|
#elif HUSB_CONFIG_EPS > 4
|
|
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
|
| USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN;
|
|
#elif HUSB_CONFIG_EPS > 3
|
|
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
|
| USBHS_UEP2_T_EN | USBHS_UEP3_T_EN;
|
|
#elif HUSB_CONFIG_EPS > 2
|
|
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
|
| USBHS_UEP2_T_EN;
|
|
#elif HUSB_CONFIG_EPS > 1
|
|
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN;
|
|
#else
|
|
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN;
|
|
#endif
|
|
|
|
// This is really cursed. Somehow it doesn't explode.
|
|
// But, normally the USB wants a separate buffer here.
|
|
|
|
#if HUSB_CONFIG_EPS > 5
|
|
// Feel free to override any of these.
|
|
USBHSD->UEP5_MAX_LEN = 64;
|
|
USBHSD->UEP5_RX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[5];
|
|
USBHSD->UEP5_RX_CTRL = USBHS_UEP_R_RES_ACK | USBHS_UEP_R_TOG_AUTO; // For bulk-out, I think you need to do this.
|
|
#endif
|
|
#if HUSB_CONFIG_EPS > 4
|
|
USBHSD->UEP4_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64?
|
|
USBHSD->UEP4_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[4];
|
|
#endif
|
|
#if HUSB_CONFIG_EPS > 3
|
|
USBHSD->UEP3_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64?
|
|
USBHSD->UEP3_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[3];
|
|
#endif
|
|
#if HUSB_CONFIG_EPS > 2
|
|
USBHSD->UEP2_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64?
|
|
USBHSD->UEP2_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[2];
|
|
#endif
|
|
#if HUSB_CONFIG_EPS > 1
|
|
USBHSD->UEP1_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64?
|
|
USBHSD->UEP1_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[1];
|
|
#endif
|
|
#if HUSB_CONFIG_EPS > 0
|
|
USBHSD->UEP0_MAX_LEN = 64;
|
|
USBHSD->UEP0_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[0];
|
|
#else
|
|
#error You must have at least EP0!
|
|
#endif
|
|
|
|
UEP_CTRL_H(0) = USBHS_UEP_R_RES_ACK | USBHS_UEP_T_RES_NAK;
|
|
int i;
|
|
for( i = 1; i < HUSB_CONFIG_EPS; i++ )
|
|
UEP_CTRL_H(i) = USBFS_UEP_T_RES_NAK;
|
|
|
|
for(uint8_t i=0; i< sizeof(HSUSBCTX.USBHS_Endp_Busy)/sizeof(HSUSBCTX.USBHS_Endp_Busy[0]); i++ )
|
|
{
|
|
HSUSBCTX.USBHS_Endp_Busy[ i ] = 0;
|
|
}
|
|
}
|
|
|
|
int HSUSBSetup()
|
|
{
|
|
// Set USB clock source to USBPHY
|
|
RCC->CFGR2 &= ~(1 << 31);
|
|
RCC->CFGR2 |= RCC_USBCLK48MCLKSource_USBPHY << 31;
|
|
|
|
// Set PLL clock source to HSE
|
|
RCC->CFGR2 &= ~(1 << 27);
|
|
RCC->CFGR2 |= RCC_HSBHSPLLCLKSource_HSE << 27;
|
|
|
|
// Configure PLL for USB
|
|
RCC->CFGR2 &= ~(7 << 24);
|
|
RCC->CFGR2 |= RCC_USBPLL_Div2 << 24;
|
|
|
|
// Configure reference clock
|
|
RCC->CFGR2 &= ~(3 << 28);
|
|
RCC->CFGR2 |= RCC_USBHSPLLCKREFCLK_4M << 28;
|
|
|
|
// Enable USB high-speed peripheral
|
|
RCC->CFGR2 |= (1 << 30);
|
|
RCC->AHBPCENR |= RCC_AHBPeriph_USBHS | RCC_AHBPeriph_DMA1;
|
|
|
|
// Initialize USB module
|
|
USBHSD->CONTROL = USBHS_UC_CLR_ALL | USBHS_UC_RESET_SIE;
|
|
Delay_Us(10);
|
|
USBHSD->CONTROL = 0;
|
|
|
|
// Initialize USB device config
|
|
USBHSD->HOST_CTRL = USBHS_UH_PHY_SUSPENDM;
|
|
USBHSD->CONTROL = USBHS_UC_DMA_EN | USBHS_UC_INT_BUSY | USBHS_UC_SPEED_HIGH;
|
|
USBHSD->INT_EN = USBHS_UIE_SETUP_ACT | USBHS_UIE_TRANSFER | USBHS_UIE_DETECT | USBHS_UIE_SUSPEND;
|
|
|
|
USBHS_InternalFinishSetup();
|
|
|
|
USBHSD->CONTROL |= USBHS_UC_DEV_PU_EN;
|
|
NVIC_EnableIRQ(USBHS_IRQn);
|
|
|
|
// Go on-bus.
|
|
return 0;
|
|
}
|
|
|
|
|