Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-mX-USB-TEST1 USBMSD_SD_HID_HelloWorld HidTest MIDI_usb_bridge ... more
Legacy Warning
This is an mbed 2 library. To learn more about mbed OS 5, visit the docs.
Pull requests against this repository are no longer supported. Please raise against mbed OS 5 as documented above.
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 ) */


