USB device stack
Dependents: USBMSD_step1 USBMSD_step1_5 picossd_step1_2cs
Diff: targets/TARGET_Silicon_Labs/src/em_usbhal.c
- Revision:
- 71:53949e6131f6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_Silicon_Labs/src/em_usbhal.c Thu Jul 27 12:14:04 2017 +0100 @@ -0,0 +1,799 @@ +/**************************************************************************//** + * @file em_usbhal.c + * @brief USB protocol stack library, low level USB peripheral access. + * @version 3.20.14 + ****************************************************************************** + * @section License + * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> + ******************************************************************************* + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "em_device.h" +#if defined( USB_PRESENT ) && ( USB_COUNT == 1 ) +#include "em_usb.h" +#if defined( USB_DEVICE ) || defined( USB_HOST ) + +#include "em_usbtypes.h" +#include "em_usbhal.h" +#if defined( USB_DEVICE ) +#include "em_usbd.h" +#endif +#if defined( USB_HOST ) +#include "em_usbh.h" +#endif +#include "em_cmu.h" +#include "em_gpio.h" + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#define EPABORT_BREAK_LOOP_COUNT 15000 /* Approx. 100 ms */ + +/* NOTE: The sequence of error message strings must agree with the */ +/* definition of USB_Status_TypeDef enum. */ +static const char * const errMsg[] = +{ + [ USB_STATUS_OK ] = "No errors", + [ -USB_STATUS_REQ_ERR ] = "Setup request error", + [ -USB_STATUS_EP_BUSY ] = "Endpoint is busy", + [ -USB_STATUS_REQ_UNHANDLED ] = "Setup request not handled", + [ -USB_STATUS_ILLEGAL ] = "Illegal operation attempted", + [ -USB_STATUS_EP_STALLED ] = "Endpoint is stalled", + [ -USB_STATUS_EP_ABORTED ] = "Transfer aborted", + [ -USB_STATUS_EP_ERROR ] = "Transfer error", + [ -USB_STATUS_EP_NAK ] = "Endpoint NAK", + [ -USB_STATUS_DEVICE_UNCONFIGURED ] = "Device is not configured", + [ -USB_STATUS_DEVICE_SUSPENDED ] = "Device is suspended", + [ -USB_STATUS_DEVICE_RESET ] = "Device has been reset", + [ -USB_STATUS_TIMEOUT ] = "Transfer timeout", + [ -USB_STATUS_DEVICE_REMOVED ] = "Device removed", + [ -USB_STATUS_HC_BUSY ] = "Host channel is busy", + [ -USB_STATUS_DEVICE_MALFUNCTION ] = "Device malfunction", + [ -USB_STATUS_PORT_OVERCURRENT ] = "VBUS overcurrent", +}; +/** @endcond */ + + +/***************************************************************************//** + * @brief + * Return an error message string for a given error code. + * + * @param[in] error + * Error code, see \ref USB_Status_TypeDef. + * + * @return + * Error message string pointer. + ******************************************************************************/ +char *USB_GetErrorMsgString( int error ) +{ + if ( error >= 0 ) + return (char*)errMsg[ 0 ]; + + return (char*)errMsg[ -error ]; +} + + +#if defined( USB_USE_PRINTF ) +/***************************************************************************//** + * @brief + * Format and print a text string given an error code, prepends an optional user + * supplied leader string. + * + * @param[in] pre + * Optional leader string to prepend to error message string. + * + * @param[in] error + * Error code, see \ref USB_Status_TypeDef. + ******************************************************************************/ +void USB_PrintErrorMsgString( char *pre, int error ) +{ + if ( pre ) + { + USB_PRINTF( "%s", pre ); + } + + if ( error > USB_STATUS_OK ) + { + USB_PRINTF( "%d", error ); + } + else + { + USB_PRINTF( "%s", USB_GetErrorMsgString( error ) ); + } +} +#endif /* defined( USB_USE_PRINTF ) */ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#if defined( DEBUG_EFM_USER ) +static void PrintI( int i ) +{ +#if !defined ( USER_PUTCHAR ) + (void)i; +#else + if ( i >= 10 ) + { + PrintI( i / 10 ); + } + + DEBUG_USB_API_PUTCHAR( ( i % 10 ) + '0' ); +#endif +} + +void assertEFM( const char *file, int line ) +{ +#if !defined ( USER_PUTCHAR ) + (void)file; +#endif + + DEBUG_USB_API_PUTS( "\nASSERT " ); + DEBUG_USB_API_PUTS( file ); + DEBUG_USB_API_PUTCHAR( ' ' ); + PrintI( line ); + for(;;){} +} +#endif /* defined( DEBUG_EFM_USER ) */ + +#if defined ( USER_PUTCHAR ) +void USB_Puts( const char *p ) +{ + while( *p ) + USB_PUTCHAR( *p++ ); +} +#endif /* defined ( USER_PUTCHAR ) */ + +void USBHAL_CoreReset( void ) +{ + USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK; + USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE); + + /* Core Soft Reset */ + USB->GRSTCTL |= USB_GRSTCTL_CSFTRST; + while ( USB->GRSTCTL & USB_GRSTCTL_CSFTRST ) {} + + USBTIMER_DelayUs( 1 ); + + /* Wait for AHB master IDLE state. */ + while ( !( USB->GRSTCTL & USB_GRSTCTL_AHBIDLE ) ) {} +} + +#ifdef USB_DEVICE +void USBDHAL_Connect( void ) +{ + USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_SFTDISCON ); +} + +USB_Status_TypeDef USBDHAL_CoreInit( uint32_t totalRxFifoSize, + uint32_t totalTxFifoSize ) +{ + uint8_t i, j; + uint16_t start, depth; + USBD_Ep_TypeDef *ep; + +#if !defined( USB_VBUS_SWITCH_NOT_PRESENT ) + CMU_ClockEnable( cmuClock_GPIO, true ); + GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */ + USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Enable PHY pins. */ +#else + USB->ROUTE = USB_ROUTE_PHYPEN; /* Enable PHY pins. */ +#endif + + USBHAL_CoreReset(); /* Reset USB core */ + +#if defined( USB_GUSBCFG_FORCEHSTMODE ) + /* Force Device Mode */ + USB->GUSBCFG = ( USB->GUSBCFG & + ~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEHSTMODE ) ) | + USB_GUSBCFG_FORCEDEVMODE; +#endif + + INT_Enable(); + USBTIMER_DelayMs( 50 ); + INT_Disable(); + + /* Set device speed */ + USB->DCFG = ( USB->DCFG & ~_USB_DCFG_DEVSPD_MASK ) | 3; /* Full speed PHY */ + + /* Stall on non-zero len status OUT packets (ctrl transfers). */ + USB->DCFG |= USB_DCFG_NZSTSOUTHSHK; + + /* Set periodic frame interval to 80% */ + USB->DCFG &= ~_USB_DCFG_PERFRINT_MASK; + + USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) | + USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR; + + /* Ignore frame numbers on ISO transfers. */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_IGNRFRMNUM; + + /* Set Rx FIFO size */ + start = EFM32_MAX( totalRxFifoSize, MIN_EP_FIFO_SIZE_INWORDS ); + USB->GRXFSIZ = ( start << _USB_GRXFSIZ_RXFDEP_SHIFT ) & + _USB_GRXFSIZ_RXFDEP_MASK; + + /* Set Tx EP0 FIFO size */ + depth = EFM32_MAX( dev->ep[ 0 ].fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); + USB->GNPTXFSIZ = ( ( depth << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) & + _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) | + ( ( start << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) & + _USB_GNPTXFSIZ_NPTXFSTADDR_MASK ); + + + /* Set Tx EP FIFO sizes for all IN ep's */ + for ( j = 1; j <= MAX_NUM_TX_FIFOS; j++ ) + { + for ( i = 1; i <= MAX_NUM_IN_EPS; i++ ) + { + ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | i ); + if ( ep ) /* Is EP in use ? */ + { + if ( ep->txFifoNum == j ) /* Is it correct FIFO number ? */ + { + start += depth; + depth = EFM32_MAX( ep->fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); + USB_DIEPTXFS[ ep->txFifoNum - 1 ] = + ( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) | + ( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK ); + } + } + } + } + + if ( totalRxFifoSize + totalTxFifoSize > MAX_DEVICE_FIFO_SIZE_INWORDS ) + return USB_STATUS_ILLEGAL; + + if ( start > MAX_DEVICE_FIFO_SIZE_INWORDS ) + return USB_STATUS_ILLEGAL; + + /* Flush the FIFO's */ + USBHAL_FlushTxFifo( 0x10 ); /* All Tx FIFO's */ + USBHAL_FlushRxFifo(); /* The Rx FIFO */ + + /* Disable all device interrupts */ + USB->DIEPMSK = 0; + USB->DOEPMSK = 0; + USB->DAINTMSK = 0; + USB->DIEPEMPMSK = 0; + + /* Disable all EP's, clear all EP ints. */ + for ( i = 0; i <= MAX_NUM_IN_EPS; i++ ) + { + USB_DINEPS[ i ].CTL = 0; + USB_DINEPS[ i ].TSIZ = 0; + USB_DINEPS[ i ].INT = 0xFFFFFFFF; + } + + for ( i = 0; i <= MAX_NUM_OUT_EPS; i++ ) + { + USB_DOUTEPS[ i ].CTL = 0; + USB_DOUTEPS[ i ].TSIZ = 0; + USB_DOUTEPS[ i ].INT = 0xFFFFFFFF; + } + +#if ( USB_DCTL_SFTDISCON_DEFAULT != 0 ) + USBD_Connect(); +#endif + + /* Enable VREGO sense. */ + USB->CTRL |= USB_CTRL_VREGOSEN; + USB->IFC = USB_IFC_VREGOSH | USB_IFC_VREGOSL; + USB->IEN = USB_IFC_VREGOSH | USB_IFC_VREGOSL; + /* Force a VREGO interrupt. */ + if ( USB->STATUS & USB_STATUS_VREGOS) + USB->IFS = USB_IFS_VREGOSH; + else + USB->IFS = USB_IFS_VREGOSL; + + return USB_STATUS_OK; +} + +USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize, + uint32_t totalTxFifoSize ) +{ + uint8_t i, j; + uint16_t start, depth; + USBD_Ep_TypeDef *ep; + + /* Set Rx FIFO size */ + start = EFM32_MAX( totalRxFifoSize, MIN_EP_FIFO_SIZE_INWORDS ); + USB->GRXFSIZ = ( start << _USB_GRXFSIZ_RXFDEP_SHIFT ) & + _USB_GRXFSIZ_RXFDEP_MASK; + + /* Set Tx EP0 FIFO size */ + depth = EFM32_MAX( dev->ep[ 0 ].fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); + USB->GNPTXFSIZ = ( ( depth << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) & + _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) | + ( ( start << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) & + _USB_GNPTXFSIZ_NPTXFSTADDR_MASK ); + + + /* Set Tx EP FIFO sizes for all IN ep's */ + for ( j = 1; j <= MAX_NUM_TX_FIFOS; j++ ) + { + for ( i = 1; i <= MAX_NUM_IN_EPS; i++ ) + { + ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | i ); + if ( ep ) /* Is EP in use ? */ + { + if ( ep->txFifoNum == j ) /* Is it correct FIFO number ? */ + { + start += depth; + depth = EFM32_MAX( ep->fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); + USB_DIEPTXFS[ ep->txFifoNum - 1 ] = + ( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) | + ( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK ); + } + } + } + } + + if ( totalRxFifoSize + totalTxFifoSize > MAX_DEVICE_FIFO_SIZE_INWORDS ) + return USB_STATUS_ILLEGAL; + + if ( start > MAX_DEVICE_FIFO_SIZE_INWORDS ) + return USB_STATUS_ILLEGAL; + + /* Flush the FIFO's */ + USBHAL_FlushTxFifo( 0x10 ); /* All Tx FIFO's */ + USBHAL_FlushRxFifo(); /* The Rx FIFO */ + + return USB_STATUS_OK; +} + +void USBDHAL_Disconnect( void ) +{ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SFTDISCON; +} + +void USBDHAL_AbortEpIn( USBD_Ep_TypeDef *ep ) +{ + /* Clear epdis & inepnakeff INT's */ + USB_DINEPS[ ep->num ].INT |= USB_DIEP_INT_EPDISBLD | + USB_DIEP_INT_INEPNAKEFF; + + /* Enable epdis & inepnakeff INT's */ + USB->DIEPMSK |= USB_DIEPMSK_EPDISBLDMSK | USB_DIEPMSK_INEPNAKEFFMSK; + USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL & + ~DEPCTL_WO_BITMASK ) | + USB_DIEP_CTL_SNAK; + + /* Wait for inepnakeff INT */ + while ( !( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_INEPNAKEFF ) ) {} + USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_INEPNAKEFF; + USB->DIEPMSK &= ~USB_DIEPMSK_INEPNAKEFFMSK; + + DEBUG_USB_INT_LO_PUTCHAR( '.' ); + + USBDHAL_SetEPDISNAK( ep ); + /* Wait for epdis INT */ + while ( !( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_EPDISBLD ) ) {} + USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_EPDISBLD; + USB->DIEPMSK &= ~USB_DIEPMSK_EPDISBLDMSK; + USBHAL_FlushTxFifo( ep->txFifoNum ); + + /* Clear any interrupts generated by the abort sequence. */ + NVIC_ClearPendingIRQ( USB_IRQn ); + + DEBUG_USB_INT_LO_PUTCHAR( '.' ); +} + +void USBDHAL_AbortEpOut( USBD_Ep_TypeDef *ep ) +{ + int cnt; + + /* Clear epdis INT's */ + USB_DOUTEPS[ ep->num ].INT |= USB_DOEP_INT_EPDISBLD; + + /* Clear Global OUT NAK if already set */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; + USB->GINTMSK |= USB_GINTMSK_GOUTNAKEFFMSK; /* Enable GOUTNAKEFF int */ + + /* Set Global OUT NAK */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SGOUTNAK; + + /* Wait for goutnakeff */ + cnt = EPABORT_BREAK_LOOP_COUNT; + while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) && cnt ) + { + cnt--; + } + + USB->GINTMSK &= ~USB_GINTMSK_GOUTNAKEFFMSK; /* Disable GOUTNAKEFF int */ + USB->DOEPMSK |= USB_DOEPMSK_EPDISBLDMSK; /* Enable EPDIS interrupt */ + + DEBUG_USB_INT_LO_PUTCHAR( ',' ); + + USBDHAL_SetEPDISNAK( ep ); /* Disable ep */ + + /* Wait for epdis INT */ + cnt = EPABORT_BREAK_LOOP_COUNT; + while ( !( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD ) && cnt ) + { + cnt--; + } + + USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_EPDISBLD; + USB->DOEPMSK &= ~USB_DOEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */ + + /* Clear Global OUT NAK */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; + + /* Clear any interrupts generated by the abort sequence. */ + NVIC_ClearPendingIRQ( USB_IRQn ); + + DEBUG_USB_INT_LO_PUTCHAR( ',' ); +} + +void USBDHAL_AbortAllEps( void ) +{ + int i, cnt; + USBD_Ep_TypeDef *ep; + uint16_t im, om, inmask=0, outmask=0; + + /* Clear epdis & inepnakeff INT's */ + for ( i = 1; i <= NUM_EP_USED; i++ ) + { + ep = &dev->ep[i]; + if ( ep->state != D_EP_IDLE ) + { + if ( ep->in ) + { + inmask |= ep->mask; + USB_DINEPS[ ep->num ].INT |= USB_DIEP_INT_EPDISBLD | + USB_DIEP_INT_INEPNAKEFF; + } + else + { + outmask |= ep->mask; + USB_DOUTEPS[ ep->num ].INT |= USB_DOEP_INT_EPDISBLD; + } + } + } + + if ( inmask ) + { + /* Enable epdis & inepnakeff INT's */ + USB->DIEPMSK |= USB_DIEPMSK_EPDISBLDMSK | USB_DIEPMSK_INEPNAKEFFMSK; + + /* Set NAK on all IN ep's */ + im = inmask; + for ( i = 1; i <= NUM_EP_USED; i++ ) + { + ep = &dev->ep[i]; + if ( im & ep->mask ) + { + USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL & + ~DEPCTL_WO_BITMASK ) | + USB_DIEP_CTL_SNAK; + } + } + } + + if ( outmask ) + { + /* Clear Global OUT NAK if already set */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; + + USB->GINTMSK |= USB_GINTMSK_GOUTNAKEFFMSK; /* Enable GOUTNAKEFF int */ + + /* Set Global OUT NAK */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SGOUTNAK; + + /* Wait for goutnakeff */ + cnt = EPABORT_BREAK_LOOP_COUNT; + while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) && cnt ) + { + cnt--; + } + USB->GINTMSK &= ~USB_GINTMSK_GOUTNAKEFFMSK; /* Disable GOUTNAKEFF int */ + USB->DOEPMSK |= USB_DOEPMSK_EPDISBLDMSK; /* Enable EPDIS interrupt */ + } + + if ( inmask ) + { + /* Wait for inepnakeff INT on all IN ep's */ + im = inmask; + cnt = EPABORT_BREAK_LOOP_COUNT; + do + { + for ( i = 1; i <= NUM_EP_USED; i++ ) + { + ep = &dev->ep[i]; + if ( im & ep->mask ) + { + if ( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_INEPNAKEFF ) + { + USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_INEPNAKEFF; + im &= ~ep->mask; + } + } + } + cnt--; + } while ( im && cnt ); + USB->DIEPMSK &= ~USB_DIEPMSK_INEPNAKEFFMSK; + } + + DEBUG_USB_INT_LO_PUTCHAR( '\'' ); + + /* Disable ep's */ + for ( i = 1; i <= NUM_EP_USED; i++ ) + { + ep = &dev->ep[i]; + if ( ep->state != D_EP_IDLE ) + { + USBDHAL_SetEPDISNAK( ep ); + } + } + + /* Wait for epdis INT */ + im = inmask; + om = outmask; + cnt = EPABORT_BREAK_LOOP_COUNT; + do + { + for ( i = 1; i <= NUM_EP_USED; i++ ) + { + ep = &dev->ep[i]; + if ( ep->in && ( im & ep->mask ) ) + { + if ( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_EPDISBLD ) + { + USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_EPDISBLD; + im &= ~ep->mask; + } + } + + if ( !ep->in && ( om & ep->mask ) ) + { + if ( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD ) + { + USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_EPDISBLD; + om &= ~ep->mask; + } + } + } + cnt--; + } while ( ( im || om ) && cnt ); + + if ( inmask ) + { + USB->DIEPMSK &= ~USB_DIEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */ + USBHAL_FlushTxFifo( 0x10 ); /* Flush all Tx FIFO's */ + } + + if ( outmask ) + { + USB->DOEPMSK &= ~USB_DOEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */ + /* Clear Global OUT NAK */ + USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; + } + + DEBUG_USB_INT_LO_PUTCHAR( '\'' ); +} + +void USBDHAL_AbortAllTransfers( USB_Status_TypeDef reason ) +{ + int i; + USBD_Ep_TypeDef *ep; + USB_XferCompleteCb_TypeDef callback; + + if ( reason != USB_STATUS_DEVICE_RESET ) + { + USBDHAL_AbortAllEps(); + } + + for ( i = 1; i <= NUM_EP_USED; i++ ) + { + ep = &(dev->ep[i]); + if ( ep->state != D_EP_IDLE ) + { + ep->state = D_EP_IDLE; + if ( ep->xferCompleteCb ) + { + callback = ep->xferCompleteCb; + ep->xferCompleteCb = NULL; + + if ( ( dev->lastState == USBD_STATE_CONFIGURED ) && + ( dev->state == USBD_STATE_ADDRESSED ) ) + { + USBDHAL_DeactivateEp( ep ); + } + + DEBUG_TRACE_ABORT( reason ); + callback( reason, ep->xferred, ep->remaining ); + } + } + } + + /* Clear any interrupts generated by the abort sequence. */ + NVIC_ClearPendingIRQ( USB_IRQn ); +} +#endif /* defined( USB_DEVICE ) */ + +#if defined( USB_HOST ) +USB_Status_TypeDef USBHHAL_CoreInit( uint32_t rxFifoSize, + uint32_t nptxFifoSize, + uint32_t ptxFifoSize ) +{ + uint8_t i; + + rxFifoSize /= 4; /* Convert from byte count to word count. */ + nptxFifoSize /= 4; + ptxFifoSize /= 4; + + CMU_ClockEnable( cmuClock_GPIO, true ); + GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */ + +#if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE ) + /* Enable VBUS overcurrent flag pin. */ + GPIO_PinModeSet( USB_VBUSOVRCUR_PORT, USB_VBUSOVRCUR_PIN, gpioModeInput, 0 ); +#endif + + USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Enable PHY pins. */ + USBHAL_CoreReset(); /* Reset USB core */ + + /* Force Host Mode */ + USB->GUSBCFG = ( USB->GUSBCFG & + ~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEDEVMODE ) ) | + USB_GUSBCFG_FORCEHSTMODE; + + INT_Enable(); + USBTIMER_DelayMs( 100 ); + INT_Disable(); + + /* Set 48 MHz PHY clock, FS/LS mode */ + USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) | + ( 1 << _USB_HCFG_FSLSPCLKSEL_SHIFT ) | + ( USB_HCFG_FSLSSUPP ); + + USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) | + USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR; + + /* Set Rx FIFO size */ + USB->GRXFSIZ = ( rxFifoSize << _USB_GRXFSIZ_RXFDEP_SHIFT ) & + _USB_GRXFSIZ_RXFDEP_MASK; + + /* Set Tx FIFO sizes */ + USB->GNPTXFSIZ = ( ( nptxFifoSize << + _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) & + _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) | + ( ( rxFifoSize << + _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) & + _USB_GNPTXFSIZ_NPTXFSTADDR_MASK ); + + USB->HPTXFSIZ = ( ( ptxFifoSize << _USB_HPTXFSIZ_PTXFSIZE_SHIFT ) & + _USB_HPTXFSIZ_PTXFSIZE_MASK ) | + ( ( ( rxFifoSize + nptxFifoSize ) + << _USB_HPTXFSIZ_PTXFSTADDR_SHIFT ) & + _USB_HPTXFSIZ_PTXFSTADDR_MASK ); + + /* Flush Tx and Rx FIFO's */ + USBHAL_FlushTxFifo( 0x10 ); + USBHAL_FlushRxFifo(); + + for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ ) + { + USB->HC[ i ].CHAR = USB_HC_CHAR_CHDIS; /* Disable channel */ + USB->HC[ i ].INT = 0xFFFFFFFF; /* Clear pending interrupts */ + } + + /* Enable and halt all channels */ + for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ ) + { + USB->HC[ i ].CHAR |= USB_HC_CHAR_CHDIS | USB_HC_CHAR_CHENA; + do + { + __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); + } + while ( USB->HC[ i ].CHAR & USB_HC_CHAR_CHENA ); + } + + /* Disable all interrupts */ + for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ ) + { + USB->HC[ i ].INTMSK = 0; + } + + USB->HAINTMSK = 0; + + return USB_STATUS_OK; +} + +void USBHHAL_HCHalt( int hcnum, uint32_t hcchar ) +{ + hcchar |= USB_HC_CHAR_CHENA | USB_HC_CHAR_CHDIS; + USB->HC[ hcnum ].CHAR = hcchar; +} + +void USBHHAL_HCInit( int hcnum ) +{ + USBH_Ep_TypeDef *ep; + + ep = hcs[ hcnum ].ep; + USB->HC[ hcnum ].INT = 0xFFFFFFFF; /* Clear all interrupt flags */ + + switch ( ep->type ) /* Enable host channel int. types */ + { + case USB_EPTYPE_CTRL: + case USB_EPTYPE_BULK: + case USB_EPTYPE_INTR: + USB->HC[ hcnum ].INTMSK = USB_HC_INT_CHHLTD; + break; + } + + hcs[ hcnum ].errorCnt = 0; + + USB->HAINTMSK |= 1 << hcnum; /* Enable host channel interrupt */ + + USB->HC[ hcnum ].CHAR = /* Program HCCHAR register */ + ( ep->parentDevice->addr << _USB_HC_CHAR_DEVADDR_SHIFT ) | + ( ( ep->addr & USB_EPNUM_MASK ) << _USB_HC_CHAR_EPNUM_SHIFT ) | + ( ep->type << _USB_HC_CHAR_EPTYPE_SHIFT ) | + ( ep->packetSize << _USB_HC_CHAR_MPS_SHIFT ) | + ( ep->in ? USB_HC_CHAR_EPDIR : 0 ) | + ( ep->parentDevice->speed == + HPRT_L_SPEED >> _USB_HPRT_PRTSPD_SHIFT + ? USB_HC_CHAR_LSPDDEV : 0 ); +} + +void USBHHAL_HCStart( int hcnum ) +{ + USBH_Hc_TypeDef *hc; + uint16_t packets, len; + + hc = &hcs[ hcnum ]; + hc->status = 0; + hc->idle = false; + + if ( hc->remaining > 0 ) + { + packets = ( hc->remaining + hc->ep->packetSize - 1 ) / hc->ep->packetSize; + } + else + { + packets = 1; + } + + if ( hc->ep->in ) + { + len = packets * hc->ep->packetSize; + } + else + { + len = hc->remaining; + } + + /* Initialize the HCTSIZn register */ + hc->hwXferSize = len; + USB->HC[ hcnum ].TSIZ = + ( ( len << _USB_HC_TSIZ_XFERSIZE_SHIFT ) & + _USB_HC_TSIZ_XFERSIZE_MASK ) | + ( ( packets << _USB_HC_TSIZ_PKTCNT_SHIFT ) & + _USB_HC_TSIZ_PKTCNT_MASK ) | + ( ( hc->ep->toggle << _USB_HC_TSIZ_PID_SHIFT ) & + _USB_HC_TSIZ_PID_MASK ); + + USB->HC[ hcnum ].DMAADDR = (uint32_t)hc->buf; + + USBHHAL_HCActivate( hcnum, + USB->HC[ hcnum ].CHAR, + hc->ep->type == USB_EPTYPE_INTR ); +} +#endif /* defined( USB_HOST ) */ + +/** @endcond */ + +#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */ +#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */