4180 final project
Fork of USBDevice by
Revision 59:2af474687369, committed 2015-08-13
- Comitter:
- mbed_official
- Date:
- Thu Aug 13 15:46:06 2015 +0100
- Parent:
- 58:f3cad7e6984e
- Commit message:
- Synchronized with git revision 376d6a73e345b728a788041adb166b08cd8d2b95
Full URL: https://github.com/mbedmicro/mbed/commit/376d6a73e345b728a788041adb166b08cd8d2b95/
Silicon Labs - Add support for USBDevice
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/inc/em_usb.h Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,999 @@
+/***************************************************************************//**
+ * @file em_usb.h
+ * @brief USB protocol stack library API for EFM32.
+ * @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.
+ *
+ ******************************************************************************/
+
+#ifndef __EM_USB_H
+#define __EM_USB_H
+
+#include "em_device.h"
+#include "em_assert.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "usbconfig.h"
+#if defined( USB_DEVICE ) || defined( USB_HOST )
+
+#include <string.h>
+#include <stddef.h>
+#include "em_common.h"
+#include "em_int.h"
+
+#if defined( USB_USE_PRINTF )
+#include <stdio.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __CC_ARM
+#pragma anon_unions
+#endif
+
+/***************************************************************************//**
+ * @addtogroup USB
+ * @brief USB HOST and DEVICE protocol stacks.
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup USB_COMMON
+ * @brief Common parts for both HOST and DEVICE USB stacks, see @ref usb_device
+ * and @ref usb_host pages for device and host library documentation.
+ * @{
+ ******************************************************************************/
+
+#define SILABS_USB_VID 0x10C4 /**< Silicon Labs Vendor ID, supplied by USB-IF. */
+
+/* SETUP request, direction of data stage */
+#define USB_SETUP_DIR_OUT 0 /**< Setup request data stage OUT direction value. */
+#define USB_SETUP_DIR_IN 1 /**< Setup request data stage IN direction value. */
+#define USB_SETUP_DIR_MASK 0x80 /**< Setup request data stage direction mask. */
+#define USB_SETUP_DIR_D2H 0x80 /**< Setup request data stage IN direction mask. */
+#define USB_SETUP_DIR_H2D 0x00 /**< Setup request data stage OUT direction mask. */
+
+/* SETUP request type */
+#define USB_SETUP_TYPE_STANDARD 0 /**< Standard setup request value. */
+#define USB_SETUP_TYPE_CLASS 1 /**< Class setup request value. */
+#define USB_SETUP_TYPE_VENDOR 2 /**< Vendor setup request value. */
+#define USB_SETUP_TYPE_STANDARD_MASK 0x00 /**< Standard setup request mask. */
+#define USB_SETUP_TYPE_CLASS_MASK 0x20 /**< Class setup request mask. */
+#define USB_SETUP_TYPE_VENDOR_MASK 0x40 /**< Vendor setup request mask. */
+
+/* SETUP request recipient */
+#define USB_SETUP_RECIPIENT_DEVICE 0 /**< Setup request device recipient value. */
+#define USB_SETUP_RECIPIENT_INTERFACE 1 /**< Setup request interface recipient value. */
+#define USB_SETUP_RECIPIENT_ENDPOINT 2 /**< Setup request endpoint recipient value. */
+#define USB_SETUP_RECIPIENT_OTHER 3 /**< Setup request other recipient value. */
+
+/* SETUP standard request codes for Full Speed devices */
+#define GET_STATUS 0 /**< Standard setup request GET_STATUS. */
+#define CLEAR_FEATURE 1 /**< Standard setup request CLEAR_FEATURE. */
+#define SET_FEATURE 3 /**< Standard setup request SET_FEATURE. */
+#define SET_ADDRESS 5 /**< Standard setup request SET_ADDRESS. */
+#define GET_DESCRIPTOR 6 /**< Standard setup request GET_DESCRIPTOR. */
+#define SET_DESCRIPTOR 7 /**< Standard setup request SET_DESCRIPTOR. */
+#define GET_CONFIGURATION 8 /**< Standard setup request GET_CONFIGURATION. */
+#define SET_CONFIGURATION 9 /**< Standard setup request SET_CONFIGURATION. */
+#define GET_INTERFACE 10 /**< Standard setup request GET_INTERFACE. */
+#define SET_INTERFACE 11 /**< Standard setup request SET_INTERFACE. */
+#define SYNCH_FRAME 12 /**< Standard setup request SYNCH_FRAME. */
+
+/* SETUP class request codes */
+#define USB_HID_GET_REPORT 0x01 /**< HID class setup request GET_REPORT. */
+#define USB_HID_GET_IDLE 0x02 /**< HID class setup request GET_IDLE. */
+#define USB_HID_SET_REPORT 0x09 /**< HID class setup request SET_REPORT. */
+#define USB_HID_SET_IDLE 0x0A /**< HID class setup request SET_IDLE. */
+#define USB_HID_SET_PROTOCOL 0x0B /**< HID class setup request SET_PROTOCOL. */
+#define USB_CDC_SETLINECODING 0x20 /**< CDC class setup request SET_LINE_CODING. */
+#define USB_CDC_GETLINECODING 0x21 /**< CDC class setup request GET_LINE_CODING. */
+#define USB_CDC_SETCTRLLINESTATE 0x22 /**< CDC class setup request SET_CONTROL_LINE_STATE. */
+#define USB_MSD_BOTRESET 0xFF /**< MSD class setup request Bulk only transfer reset. */
+#define USB_MSD_GETMAXLUN 0xFE /**< MSD class setup request Get Max LUN. */
+#define USB_AUDIO_GET_CUR 0x81 /**< Audio class setup request GET_CUR. */
+#define USB_AUDIO_SET_CUR 0x01 /**< Audio class setup request SET_CUR. */
+#define USB_AUDIO_GET_CUR 0x81 /**< Audio class setup request GET_CUR. */
+#define USB_AUDIO_SET_MIN 0x02 /**< Audio class setup request SET_MIN. */
+#define USB_AUDIO_GET_MIN 0x82 /**< Audio class setup request GET_MIN. */
+#define USB_AUDIO_SET_MAX 0x03 /**< Audio class setup request SET_MAX. */
+#define USB_AUDIO_GET_MAX 0x83 /**< Audio class setup request GET_MAX. */
+#define USB_AUDIO_SET_RES 0x04 /**< Audio class setup request SET_RES. */
+#define USB_AUDIO_GET_RES 0x84 /**< Audio class setup request GET_RES. */
+#define USB_AUDIO_SET_MEM 0x05 /**< Audio class setup request SET_MEM. */
+#define USB_AUDIO_GET_MEM 0x85 /**< Audio class setup request GET_MEM. */
+#define USB_AUDIO_GET_STAT 0xFF /**< Audio class setup request GET_STAT. */
+
+/* SETUP command GET/SET_DESCRIPTOR decriptor types */
+#define USB_DEVICE_DESCRIPTOR 1 /**< DEVICE descriptor value. */
+#define USB_CONFIG_DESCRIPTOR 2 /**< CONFIGURATION descriptor value. */
+#define USB_STRING_DESCRIPTOR 3 /**< STRING descriptor value. */
+#define USB_MAX_STRING_DESCRIPTOR_CHARS 126 /**< Maximum STRING descriptor bString length. */
+#define USB_INTERFACE_DESCRIPTOR 4 /**< INTERFACE descriptor value. */
+#define USB_ENDPOINT_DESCRIPTOR 5 /**< ENDPOINT descriptor value. */
+#define USB_DEVICE_QUALIFIER_DESCRIPTOR 6 /**< DEVICE_QUALIFIER descriptor value. */
+#define USB_OTHER_SPEED_CONFIG_DESCRIPTOR 7 /**< OTHER_SPEED_CONFIGURATION descriptor value. */
+#define USB_INTERFACE_POWER_DESCRIPTOR 8 /**< INTERFACE_POWER descriptor value. */
+#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR 11 /**< INTERFACE_ASSOCIATION descriptor value. */
+#define USB_HID_DESCRIPTOR 0x21 /**< HID descriptor value. */
+#define USB_SMARTCARD_DESCRIPTOR 0x21 /**< Smartcard usb-ccid-specific Descriptor Type. */
+#define USB_HID_REPORT_DESCRIPTOR 0x22 /**< HID REPORT descriptor value. */
+#define USB_CS_INTERFACE_DESCRIPTOR 0x24 /**< Audio Class-specific interface Descriptor Type. */
+#define USB_CS_ENDPOINT_DESCRIPTOR 0x25 /**< Audio Class-specific endpoint Descriptor Type. */
+#define USB_HUB_DESCRIPTOR 0x29 /**< HUB descriptor value. */
+#define USB_CA_HEADER_DESCRIPTOR 1 /**< Audio Class-Specific AC Interface Header descriptor.*/
+#define USB_CA_INPUT_TERMINAL_DESCRIPTOR 2 /**< Audio Class-Specific AC Interface Input Terminal desc. */
+#define USB_CA_OUTPUT_TERMINAL_DESCRIPTOR 3 /**< Audio Class-Specific AC Interface Output Terminal desc.*/
+#define USB_CA_MIXER_UNIT_DESCRIPTOR 4 /**< Audio Class-Specific AC Interface Mixer descriptor.*/
+#define USB_CA_SELECTOR_UNIT_DESCRIPTOR 5 /**< Audio Class-Specific AC Interface Selector desc. */
+#define USB_CA_FEATURE_UNIT_DESCRIPTOR 6 /**< Audio Class-Specific AC Interface Feature desc. */
+#define USB_CA_PROCESSING_UNIT_DESCRIPTOR 7 /**< Audio Class-Specific AC Interface Processing desc.*/
+#define USB_CA_EXTENSION_UNIT_DESCRIPTOR 8 /**< Audio Class-Specific AC Interface Extension desc. */
+#define USB_CA_EP_GENERAL_DESCRIPTOR 1 /**< Audio Class-Specific general descriptor subtype code.*/
+#define USB_CA_AS_GENERAL_DESCRIPTOR 1 /**< Audio Class-Specific AS Interface General descriptor.*/
+#define USB_CA_FORMAT_TYPE_DESCRIPTOR 2 /**< Audio Class-Specific AS Interface Format Type desc. */
+
+#define USB_DEVICE_DESCSIZE 18 /**< Device descriptor size. */
+#define USB_CONFIG_DESCSIZE 9 /**< Configuration descriptor size. */
+#define USB_INTERFACE_DESCSIZE 9 /**< Interface descriptor size. */
+#define USB_ENDPOINT_DESCSIZE 7 /**< Endpoint descriptor size. */
+#define USB_DEVICE_QUALIFIER_DESCSIZE 10 /**< Device qualifier descriptor size. */
+#define USB_OTHER_SPEED_CONFIG_DESCSIZE 9 /**< Device other speed configuration descriptor size. */
+#define USB_INTERFACE_ASSOCIATION_DESCSIZE 8 /**< INTERFACE_ASSOCIATION descriptor size. */
+#define USB_HID_DESCSIZE 9 /**< HID descriptor size. */
+#define USB_SMARTCARD_DESCSIZE 54 /**< CCID descriptor size. */
+#define USB_CDC_HEADER_FND_DESCSIZE 5 /**< CDC Header functional descriptor size. */
+#define USB_CDC_CALLMNG_FND_DESCSIZE 5 /**< CDC Call Management functional descriptor size. */
+#define USB_CDC_ACM_FND_DESCSIZE 4 /**< CDC Abstract Control Management functional descriptor size.*/
+#define USB_CA_INPUT_TERMINAL_DESCSIZE 12 /**< Audio Input Terminal descriptor size. */
+#define USB_CA_OUTPUT_TERMINAL_DESCSIZE 9 /**< Audio Output Terminal descriptor size. */
+#define USB_CA_EP_GENERAL_DESCSIZE 7 /**< Audio Class-Specific general descriptor subtype size.*/
+#define USB_CA_AS_GENERAL_DESCSIZE 7 /**< Audio Class-Specific AS Interface General desc size.*/
+#define USB_CA_STD_AS_ENDPOINT_DESCSZIE 9 /**< Audio-class standard audio stream descriptor size.*/
+
+/* Misc. USB definitions */
+#define USB_LS_CTRL_EP_MAXSIZE 8 /**< The max size of low speed control endpoints. */
+#define USB_LS_INTR_EP_MAXSIZE 8 /**< The max size of low speed interrupt endpoints. */
+#define USB_FS_CTRL_EP_MAXSIZE 64 /**< The max size of full speed control endpoints. */
+#define USB_FS_INTR_EP_MAXSIZE 64 /**< The max size of full speed interrupt endpoints. */
+#define USB_FS_BULK_EP_MAXSIZE 64 /**< The max size of full speed bulk endpoints. */
+#define USB_FS_ISOC_EP_MAXSIZE 1023 /**< The max size of full speed isochronous endpoints. */
+#define USB_EPTYPE_CTRL 0 /**< Endpoint type control. */
+#define USB_EPTYPE_ISOC 1 /**< Endpoint type isochron. */
+#define USB_EPTYPE_BULK 2 /**< Endpoint type bulk. */
+#define USB_EPTYPE_INTR 3 /**< Endpoint type interrupt. */
+#define USB_EPSYNC_NO (0 << 2) /**< Endpoint synchronization type, none. */
+#define USB_EPSYNC_ASYNC (1 << 2) /**< Endpoint synchronization type, asynchronous. */
+#define USB_EPSYNC_ADAPTIVE (2 << 2) /**< Endpoint synchronization type, adaptive. */
+#define USB_EPSYNC_SYNC (3 << 2) /**< Endpoint synchronization type, synchronous. */
+#define USB_EP_DIR_IN 0x80 /**< Endpoint direction mask. */
+#define USB_SETUP_PKT_SIZE 8 /**< Setup request packet size. */
+#define USB_EPNUM_MASK 0x0F /**< Endpoint number mask. */
+#define USB_LANGID_ENUS 0x0409 /**< English-United States language id. */
+#define USB_MAX_DEVICE_ADDRESS 127 /**< Maximum allowable device address. */
+
+#define CONFIG_DESC_BM_REMOTEWAKEUP 0x20 /**< Configuration descriptor attribute macro. */
+#define CONFIG_DESC_BM_SELFPOWERED 0x40 /**< Configuration descriptor attribute macro. */
+#define CONFIG_DESC_BM_RESERVED_D7 0x80 /**< Configuration descriptor attribute macro. */
+#define CONFIG_DESC_BM_TRANSFERTYPE 0x03 /**< Configuration descriptor transfer type bitmask. */
+#define CONFIG_DESC_MAXPOWER_mA(x) (((x)+1)/2) /**< Configuration descriptor power macro. */
+
+#define DEVICE_IS_SELFPOWERED 0x0001 /**< Standard request GET_STATUS bitmask. */
+#define REMOTE_WAKEUP_ENABLED 0x0002 /**< Standard request GET_STATUS bitmask. */
+#define USB_FEATURE_ENDPOINT_HALT 0 /**< Standard request CLEAR/SET_FEATURE bitmask. */
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 /**< Standard request CLEAR/SET_FEATURE bitmask. */
+
+#define HUB_FEATURE_PORT_RESET 4 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
+#define HUB_FEATURE_PORT_POWER 8 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
+#define HUB_FEATURE_C_PORT_CONNECTION 16 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
+#define HUB_FEATURE_C_PORT_RESET 20 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
+#define HUB_FEATURE_PORT_INDICATOR 22 /**< HUB class request CLEAR/SET_PORT_FEATURE feature selector. */
+
+#define USB_CLASS_CDC 2 /**< CDC device/interface class code. */
+#define USB_CLASS_CDC_DATA 0x0A /**< CDC Data interface class code. */
+#define USB_CLASS_CDC_ACM 2 /**< CDC Abstract Control Model interface subclass code. */
+#define USB_CLASS_CDC_HFN 0 /**< CDC class Header Functional Descriptor subtype. */
+#define USB_CLASS_CDC_CMNGFN 1 /**< CDC class Call Management Functional Descriptor subtype.*/
+#define USB_CLASS_CDC_ACMFN 2 /**< CDC class Abstract Control Management Functional Descriptor subtype.*/
+#define USB_CLASS_CDC_UNIONFN 6 /**< CDC class Union Functional Descriptor subtype. */
+
+#define USB_CLASS_HID 3 /**< HID device/interface class code. */
+#define USB_CLASS_HID_KEYBOARD 1 /**< HID keyboard interface protocol code. */
+#define USB_CLASS_HID_MOUSE 2 /**< HID mouse interface protocol code. */
+
+#define USB_CLASS_HUB 9 /**< HUB device/interface class code. */
+
+#define USB_CLASS_MSD 8 /**< MSD device/interface class code. */
+#define USB_CLASS_MSD_BOT_TRANSPORT 0x50 /**< MSD Bulk Only Transport protocol. */
+#define USB_CLASS_MSD_SCSI_CMDSET 6 /**< MSD Subclass SCSI transparent command set. */
+#define USB_CLASS_MSD_CSW_CMDPASSED 0 /**< MSD BOT Command status wrapper command passed code. */
+#define USB_CLASS_MSD_CSW_CMDFAILED 1 /**< MSD BOT Command status wrapper command failed code. */
+#define USB_CLASS_MSD_CSW_PHASEERROR 2 /**< MSD BOT Command status wrapper cmd phase error code.*/
+
+#define USB_CLASS_AUDIO 1 /**< Audio interface class code. */
+#define USB_CLASS_AUDIO_CONTROL 1 /**< Audio subclass code for control interface. */
+#define USB_CLASS_AUDIO_STREAMING 2 /**< Audio subclass code for streaming interface. */
+#define USB_CLASS_AUDIO_MIDISTREAMING 3 /**< Audio subclass code for midi streaming interface. */
+
+/*** Triplet for the device descriptor of a composite device using IAD descriptors. ***/
+#define USB_CLASS_MISCELLANEOUS 0xEF /**< MISCELLANEOUS device class code. */
+#define USB_CLASS_MISC_COMMON_SUBCLASS 2 /**< MISCELLANEOUS Common sub class code. */
+#define USB_CLASS_MISC_IAD_PROTOCOL 1 /**< MISCELLANEOUS Interface Association Descriptor protocol code. */
+
+#define PORT_FULL_SPEED 1 /**< Full speed return value for USBH_GetPortSpeed(). */
+#define PORT_LOW_SPEED 2 /**< Low speed return value for USBH_GetPortSpeed(). */
+
+#if defined( __GNUC__ ) /* GCC compilers */
+#if defined( __CHAR16_TYPE__ )
+typedef __CHAR16_TYPE__ char16_t;
+#else
+typedef unsigned short char16_t;
+#endif
+
+#elif defined( __ICCARM__ ) /* IAR compiler */
+#include <uchar.h>
+
+#elif defined( __CC_ARM ) /* MDK-ARM compiler */
+typedef unsigned short char16_t;
+#endif
+
+/** Macro for creating USB compliant UTF-16LE UNICODE string descriptors.
+ * @n Example: STATIC_CONST_STRING_DESC( iManufacturer, 'E','n','e','r','g','y',' ','M','i','c','r','o',' ','A','S' );
+ * @note The size of the resulting struct will be two byte larger than a USB string
+ * descriptor. This is to accommodate a terminating null char for the string.
+ * The value assigned to the 'len' member does not take this into account
+ * and is therefore correct usb wise.
+ */
+#define STATIC_CONST_STRING_DESC( _name, ... ) \
+EFM32_PACK_START( 1 ) \
+typedef struct \
+{ \
+ uint8_t len; \
+ uint8_t type; \
+ char16_t name[ 1 + sizeof( (char16_t[]){__VA_ARGS__} ) / 2]; \
+} __attribute__ ((packed)) _##_name; \
+EFM32_PACK_END() \
+EFM32_ALIGN( 4 ) \
+EFM32_PACK_START( 1 ) \
+static const _##_name _name __attribute__ ((aligned(4)))= \
+{ \
+ .len = sizeof( _##_name ) - 2, \
+ .type = USB_STRING_DESCRIPTOR, \
+ .name = {__VA_ARGS__}, \
+ .name[ ( ( sizeof( _##_name ) - 2 ) / 2 ) - 1 ] = '\0' \
+} \
+EFM32_PACK_END()
+
+/** Macro for creating USB compliant language string descriptors.
+ * @n Example: STATIC_CONST_STRING_DESC_LANGID( langID, 0x04, 0x09 );
+ */
+#define STATIC_CONST_STRING_DESC_LANGID( _name, x, y ) \
+EFM32_PACK_START( 1 ) \
+typedef struct \
+{ \
+ uint8_t len; \
+ uint8_t type; \
+ uint8_t name[ 2 ]; \
+} __attribute__ ((packed)) _##_name; \
+EFM32_PACK_END() \
+EFM32_ALIGN( 4 ) \
+EFM32_PACK_START( 1 ) \
+static const _##_name _name __attribute__ ((aligned(4)))= \
+{ \
+ .len = 4, \
+ .type = USB_STRING_DESCRIPTOR, \
+ .name = { y, x } \
+} \
+EFM32_PACK_END()
+
+/** Macro for creating WORD (4 byte) aligned uint8_t array with size which
+ * is a multiple of WORD size.
+ * @n Example: @n UBUF( rxBuffer, 37 ); => uint8_t rxBuffer[ 40 ];
+ */
+#if !defined(__GNUC__)
+#define UBUF( x, y ) EFM32_ALIGN( 4 ) uint8_t x[((y)+3)&~3]
+#define STATIC_UBUF( x, y ) EFM32_ALIGN( 4 ) static uint8_t x[((y)+3)&~3]
+#else
+#define UBUF( x, y ) uint8_t x[((y)+3)&~3] __attribute__ ((aligned(4)))
+
+/** Macro for creating WORD (4 byte) aligned static uint8_t arrays with size which
+ * is a multiple of WORD size.
+ * @n Example: @n STATIC_UBUF( rxBuffer, 37 ); => static uint8_t rxBuffer[ 40 ];
+ */
+#define STATIC_UBUF( x, y ) static uint8_t x[((y)+3)&~3] __attribute__ ((aligned(4)))
+#endif
+
+
+/** @brief USB transfer status enumerator. */
+typedef enum
+{
+ /* NOTE: Please keep in sync with table errMsg[] in em_usbhal.c */
+ USB_STATUS_OK = 0, /**< No errors detected. */
+ USB_STATUS_REQ_ERR = -1, /**< Setup request error. */
+ USB_STATUS_EP_BUSY = -2, /**< Endpoint is busy. */
+ USB_STATUS_REQ_UNHANDLED = -3, /**< Setup request not handled. */
+ USB_STATUS_ILLEGAL = -4, /**< Illegal operation attempted. */
+ USB_STATUS_EP_STALLED = -5, /**< Endpoint is stalled. */
+ USB_STATUS_EP_ABORTED = -6, /**< Endpoint transfer was aborted. */
+ USB_STATUS_EP_ERROR = -7, /**< Endpoint transfer error. */
+ USB_STATUS_EP_NAK = -8, /**< Endpoint NAK'ed transfer request. */
+ USB_STATUS_DEVICE_UNCONFIGURED = -9, /**< Device is unconfigured. */
+ USB_STATUS_DEVICE_SUSPENDED = -10, /**< Device is suspended. */
+ USB_STATUS_DEVICE_RESET = -11, /**< Device is/was reset. */
+ USB_STATUS_TIMEOUT = -12, /**< Transfer timeout. */
+ USB_STATUS_DEVICE_REMOVED = -13, /**< Device was removed. */
+ USB_STATUS_HC_BUSY = -14, /**< Host channel is busy. */
+ USB_STATUS_DEVICE_MALFUNCTION = -15, /**< Malfunctioning device attached. */
+ USB_STATUS_PORT_OVERCURRENT = -16, /**< VBUS shortcircuit/overcurrent failure. */
+} USB_Status_TypeDef;
+/** @} (end addtogroup USB_COMMON) */
+
+
+#if defined( USB_DEVICE )
+/***************************************************************************//**
+ * @addtogroup USB_DEVICE
+ * @brief USB DEVICE protocol stack, see @ref usb_device page for detailed documentation.
+ * @{
+ ******************************************************************************/
+
+#define USB_PWRSAVE_MODE_OFF 0 /**< No energy saving mode selected. */
+#define USB_PWRSAVE_MODE_ONSUSPEND 1 /**< Enter USB power-save mode on suspend. */
+#define USB_PWRSAVE_MODE_ONVBUSOFF 2 /**< Enter USB power-save mode when not attached to host. */
+#define USB_PWRSAVE_MODE_ENTEREM2 4 /**< Enter EM2 while in power-save mode. */
+
+#define USB_USBC_32kHz_CLK_LFXO 0 /**< Use 32kHz LFXO clock while in powersave mode. */
+#define USB_USBC_32kHz_CLK_LFRCO 1 /**< Use 32kHz LFRCO clock while in powersave mode. */
+
+/** @brief USB device state enumerator. */
+typedef enum
+{
+ USBD_STATE_NONE = 0, /**< Device state is undefined/unknown. */
+ USBD_STATE_ATTACHED = 1, /**< Device state is ATTACHED. */
+ USBD_STATE_POWERED = 2, /**< Device state is POWERED. */
+ USBD_STATE_DEFAULT = 3, /**< Device state is DEFAULT. */
+ USBD_STATE_ADDRESSED = 4, /**< Device state is ADDRESSED. */
+ USBD_STATE_CONFIGURED = 5, /**< Device state is CONFIGURED. */
+ USBD_STATE_SUSPENDED = 6, /**< Device state is SUSPENDED. */
+ USBD_STATE_LASTMARKER = 7, /**< Device state enum end marker. */
+} USBD_State_TypeDef;
+/** @} (end addtogroup USB_DEVICE) */
+#endif /* defined( USB_DEVICE ) */
+
+/** @addtogroup USB_COMMON
+ * @{*/
+
+/** @brief USB Setup request package. */
+EFM32_PACK_START( 1 )
+typedef struct
+{
+ union
+ {
+ struct
+ {
+ union
+ {
+ struct
+ {
+ uint8_t Recipient : 5; /**< Request recipient (device, interface, endpoint or other).*/
+ uint8_t Type : 2; /**< Request type (standard, class or vendor). */
+ uint8_t Direction : 1; /**< Transfer direction of SETUP data phase. */
+ };
+ uint8_t bmRequestType; /**< Request characteristics. */
+ };
+ uint8_t bRequest; /**< Request code. */
+ uint16_t wValue; /**< Varies according to request. */
+ uint16_t wIndex; /**< Index or offset, varies according to request. */
+ uint16_t wLength; /**< Number of bytes to transfer if there is a data stage.*/
+ };
+ uint32_t dw[2];
+ };
+} __attribute__ ((packed)) USB_Setup_TypeDef;
+EFM32_PACK_END()
+
+
+/** @brief USB Device Descriptor. */
+EFM32_PACK_START( 1 )
+typedef struct
+{
+ uint8_t bLength; /**< Size of this descriptor in bytes */
+ uint8_t bDescriptorType; /**< Constant DEVICE Descriptor Type */
+ uint16_t bcdUSB; /**< USB Specification Release Number in Binary-Coded
+ Decimal */
+ uint8_t bDeviceClass; /**< Class code (assigned by the USB-IF) */
+ uint8_t bDeviceSubClass; /**< Subclass code (assigned by the USB-IF) */
+ uint8_t bDeviceProtocol; /**< Protocol code (assigned by the USB-IF) */
+ uint8_t bMaxPacketSize0; /**< Maximum packet size for endpoint zero */
+ uint16_t idVendor; /**< Vendor ID (assigned by the USB-IF) */
+ uint16_t idProduct; /**< Product ID (assigned by the manufacturer) */
+ uint16_t bcdDevice; /**< Device release number in binary-coded decimal */
+ uint8_t iManufacturer; /**< Index of string descriptor describing manufacturer*/
+ uint8_t iProduct; /**< Index of string descriptor describing product */
+ uint8_t iSerialNumber; /**< Index of string descriptor describing the device
+ serialnumber */
+ uint8_t bNumConfigurations; /**< Number of possible configurations */
+} __attribute__ ((packed)) USB_DeviceDescriptor_TypeDef;
+EFM32_PACK_END()
+
+
+/** @brief USB Configuration Descriptor. */
+EFM32_PACK_START( 1 )
+typedef struct
+{
+ uint8_t bLength; /**< Size of this descriptor in bytes */
+ uint8_t bDescriptorType; /**< Constant CONFIGURATION Descriptor Type */
+ uint16_t wTotalLength; /**< Total length of data returned for this
+ configuration. Includes the combined length of all
+ descriptors (configuration, interface, endpoint,
+ and class- or vendor-specific) returned for this
+ configuration. */
+ uint8_t bNumInterfaces; /**< Number of interfaces supported by this
+ configuration */
+ uint8_t bConfigurationValue; /**< Value to use as an argument to the
+ SetConfiguration request to select this
+ configuration. */
+ uint8_t iConfiguration; /**< Index of string descriptor describing this
+ configuration. */
+ uint8_t bmAttributes; /**< Configuration characteristics.
+ @n D7: Reserved (set to one)
+ @n D6: Self-powered
+ @n D5: Remote Wakeup
+ @n D4...0: Reserved (reset to zero) */
+ uint8_t bMaxPower; /**< Maximum power consumption of the USB device, unit
+ is 2mA per LSB */
+} __attribute__ ((packed)) USB_ConfigurationDescriptor_TypeDef;
+EFM32_PACK_END()
+
+
+/** @brief USB Interface Descriptor. */
+EFM32_PACK_START( 1 )
+typedef struct
+{
+ uint8_t bLength; /**< Size of this descriptor in bytes. */
+ uint8_t bDescriptorType; /**< Constant INTERFACE Descriptor Type. */
+ uint8_t bInterfaceNumber; /**< Number of this interface. Zero-based value
+ identifying the index in the array of concurrent
+ interfaces supported by this configuration. */
+ uint8_t bAlternateSetting; /**< Value used to select this alternate setting for
+ the interface identified in the prior field. */
+ uint8_t bNumEndpoints; /**< Number of endpoints used by this interface
+ (excluding endpoint zero). If this value is zero,
+ this interface only uses the Default Control Pipe.*/
+ uint8_t bInterfaceClass; /**< Class code (assigned by the USB-IF). A value
+ of zero is reserved for future standardization. If
+ this field is set to FFH, the interface class is
+ vendor-specific. All other values are reserved for
+ assignment by the USB-IF. */
+ uint8_t bInterfaceSubClass; /**< Subclass code (assigned by the USB-IF). These codes
+ are qualified by the value of the bInterfaceClass
+ field. If the bInterfaceClass field is reset to
+ zero, this field must also be reset to zero. If
+ the bInterfaceClass field is not set to FFH, all
+ values are reserved forassignment by the USB-IF. */
+ uint8_t bInterfaceProtocol; /**< Protocol code (assigned by the USB). These codes
+ are qualified by the value of the bInterfaceClass
+ and the bInterfaceSubClass fields. If an interface
+ supports class-specific requests, this code
+ identifies the protocols that the device uses as
+ defined by the specification of the device class.
+ If this field is reset to zero, the device does
+ not use a class-specific protocol on this
+ interface. If this field is set to FFH, the device
+ uses a vendor-specific protocol for this interface*/
+ uint8_t iInterface; /**< Index of string descriptor describing this
+ interface. */
+} __attribute__ ((packed)) USB_InterfaceDescriptor_TypeDef;
+EFM32_PACK_END()
+
+
+/** @brief USB Endpoint Descriptor. */
+EFM32_PACK_START( 1 )
+typedef struct
+{
+ uint8_t bLength; /**< Size of this descriptor in bytes */
+ uint8_t bDescriptorType; /**< Constant ENDPOINT Descriptor Type */
+ uint8_t bEndpointAddress; /**< The address of the endpoint */
+ uint8_t bmAttributes; /**< This field describes the endpoint attributes */
+ uint16_t wMaxPacketSize; /**< Maximum packet size for the endpoint */
+ uint8_t bInterval; /**< Interval for polling EP for data transfers */
+} __attribute__ ((packed)) USB_EndpointDescriptor_TypeDef;
+EFM32_PACK_END()
+
+
+/** @brief USB String Descriptor. */
+EFM32_PACK_START( 1 )
+typedef struct
+{
+ uint8_t len; /**< Size of this descriptor in bytes. */
+ uint8_t type; /**< Constant STRING Descriptor Type. */
+ char16_t name[]; /**< The string encoded with UTF-16LE UNICODE charset. */
+} __attribute__ ((packed)) USB_StringDescriptor_TypeDef;
+EFM32_PACK_END()
+
+/** @} (end addtogroup USB_COMMON) */
+
+/*** -------------------- Serial port debug configuration ---------------- ***/
+
+#if defined( DOXY_DOC_ONLY )
+/** @addtogroup USB_COMMON
+ * @{*/
+
+/***************************************************************************//**
+ * @brief
+ * Transmit a single char on the debug serial port.
+ *
+ * @note
+ * This function is enabled with \#define DEBUG_USB_API when configuring the
+ * protocol stack in "usbconfig.h".
+ * This is convenient when debugging code, no need to remove use of this
+ * function when debugging has completed.
+ *
+ * @param[in] c
+ * Char to transmit.
+ *
+ * @return
+ * The char transmitted.
+ ******************************************************************************/
+int USB_PUTCHAR( char c );
+
+/***************************************************************************//**
+ * @brief
+ * Transmit a zero terminated string on the debug serial port.
+ *
+ * @note
+ * This function is enabled with \#define DEBUG_USB_API when configuring the
+ * protocol stack in "usbconfig.h".
+ * This is convenient when debugging code, no need to remove use of this
+ * function when debugging has completed.
+ *
+ * @param[in] p
+ * Pointer to string to transmit.
+ ******************************************************************************/
+void USB_PUTS( const char *p );
+
+/***************************************************************************//**
+ * @brief
+ * Transmit "printf" formated data on the debug serial port.
+ *
+ * @note
+ * This function is enabled with \#define USB_USE_PRINTF when configuring the
+ * protocol stack in "usbconfig.h".
+ * This is convenient when debugging code, no need to remove use of this
+ * function when debugging has completed.
+ *
+ * @param[in] format
+ * Format string (as in printf). No floating point format support.
+ ******************************************************************************/
+int USB_PRINTF( const char *format, ... );
+
+/** @} (end addtogroup USB_COMMON) */
+#endif /* defined( DOXY_DOC_ONLY ) */
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/* Hardware constraint, do not change. */
+#define MAX_NUM_HOSTCHANNELS 14
+
+/* The DMA engine use one FIFO ram word for each host channel. */
+#define MAX_HOST_FIFO_SIZE_INWORDS (512-MAX_NUM_HOSTCHANNELS)/*Unit is 4 bytes*/
+
+#if defined ( USER_PUTCHAR )
+ void USB_Puts( const char *p );
+ #define USB_PUTS( s ) USB_Puts( s )
+ #define USB_PUTCHAR( c ) USER_PUTCHAR( c )
+#else
+ #define USB_PUTS( s )
+ #define USB_PUTCHAR( c )
+#endif
+
+#if defined( USB_USE_PRINTF )
+ /* Use a printf which don't support floating point formatting */
+ #if defined(__ICCARM__) || defined (__CC_ARM) || defined (__CROSSWORKS_ARM)
+ #define USB_PRINTF printf
+ #else
+ #define USB_PRINTF iprintf
+ #endif
+#else
+ #define USB_PRINTF(...)
+#endif /* defined( USB_USE_PRINTF ) */
+
+#if defined( DEBUG_USB_API )
+ #define DEBUG_USB_API_PUTS( s ) USB_PUTS( s )
+ #define DEBUG_USB_API_PUTCHAR( c ) USB_PUTCHAR( c )
+#else
+ #define DEBUG_USB_API_PUTS( s )
+ #define DEBUG_USB_API_PUTCHAR( c )
+#endif /* defined( DEBUG_USB_API ) */
+
+/** @endcond */
+
+/*** -------------------- Common API definitions ------------------------- ***/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#if defined( USB_HOST )
+ #if defined( NUM_APP_TIMERS )
+ #define NUM_QTIMERS ( NUM_HC_USED + 2 + NUM_APP_TIMERS + 1 )
+ #else
+ #define NUM_QTIMERS ( NUM_HC_USED + 2 + 1 )
+ #endif
+ /* + 2 for default ctrl. host ch. 0 & 1, + 1 for host port timer */
+#else
+ #if defined( NUM_APP_TIMERS )
+ #define NUM_QTIMERS ( NUM_APP_TIMERS )
+ #else
+ #define NUM_QTIMERS 0
+ #endif
+#endif /* defined( USB_HOST ) */
+/** @endcond */
+
+/** @addtogroup USB_COMMON
+ * @{*/
+
+/***************************************************************************//**
+ * @brief
+ * USB transfer callback function.
+ *
+ * @details
+ * The callback function is called when a transfer has completed. An application
+ * should check the status, xferred and optionally the remaining parameters
+ * before deciding if the transfer is usable. In the case where the transfer
+ * is part of a control request data stage, the callback function should
+ * return an appropriate @ref USB_Status_TypeDef status.
+ *
+ * @param[in] status
+ * The transfer status. See @ref USB_Status_TypeDef.
+ *
+ * @param[in] xferred
+ * Number of bytes actually transferred.
+ *
+ * @param[in] remaining
+ * Number of bytes not transferred.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+typedef int (*USB_XferCompleteCb_TypeDef)( USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining );
+
+/***************************************************************************//**
+ * @brief
+ * USBTIMER callback function.
+ *
+ * @details
+ * The callback function is called when an USBTIMER has expired. The callback
+ * is done with interrupts disabled.
+ ******************************************************************************/
+typedef void (*USBTIMER_Callback_TypeDef)( void );
+
+char *USB_GetErrorMsgString( int error );
+
+#if defined( USB_USE_PRINTF )
+ void USB_PrintErrorMsgString( char *pre, int error );
+#else
+ #define USB_PrintErrorMsgString( pre, error )
+#endif
+
+void USBTIMER_DelayMs( uint32_t msec );
+void USBTIMER_DelayUs( uint32_t usec );
+void USBTIMER_Init( void );
+
+#if ( NUM_QTIMERS > 0 )
+ void USBTIMER_Start( uint32_t id, uint32_t timeout, USBTIMER_Callback_TypeDef callback );
+ void USBTIMER_Stop( uint32_t id );
+#endif /* ( NUM_QTIMERS > 0 ) */
+/** @} (end addtogroup USB_COMMON) */
+
+#if defined( USB_DEVICE )
+/** @addtogroup USB_DEVICE
+ * @{*/
+/*** -------------------- DEVICE mode API definitions -------------------- ***/
+
+/***************************************************************************//**
+ * @brief
+ * USB Reset callback function.
+ * @details
+ * Called whenever USB reset signalling is detected on the USB port.
+ ******************************************************************************/
+typedef void (*USBD_UsbResetCb_TypeDef)( void );
+
+/***************************************************************************//**
+ * @brief
+ * USB Start Of Frame (SOF) interrupt callback function.
+ *
+ * @details
+ * Called at each SOF interrupt (if enabled),
+ *
+ * @param[in] sofNr
+ * Current frame number. The value rolls over to 0 after 16383 (0x3FFF).
+ ******************************************************************************/
+typedef void (*USBD_SofIntCb_TypeDef)( uint16_t sofNr );
+
+/***************************************************************************//**
+ * @brief
+ * USB State change callback function.
+ *
+ * @details
+ * Called whenever the device change state.
+ *
+ * @param[in] oldState
+ * The device USB state just leaved. See @ref USBD_State_TypeDef.
+ *
+ * @param[in] newState
+ * New (the current) USB device state. See @ref USBD_State_TypeDef.
+ ******************************************************************************/
+typedef void (*USBD_DeviceStateChangeCb_TypeDef)( USBD_State_TypeDef oldState, USBD_State_TypeDef newState );
+
+/***************************************************************************//**
+ * @brief
+ * USB power mode callback function.
+ *
+ * @details
+ * Called whenever the device stack needs to query if the device is currently
+ * self- or bus-powered. Typically when host has issued an @ref GET_STATUS
+ * setup command.
+ *
+ * @return
+ * True if self-powered, false otherwise.
+ ******************************************************************************/
+typedef bool (*USBD_IsSelfPoweredCb_TypeDef)( void );
+
+/***************************************************************************//**
+ * @brief
+ * USB setup request callback function.
+ *
+ * @details
+ * Called on each setup request received from host. This gives the application a
+ * possibility to extend or override standard requests, and to implement class
+ * or vendor specific requests. Return @ref USB_STATUS_OK if the request is
+ * handled, return @ref USB_STATUS_REQ_ERR if it is an illegal request or
+ * return @ref USB_STATUS_REQ_UNHANDLED to pass the request on to the default
+ * request handler.
+ *
+ * @param[in] setup
+ * Pointer to an USB setup packet. See @ref USB_Setup_TypeDef.
+ *
+ * @return
+ * An appropriate status/error code. See @ref USB_Status_TypeDef.
+ ******************************************************************************/
+typedef int (*USBD_SetupCmdCb_TypeDef)( const USB_Setup_TypeDef *setup );
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+struct USBD_Callbacks_TypeDef;
+typedef struct USBD_Callbacks_TypeDef const *USBD_Callbacks_TypeDef_Pointer;
+/** @endcond */
+
+
+/** @brief USB Device stack initialization structure.
+ * @details This structure is passed to @ref USBD_Init() when starting up
+ * the device. */
+typedef struct
+{
+ const USB_DeviceDescriptor_TypeDef *deviceDescriptor; /**< Pointer to a device descriptor. */
+ const uint8_t *configDescriptor; /**< Pointer to a configuration descriptor. */
+ const void * const *stringDescriptors; /**< Pointer to an array of string descriptor pointers.*/
+ const uint8_t numberOfStrings; /**< Number of strings in string descriptor array. */
+ const uint8_t *bufferingMultiplier; /**< Pointer to an array defining the size of the
+ endpoint buffers. The size is given in
+ multiples of endpoint size. Generally a value
+ of 1 (single) or 2 (double) buffering should be
+ used. */
+ USBD_Callbacks_TypeDef_Pointer callbacks; /**< Pointer to struct with callbacks
+ (@ref USBD_Callbacks_TypeDef). These callbacks
+ are used by the device stack to signal events
+ to or query the application. */
+ const uint32_t reserved; /**< Reserved for future use. */
+} USBD_Init_TypeDef;
+
+
+/** @brief USB Device stack callback structure.
+ * @details Callback functions used by the device stack to signal events or
+ * query status to/from the application. See @ref USBD_Init_TypeDef. Assign
+ * members to NULL if your application don't need a specific callback. */
+typedef struct USBD_Callbacks_TypeDef
+{
+ const USBD_UsbResetCb_TypeDef usbReset; /**< Called whenever USB reset signalling is detected
+ on the USB port. */
+ const USBD_DeviceStateChangeCb_TypeDef usbStateChange; /**< Called whenever the device change state. */
+ const USBD_SetupCmdCb_TypeDef setupCmd; /**< Called on each setup request received from host.*/
+ const USBD_IsSelfPoweredCb_TypeDef isSelfPowered; /**< Called whenever the device stack needs to query
+ if the device is currently self- or bus-powered.
+ Applies to devices which can operate in both modes.*/
+ const USBD_SofIntCb_TypeDef sofInt; /**< Called at each SOF interrupt. If NULL, the device
+ stack will not enable the SOF interrupt. */
+} USBD_Callbacks_TypeDef;
+
+
+/*** -------------------- DEVICE mode API -------------------------------- ***/
+
+void USBD_AbortAllTransfers( void );
+int USBD_AbortTransfer( int epAddr );
+void USBD_Connect( void );
+void USBD_Disconnect( void );
+bool USBD_EpIsBusy( int epAddr );
+USBD_State_TypeDef USBD_GetUsbState( void );
+const char * USBD_GetUsbStateName( USBD_State_TypeDef state );
+int USBD_Init( const USBD_Init_TypeDef *p );
+int USBD_Read( int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback );
+int USBD_RemoteWakeup( void );
+bool USBD_SafeToEnterEM2( void );
+int USBD_StallEp( int epAddr );
+void USBD_Stop( void );
+int USBD_UnStallEp( int epAddr );
+int USBD_Write( int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback );
+
+#ifdef __MBED__
+int USBD_SetAddress( uint8_t addr );
+int USBD_AddEndpoint( int epAddr, int transferType, int maxPacketSize, int bufferMult );
+int USBD_EpIsStalled( int epAddr );
+void USBD_StallEp0( void );
+#endif
+
+/** @} (end addtogroup USB_DEVICE) */
+#endif /* defined( USB_DEVICE ) */
+
+
+#if defined( USB_HOST )
+/***************************************************************************//**
+ * @addtogroup USB_HOST
+ * @brief USB HOST protocol stack, see @ref usb_host page for detailed documentation.
+ * @{
+ ******************************************************************************/
+/*** -------------------- HOST mode API definitions ---------------------- ***/
+
+#define USB_VBUSOVRCUR_PORT_NONE -1 /**< No overcurrent flag functionality. */
+#define USB_VBUSOVRCUR_POLARITY_LOW 0 /**< Overcurrent flag pin polarity is low. */
+#define USB_VBUSOVRCUR_POLARITY_HIGH 1 /**< Overcurrent flag pin polarity is high. */
+
+/** USB HOST endpoint status enumerator. */
+typedef enum
+{
+ H_EP_IDLE = 0, /**< The endpoint is idle. */
+ H_EP_SETUP = 1, /**< The endpoint is in SETUP stage. */
+ H_EP_DATA_IN = 2, /**< The endpoint is in DATA IN stage. */
+ H_EP_DATA_OUT = 3, /**< The endpoint is in DATA OUT stage. */
+ H_EP_STATUS_IN = 4, /**< The endpoint is in STATUS IN stage. */
+ H_EP_STATUS_OUT = 5, /**< The endpoint is in STATUS OUT stage. */
+} USBH_EpState_TypeDef;
+
+
+/** @brief USB HOST endpoint status data.
+ * @details A host application should not manipulate the contents of
+ * this struct. */
+typedef struct
+{
+ USB_Setup_TypeDef setup; /**< A SETUP package. */
+ uint8_t setupErrCnt; /**< Error counter for SETUP transfers. */
+ USB_EndpointDescriptor_TypeDef epDesc; /**< Endpoint descriptor. */
+ struct USBH_Device_TypeDef *parentDevice; /**< The device the endpoint belongs to. */
+ uint8_t type; /**< Endpoint type. */
+ uint16_t packetSize; /**< Packet size, current transfer. */
+ uint8_t hcOut; /**< Host channel number assigned for OUT transfers. */
+ uint8_t hcIn; /**< Host channel number assigned for IN transfers. */
+ bool in; /**< Endpoint direction. */
+ uint8_t toggle; /**< Endpoint data toggle. */
+ USBH_EpState_TypeDef state; /**< Endpoint state. */
+ uint8_t addr; /**< Endpoint address. */
+ uint8_t *buf; /**< Transfer buffer. */
+ volatile bool xferCompleted; /**< Transfer completion flag. */
+ USB_Status_TypeDef xferStatus; /**< Transfer status. */
+ USB_XferCompleteCb_TypeDef xferCompleteCb; /**< Transfer completion callback function. */
+ uint32_t xferred; /**< Number of bytes transferred. */
+ uint32_t remaining; /**< Number of bytes remaining. */
+ uint32_t timeout; /**< Transfer timeout. */
+} USBH_Ep_TypeDef;
+
+
+/** @brief USB HOST device definition.
+ * @details A host application should not manipulate the contents of
+ * this struct. */
+typedef struct USBH_Device_TypeDef
+{
+ USB_DeviceDescriptor_TypeDef devDesc; /**< The device device descriptor. */
+ USB_ConfigurationDescriptor_TypeDef confDesc; /**< The device configuration descriptor. */
+ USB_InterfaceDescriptor_TypeDef itfDesc; /**< The device interface descriptor. */
+ USBH_Ep_TypeDef ep0; /**< Endpoint 0 status data. */
+ USBH_Ep_TypeDef *ep; /**< Array of endpoint status data. */
+ int numEp; /**< Number of endpoints. */
+ uint8_t addr; /**< The device address. */
+ uint8_t speed; /**< The device speed (low or full speed). */
+} USBH_Device_TypeDef;
+
+
+/** @brief USB Host stack initialization structure.
+ * @details This structure is passed to @ref USBH_Init() when starting up the
+ * device. Max accumulated FIFO size is 2K bytes. */
+typedef struct
+{
+ uint32_t rxFifoSize; /**< Number of FIFO bytes set aside for IN endpoints. */
+ uint32_t nptxFifoSize; /**< Number of FIFO bytes set aside for OUT CTRL/BULK endoints. */
+ uint32_t ptxFifoSize; /**< Number of FIFO bytes set aside for OUT INTR/ISO endoints. */
+ uint32_t reserved; /**< Reserved for future use. */
+} USBH_Init_TypeDef;
+
+
+/** Default @ref USBH_Init_TypeDef values, provides reasonable Tx/Rx FIFO
+ * partitioning. */
+/* In DMA mode the total available FIFO space is smaller. */
+/* The DMA controller use one FIFO word pr. channel for status. */
+/* The unit in the table is byte. */
+#define USBH_INIT_DEFAULT \
+{ \
+ MAX_HOST_FIFO_SIZE_INWORDS * 2,/* 1024 bytes Rx FIFO size. */ \
+ MAX_HOST_FIFO_SIZE_INWORDS, /* 512 bytes non-periodic Tx FIFO size. */ \
+ MAX_HOST_FIFO_SIZE_INWORDS, /* 512 bytes periodic Tx FIFO size. */ \
+ 0 /* Reserved. */ \
+}
+
+/*** -------------------- HOST mode API ---------------------------------- ***/
+
+int USBH_AssignHostChannel( USBH_Ep_TypeDef *ep, uint8_t hcnum );
+int USBH_ControlMsg( USBH_Ep_TypeDef *ep, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, void *data, int timeout, USB_XferCompleteCb_TypeDef callback );
+int USBH_ControlMsgB( USBH_Ep_TypeDef *ep, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, void *data, int timeout );
+bool USBH_DeviceConnected( void );
+int USBH_GetConfigurationDescriptorB( USBH_Device_TypeDef *device, void *buf, int len, uint8_t configIndex );
+int USBH_GetDeviceDescriptorB( USBH_Device_TypeDef *device, void *buf, int len );
+uint8_t USBH_GetPortSpeed( void );
+int USBH_GetStringB( USBH_Device_TypeDef *device, uint8_t *buf, int bufLen, uint8_t stringIndex, uint16_t langID );
+int USBH_Init( const USBH_Init_TypeDef *p );
+int USBH_InitDeviceData( USBH_Device_TypeDef *device, const uint8_t *buf, USBH_Ep_TypeDef *ep, int numEp, uint8_t deviceSpeed );
+int USBH_PortReset( void );
+int USBH_PortResume( void );
+void USBH_PortSuspend( void );
+void USBH_PrintString( const char *pre, const USB_StringDescriptor_TypeDef *s, const char *post );
+
+#if defined( USB_USE_PRINTF )
+int USBH_PrintConfigurationDescriptor( const USB_ConfigurationDescriptor_TypeDef *config, int maxLen );
+int USBH_PrintDeviceDescriptor( const USB_DeviceDescriptor_TypeDef *device );
+int USBH_PrintEndpointDescriptor( const USB_EndpointDescriptor_TypeDef *endpoint );
+int USBH_PrintInterfaceDescriptor( const USB_InterfaceDescriptor_TypeDef *interface );
+#else
+#define USBH_PrintConfigurationDescriptor( config, maxLen )
+#define USBH_PrintDeviceDescriptor( device )
+#define USBH_PrintEndpointDescriptor( endpoint )
+#define USBH_PrintInterfaceDescriptor( interface )
+#endif /* defined( USB_USE_PRINTF ) */
+
+int USBH_QueryDeviceB( uint8_t *buf, size_t bufsize, uint8_t deviceSpeed );
+USB_ConfigurationDescriptor_TypeDef* USBH_QGetConfigurationDescriptor( const uint8_t *buf, int configIndex );
+USB_DeviceDescriptor_TypeDef* USBH_QGetDeviceDescriptor( const uint8_t *buf );
+USB_EndpointDescriptor_TypeDef* USBH_QGetEndpointDescriptor( const uint8_t *buf, int configIndex, int interfaceIndex, int endpointIndex );
+USB_InterfaceDescriptor_TypeDef* USBH_QGetInterfaceDescriptor( const uint8_t *buf, int configIndex, int interfaceIndex );
+
+int USBH_Read( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout, USB_XferCompleteCb_TypeDef callback );
+int USBH_ReadB( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout );
+int USBH_SetAddressB( USBH_Device_TypeDef *device, uint8_t deviceAddress );
+int USBH_SetAltInterfaceB( USBH_Device_TypeDef *device, uint8_t interfaceIndex, uint8_t alternateSetting );
+int USBH_SetConfigurationB( USBH_Device_TypeDef *device, uint8_t configValue );
+int USBH_StallEpB( USBH_Ep_TypeDef *ep );
+void USBH_Stop( void );
+int USBH_UnStallEpB( USBH_Ep_TypeDef *ep );
+int USBH_WaitForDeviceConnectionB( uint8_t *buf, int timeoutInSeconds );
+int USBH_Write( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout, USB_XferCompleteCb_TypeDef callback );
+int USBH_WriteB( USBH_Ep_TypeDef *ep, void *data, int byteCount, int timeout );
+
+/** @} (end addtogroup USB_HOST) */
+#endif /* defined( USB_HOST ) */
+/** @} (end addtogroup USB) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
+#endif /* __EM_USB_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/inc/em_usbd.h Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,206 @@
+/***************************************************************************//**
+ * @file em_usbd.h
+ * @brief USB protocol stack library API for EFM32.
+ * @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.
+ *
+ ******************************************************************************/
+
+#ifndef __EM_USBD_H
+#define __EM_USBD_H
+
+#include "em_device.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "em_usb.h"
+#if defined( USB_DEVICE )
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#if defined( DEBUG_USB_API )
+#define DEBUG_TRACE_ABORT( x ) \
+{ \
+ if ( x == USB_STATUS_EP_STALLED ) \
+ { DEBUG_USB_API_PUTS( "\nEP cb(), EP stalled" ); } \
+ else if ( x == USB_STATUS_EP_ABORTED ) \
+ { DEBUG_USB_API_PUTS( "\nEP cb(), EP aborted" ); } \
+ else if ( x == USB_STATUS_DEVICE_UNCONFIGURED ) \
+ { DEBUG_USB_API_PUTS( "\nEP cb(), device unconfigured" ); } \
+ else if ( x == USB_STATUS_DEVICE_SUSPENDED ) \
+ { DEBUG_USB_API_PUTS( "\nEP cb(), device suspended" ); } \
+ else /* ( x == USB_STATUS_DEVICE_RESET ) */ \
+ { DEBUG_USB_API_PUTS( "\nEP cb(), device reset" ); } \
+}
+#else
+#define DEBUG_TRACE_ABORT( x )
+#endif
+
+extern USBD_Device_TypeDef *dev;
+extern volatile bool USBD_poweredDown;
+
+__STATIC_INLINE void USBD_ArmEp0( USBD_Ep_TypeDef *ep );
+__STATIC_INLINE void USBD_ArmEpN( USBD_Ep_TypeDef *ep );
+__STATIC_INLINE void USBD_AbortEp( USBD_Ep_TypeDef *ep );
+
+void USBD_SetUsbState( USBD_State_TypeDef newState );
+
+int USBDCH9_SetupCmd( USBD_Device_TypeDef *device );
+
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device );
+void USBDEP_EpHandler( uint8_t epAddr );
+
+__STATIC_INLINE void USBD_ActivateAllEps( bool forceIdle )
+{
+ int i;
+
+ for ( i = 1; i <= NUM_EP_USED; i++ )
+ {
+ USBDHAL_ActivateEp( &dev->ep[ i ], forceIdle );
+ }
+}
+
+__STATIC_INLINE void USBD_ArmEp( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->num == 0 )
+ {
+ USBD_ArmEp0( ep );
+ }
+ else
+ {
+ USBD_ArmEpN( ep );
+ }
+}
+
+__STATIC_INLINE void USBD_ArmEp0( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->in )
+ {
+ if ( ep->remaining == 0 ) /* Zero Length Packet? */
+ {
+ ep->zlp = 1;
+ }
+
+ USBDHAL_SetEp0InDmaPtr( ep->buf );
+ USBDHAL_StartEp0In( EFM32_MIN( ep->remaining, ep->packetSize ),
+ dev->ep0MpsCode );
+ }
+ else
+ {
+ USBDHAL_SetEp0OutDmaPtr( ep->buf );
+ USBDHAL_StartEp0Out( ep->packetSize, dev->ep0MpsCode );
+ }
+}
+
+__STATIC_INLINE void USBD_ArmEpN( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->in )
+ {
+ USBDHAL_StartEpIn( ep );
+ }
+ else
+ {
+ USBDHAL_StartEpOut( ep );
+ }
+}
+
+__STATIC_INLINE void USBD_DeactivateAllEps( USB_Status_TypeDef reason )
+{
+ int i;
+ USBD_Ep_TypeDef *ep;
+
+ for ( i = 1; i <= NUM_EP_USED; i++ )
+ {
+ ep = &dev->ep[ i ];
+
+ if ( ep->state == D_EP_IDLE )
+ {
+ USBDHAL_DeactivateEp( ep );
+ }
+ }
+
+ USBDHAL_AbortAllTransfers( reason );
+}
+
+__STATIC_INLINE USBD_Ep_TypeDef *USBD_GetEpFromAddr( uint8_t epAddr )
+{
+ int epIndex;
+ USBD_Ep_TypeDef *ep = NULL;
+
+ if ( epAddr & USB_SETUP_DIR_MASK )
+ {
+ epIndex = dev->inEpAddr2EpIndex[ epAddr & USB_EPNUM_MASK ];
+ }
+ else
+ {
+ epIndex = dev->outEpAddr2EpIndex[ epAddr & USB_EPNUM_MASK ];
+ }
+
+ if ( epIndex )
+ {
+ ep = &dev->ep[ epIndex ];
+ }
+ else if ( ( epAddr & USB_EPNUM_MASK ) == 0 )
+ {
+ ep = &dev->ep[ 0 ];
+ }
+
+ return ep;
+}
+
+__STATIC_INLINE void USBD_ReArmEp0( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->in )
+ {
+ USBDHAL_StartEp0In( EFM32_MIN( ep->remaining, ep->packetSize ),
+ dev->ep0MpsCode );
+ }
+ else
+ {
+ USBDHAL_StartEp0Out( ep->packetSize, dev->ep0MpsCode );
+ }
+}
+
+__STATIC_INLINE void USBD_AbortEp( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->state == D_EP_IDLE )
+ {
+ return;
+ }
+
+ if ( ep->in )
+ {
+ USBDHAL_AbortEpIn( ep );
+ }
+ else
+ {
+ USBDHAL_AbortEpOut( ep );
+ }
+}
+
+/** @endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined( USB_DEVICE ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
+#endif /* __EM_USBD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/inc/em_usbh.h Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,75 @@
+/***************************************************************************//**
+ * @file em_usbh.h
+ * @brief USB protocol stack library API for EFM32.
+ * @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.
+ *
+ ******************************************************************************/
+
+#ifndef __EM_USBH_H
+#define __EM_USBH_H
+
+#include "em_device.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "em_usb.h"
+#if defined( USB_HOST )
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+extern USBH_Hc_TypeDef hcs[];
+extern int USBH_attachRetryCount;
+extern const USBH_AttachTiming_TypeDef USBH_attachTiming[];
+extern USBH_Init_TypeDef USBH_initData;
+extern volatile USBH_PortState_TypeDef USBH_portStatus;
+
+USB_Status_TypeDef USBH_CtlSendSetup( USBH_Ep_TypeDef *ep );
+USB_Status_TypeDef USBH_CtlSendData( USBH_Ep_TypeDef *ep, uint16_t length );
+USB_Status_TypeDef USBH_CtlReceiveData( USBH_Ep_TypeDef *ep, uint16_t length );
+
+#if defined( USB_RAW_API )
+int USBH_CtlRxRaw( uint8_t pid, USBH_Ep_TypeDef *ep, void *data, int byteCount );
+int USBH_CtlTxRaw( uint8_t pid, USBH_Ep_TypeDef *ep, void *data, int byteCount );
+#endif
+
+void USBHEP_EpHandler( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result );
+void USBHEP_CtrlEpHandler( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result );
+void USBHEP_TransferDone( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result );
+
+__STATIC_INLINE uint16_t USBH_GetFrameNum( void )
+{
+ return USBHHAL_GetFrameNum();
+}
+
+__STATIC_INLINE bool USBH_FrameNumIsEven( void )
+{
+ return ( USBHHAL_GetFrameNum() & 1 ) == 0;
+}
+
+/** @endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined( USB_HOST ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
+#endif /* __EM_USBH_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/inc/em_usbhal.h Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,757 @@
+/***************************************************************************//**
+ * @file em_usbhal.h
+ * @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.
+ *
+ ******************************************************************************/
+
+#ifndef __EM_USBHAL_H
+#define __EM_USBHAL_H
+
+#include "em_device.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "em_usb.h"
+#if defined( USB_DEVICE ) || defined( USB_HOST )
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#define USB_PID_DATA0 0
+#define USB_PID_DATA2 1
+#define USB_PID_DATA1 2
+#define USB_PID_SETUP 3
+
+#define HPRT_F_SPEED ( 1 << _USB_HPRT_PRTSPD_SHIFT )
+#define HPRT_L_SPEED ( 2 << _USB_HPRT_PRTSPD_SHIFT )
+#define HCFG_PHYCLK_48MHZ 1
+#define HCFG_PHYCLK_6MHZ 2
+
+#define DOEP0_XFERSIZE_PKTCNT_MASK ( _USB_DOEP0TSIZ_XFERSIZE_MASK | \
+ _USB_DOEP0TSIZ_PKTCNT_MASK )
+#define DOEP_XFERSIZE_PKTCNT_MASK ( _USB_DOEP_TSIZ_XFERSIZE_MASK | \
+ _USB_DOEP_TSIZ_PKTCNT_MASK )
+
+#define DIEP0_XFERSIZE_PKTCNT_MASK ( _USB_DIEP0TSIZ_XFERSIZE_MASK | \
+ _USB_DIEP0TSIZ_PKTCNT_MASK )
+#define DIEP_XFERSIZE_PKTCNT_MASK ( _USB_DIEP_TSIZ_XFERSIZE_MASK | \
+ _USB_DIEP_TSIZ_PKTCNT_MASK | \
+ _USB_DIEP_TSIZ_MC_MASK )
+
+#define DIEPCTL_EPTYPE_CONTROL (0 << _USB_DIEP_CTL_EPTYPE_SHIFT )
+#define DIEPCTL_EPTYPE_ISOC (1 << _USB_DIEP_CTL_EPTYPE_SHIFT )
+#define DIEPCTL_EPTYPE_BULK (2 << _USB_DIEP_CTL_EPTYPE_SHIFT )
+#define DIEPCTL_EPTYPE_INTR (3 << _USB_DIEP_CTL_EPTYPE_SHIFT )
+
+#define DOEPCTL_EPTYPE_CONTROL (0 << _USB_DOEP_CTL_EPTYPE_SHIFT )
+#define DOEPCTL_EPTYPE_ISOC (1 << _USB_DOEP_CTL_EPTYPE_SHIFT )
+#define DOEPCTL_EPTYPE_BULK (2 << _USB_DOEP_CTL_EPTYPE_SHIFT )
+#define DOEPCTL_EPTYPE_INTR (3 << _USB_DOEP_CTL_EPTYPE_SHIFT )
+
+#define HCCHAR_EPTYPE_CTRL (0 << _USB_HC_CHAR_EPTYPE_SHIFT )
+#define HCCHAR_EPTYPE_ISOC (1 << _USB_HC_CHAR_EPTYPE_SHIFT )
+#define HCCHAR_EPTYPE_BULK (2 << _USB_HC_CHAR_EPTYPE_SHIFT )
+#define HCCHAR_EPTYPE_INTR (3 << _USB_HC_CHAR_EPTYPE_SHIFT )
+
+#define GRXSTSP_PKTSTS_DEVICE_GOTNAK ( 1 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_DEVICE_DATAOUTRECEIVED ( 2 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_DEVICE_DATAOUTCOMPLETE ( 3 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_DEVICE_SETUPCOMPLETE ( 4 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_DEVICE_SETUPRECEIVED ( 6 << _USB_GRXSTSP_PKTSTS_SHIFT )
+
+#define GRXSTSP_PKTSTS_HOST_DATAINRECEIVED ( 2 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_HOST_DATAINCOMPLETE ( 3 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_HOST_DATATOGGLEERROR ( 5 << _USB_GRXSTSP_PKTSTS_SHIFT )
+#define GRXSTSP_PKTSTS_HOST_CHANNELHALTED ( 7 << _USB_GRXSTSP_PKTSTS_SHIFT )
+
+#define DCTL_WO_BITMASK \
+ ( _USB_DCTL_CGOUTNAK_MASK | _USB_DCTL_SGOUTNAK_MASK | \
+ _USB_DCTL_CGNPINNAK_MASK | _USB_DCTL_SGNPINNAK_MASK )
+#define GUSBCFG_WO_BITMASK ( USB_GUSBCFG_CORRUPTTXPKT )
+#define DEPCTL_WO_BITMASK \
+ ( USB_DIEP_CTL_CNAK | USB_DIEP_CTL_SNAK | \
+ USB_DIEP_CTL_SETD0PIDEF | USB_DIEP_CTL_SETD1PIDOF )
+
+#define HPRT_WC_MASK ( USB_HPRT_PRTCONNDET | USB_HPRT_PRTENA | \
+ USB_HPRT_PRTENCHNG | USB_HPRT_PRTOVRCURRCHNG )
+
+typedef __IO uint32_t USB_FIFO_TypeDef[ 0x1000 / sizeof( uint32_t ) ];
+typedef __IO uint32_t USB_DIEPTXF_TypeDef;
+
+#define USB_DINEPS ((USB_DIEP_TypeDef *) &USB->DIEP0CTL )
+#define USB_DOUTEPS ((USB_DOEP_TypeDef *) &USB->DOEP0CTL )
+#define USB_FIFOS ((USB_FIFO_TypeDef *) &USB->FIFO0D )
+#define USB_DIEPTXFS ((USB_DIEPTXF_TypeDef *) &USB->DIEPTXF1 )
+
+void USBHAL_CoreReset( void );
+
+#if defined( USB_DEVICE )
+void USBDHAL_AbortAllTransfers( USB_Status_TypeDef reason );
+USB_Status_TypeDef USBDHAL_CoreInit( const uint32_t totalRxFifoSize,
+ const uint32_t totalTxFifoSize );
+void USBDHAL_Connect( void );
+void USBDHAL_Disconnect( void );
+void USBDHAL_AbortAllEps( void );
+void USBDHAL_AbortEpIn( USBD_Ep_TypeDef *ep );
+void USBDHAL_AbortEpOut( USBD_Ep_TypeDef *ep );
+
+__STATIC_INLINE USB_Status_TypeDef USBDHAL_GetStallStatusEp(
+ USBD_Ep_TypeDef *ep, uint16_t *halt );
+__STATIC_INLINE uint32_t USBDHAL_GetInEpInts( USBD_Ep_TypeDef *ep );
+__STATIC_INLINE uint32_t USBDHAL_GetOutEpInts( USBD_Ep_TypeDef *ep );
+__STATIC_INLINE void USBDHAL_SetEPDISNAK( USBD_Ep_TypeDef *ep );
+#endif /* defined( USB_DEVICE ) */
+
+#if defined( USB_HOST )
+USB_Status_TypeDef USBHHAL_CoreInit( const uint32_t rxFifoSize,
+ const uint32_t nptxFifoSize,
+ const uint32_t ptxFifoSize );
+void USBHHAL_HCHalt( int hcnum, uint32_t hcchar );
+void USBHHAL_HCInit( int hcnum );
+void USBHHAL_HCStart( int hcnum );
+#endif /* defined( USB_HOST ) */
+
+__STATIC_INLINE void USBHAL_DisableGlobalInt( void )
+{
+ USB->GAHBCFG &= ~USB_GAHBCFG_GLBLINTRMSK;
+}
+
+__STATIC_INLINE void USBHAL_DisablePhyPins( void )
+{
+ USB->ROUTE = _USB_ROUTE_RESETVALUE;
+}
+
+__STATIC_INLINE void USBHAL_DisableUsbInt( void )
+{
+ USB->IEN = _USB_IEN_RESETVALUE;
+}
+
+__STATIC_INLINE void USBHAL_EnableGlobalInt( void )
+{
+ USB->GAHBCFG |= USB_GAHBCFG_GLBLINTRMSK;
+}
+
+__STATIC_INLINE void USBHAL_FlushRxFifo( void )
+{
+ USB->GRSTCTL = USB_GRSTCTL_RXFFLSH;
+ while ( USB->GRSTCTL & USB_GRSTCTL_RXFFLSH ) {}
+}
+
+__STATIC_INLINE void USBHAL_FlushTxFifo( uint8_t fifoNum )
+{
+ USB->GRSTCTL = USB_GRSTCTL_TXFFLSH | ( fifoNum << _USB_GRSTCTL_TXFNUM_SHIFT );
+ while ( USB->GRSTCTL & USB_GRSTCTL_TXFFLSH ) {}
+}
+
+__STATIC_INLINE uint32_t USBHAL_GetCoreInts( void )
+{
+ uint32_t retVal;
+
+ retVal = USB->GINTSTS;
+ retVal &= USB->GINTMSK;
+
+ return retVal;
+}
+
+__STATIC_INLINE bool USBHAL_VbusIsOn( void )
+{
+ return ( USB->STATUS & USB_STATUS_VREGOS ) != 0;
+}
+
+#if defined( USB_DEVICE )
+__STATIC_INLINE void USBDHAL_ActivateEp( USBD_Ep_TypeDef *ep, bool forceIdle )
+{
+#define DIEP_MPS_EPTYPE_TXFNUM_MASK ( _USB_DIEP_CTL_MPS_MASK | \
+ _USB_DIEP_CTL_EPTYPE_MASK | \
+ _USB_DIEP_CTL_TXFNUM_MASK )
+#define DOEP_MPS_EPTYPE_MASK ( _USB_DOEP_CTL_MPS_MASK | \
+ _USB_DOEP_CTL_EPTYPE_MASK )
+ uint32_t daintmask, depctl;
+
+ if ( forceIdle )
+ ep->state = D_EP_IDLE;
+
+ if ( ep->in )
+ {
+ daintmask = ep->mask;
+ depctl = USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
+
+ if ( !( depctl & USB_DIEP_CTL_USBACTEP ) )
+ {
+ depctl = ( depctl &
+ ~( DIEP_MPS_EPTYPE_TXFNUM_MASK |
+ USB_DIEP_CTL_STALL ) ) |
+ ( ep->packetSize << _USB_DIEP_CTL_MPS_SHIFT ) |
+ ( ep->type << _USB_DIEP_CTL_EPTYPE_SHIFT ) |
+ ( ep->txFifoNum << _USB_DIEP_CTL_TXFNUM_SHIFT ) |
+ USB_DIEP_CTL_SETD0PIDEF |
+ USB_DIEP_CTL_USBACTEP |
+ USB_DIEP_CTL_SNAK;
+ }
+ else
+ {
+ depctl |= USB_DIEP_CTL_SETD0PIDEF;
+ }
+ USB_DINEPS[ ep->num ].CTL = depctl;
+ }
+ else
+ {
+ daintmask = ep->mask << _USB_DAINTMSK_OUTEPMSK0_SHIFT;
+ depctl = USB_DOUTEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
+
+ if ( !( depctl & USB_DOEP_CTL_USBACTEP ) )
+ {
+ depctl = ( depctl &
+ ~( DOEP_MPS_EPTYPE_MASK |
+ USB_DOEP_CTL_STALL ) ) |
+ ( ep->packetSize << _USB_DOEP_CTL_MPS_SHIFT ) |
+ ( ep->type << _USB_DOEP_CTL_EPTYPE_SHIFT ) |
+ USB_DOEP_CTL_SETD0PIDEF |
+ USB_DOEP_CTL_USBACTEP |
+ USB_DOEP_CTL_SNAK;
+ }
+ else
+ {
+ depctl |= USB_DOEP_CTL_SETD0PIDEF;
+ }
+ USB_DOUTEPS[ ep->num ].CTL = depctl;
+ }
+
+ /* Enable interrupt for this EP */
+ USB->DAINTMSK |= daintmask;
+
+#undef DIEP_MPS_EPTYPE_TXFNUM_MASK
+#undef DOEP_MPS_EPTYPE_MASK
+}
+
+__STATIC_INLINE void USBDHAL_ClearRemoteWakeup( void )
+{
+ USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_RMTWKUPSIG );
+}
+
+__STATIC_INLINE void USBDHAL_DeactivateEp( USBD_Ep_TypeDef *ep )
+{
+ uint32_t daintmask;
+
+ if ( ep->in )
+ {
+ USB_DINEPS[ ep->num ].CTL = 0;
+ daintmask = ep->mask;
+ }
+ else
+ {
+ USB_DOUTEPS[ ep->num ].CTL = 0;
+ daintmask = ep->mask << _USB_DAINTMSK_OUTEPMSK0_SHIFT;
+ }
+
+ /* Disable interrupt for this EP */
+ USB->DAINTMSK &= ~daintmask;
+}
+
+__STATIC_INLINE void USBDHAL_EnableInts( USBD_Device_TypeDef *dev )
+{
+ uint32_t mask;
+
+ /* Disable all interrupts. */
+ USB->GINTMSK = 0;
+
+ /* Clear pending interrupts */
+ USB->GINTSTS = 0xFFFFFFFF;
+
+ mask = USB_GINTMSK_USBSUSPMSK |
+ USB_GINTMSK_USBRSTMSK |
+ USB_GINTMSK_ENUMDONEMSK |
+ USB_GINTMSK_IEPINTMSK |
+ USB_GINTMSK_OEPINTMSK |
+ USB_GINTMSK_WKUPINTMSK;
+
+ if ( dev->callbacks->sofInt )
+ {
+ mask |= USB_GINTMSK_SOFMSK;
+ }
+
+ USB->GINTMSK = mask;
+}
+
+__STATIC_INLINE void USBDHAL_EnableUsbResetAndSuspendInt( void )
+{
+ /* Disable all interrupts. */
+ USB->GINTMSK = 0;
+
+ USB->GINTMSK = USB_GINTMSK_USBRSTMSK | USB_GINTMSK_USBSUSPMSK;
+}
+
+__STATIC_INLINE void USBDHAL_Ep0Activate( uint32_t ep0mps )
+{
+ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGNPINNAK;
+
+ USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
+ | USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA
+ | ep0mps;
+}
+
+__STATIC_INLINE bool USBDHAL_EpIsStalled( USBD_Ep_TypeDef *ep )
+{
+ bool retVal = false;
+ uint16_t stallStatus;
+
+ if ( USBDHAL_GetStallStatusEp( ep, &stallStatus ) == USB_STATUS_OK )
+ {
+ retVal = stallStatus & 1 ? true : false;
+ }
+ return retVal;
+}
+
+__STATIC_INLINE uint32_t USBDHAL_GetAllInEpInts( void )
+{
+ uint32_t retVal;
+
+ retVal = USB->DAINT;
+ retVal &= USB->DAINTMSK;
+ return retVal & 0xFFFF;
+}
+
+__STATIC_INLINE uint32_t USBDHAL_GetAllOutEpInts( void )
+{
+ uint32_t retVal;
+
+ retVal = USB->DAINT;
+ retVal &= USB->DAINTMSK;
+ return retVal >> 16;
+}
+
+__STATIC_INLINE uint32_t USBDHAL_GetInEpInts( USBD_Ep_TypeDef *ep )
+{
+ uint32_t retVal, msk;
+
+ msk = USB->DIEPMSK;
+ retVal = USB_DINEPS[ ep->num ].INT;
+
+ return retVal & msk;
+}
+
+__STATIC_INLINE uint32_t USBDHAL_GetOutEpInts( USBD_Ep_TypeDef *ep )
+{
+ uint32_t retVal;
+
+ retVal = USB_DOUTEPS[ ep->num ].INT;
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+ retVal &= USB->DOEPMSK | USB_DOEP0INT_STUPPKTRCVD;
+#else
+ retVal &= USB->DOEPMSK;
+#endif
+
+ return retVal;
+}
+
+__STATIC_INLINE USB_Status_TypeDef USBDHAL_GetStallStatusEp(
+ USBD_Ep_TypeDef *ep, uint16_t *halt )
+{
+ uint32_t depctl, eptype;
+ USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
+
+ if ( ep->in == true )
+ {
+ depctl = USB_DINEPS[ ep->num ].CTL;
+ eptype = depctl & _USB_DIEP_CTL_EPTYPE_MASK;
+
+ if (( eptype == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_EPTYPE_BULK ))
+ {
+ *halt = depctl & USB_DIEP_CTL_STALL ? 1 : 0;
+ retVal = USB_STATUS_OK;
+ }
+ }
+ else
+ {
+ depctl = USB_DOUTEPS[ ep->num ].CTL;
+ eptype = depctl & _USB_DOEP_CTL_EPTYPE_MASK;
+
+ if (( eptype == DOEPCTL_EPTYPE_INTR ) || ( eptype == DOEPCTL_EPTYPE_BULK ))
+ {
+ *halt = depctl & USB_DOEP_CTL_STALL ? 1 : 0;
+ retVal = USB_STATUS_OK;
+ }
+ }
+
+ return retVal;
+}
+
+__STATIC_INLINE void USBDHAL_ReenableEp0Setup( USBD_Device_TypeDef *dev )
+
+{
+ USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
+ USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
+ | USB_DOEP0CTL_EPENA
+ | dev->ep0MpsCode;
+}
+
+__STATIC_INLINE void USBDHAL_SetAddr( uint8_t addr )
+{
+ USB->DCFG = ( USB->DCFG &
+ ~_USB_DCFG_DEVADDR_MASK ) |
+ (addr << _USB_DCFG_DEVADDR_SHIFT );
+}
+
+__STATIC_INLINE void USBDHAL_SetEp0InDmaPtr( uint8_t* addr )
+{
+ USB->DIEP0DMAADDR = (uint32_t)addr;
+}
+
+__STATIC_INLINE void USBDHAL_SetEp0OutDmaPtr( uint8_t* addr )
+{
+ USB->DOEP0DMAADDR = (uint32_t)addr;
+}
+
+__STATIC_INLINE void USBDHAL_SetEPDISNAK( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->in )
+ {
+ USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL &
+ ~DEPCTL_WO_BITMASK ) |
+ USB_DIEP_CTL_SNAK |
+ USB_DIEP_CTL_EPDIS;
+ }
+ else
+ {
+ USB_DOUTEPS[ ep->num ].CTL = ( USB_DOUTEPS[ ep->num ].CTL &
+ ~DEPCTL_WO_BITMASK ) |
+ USB_DOEP_CTL_EPENA;
+
+ USB_DOUTEPS[ ep->num ].CTL = ( USB_DOUTEPS[ ep->num ].CTL &
+ ~DEPCTL_WO_BITMASK ) |
+ USB_DOEP_CTL_SNAK |
+ USB_DOEP_CTL_EPDIS;
+ }
+}
+
+__STATIC_INLINE void USBDHAL_SetRemoteWakeup( void )
+{
+ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_RMTWKUPSIG;
+}
+
+__STATIC_INLINE USB_Status_TypeDef USBDHAL_StallEp( USBD_Ep_TypeDef *ep )
+{
+ uint32_t depctl, eptype;
+ USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
+
+ if ( ep->in == true )
+ {
+ depctl = USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
+ eptype = depctl & _USB_DIEP_CTL_EPTYPE_MASK;
+
+ if ( eptype != DIEPCTL_EPTYPE_ISOC )
+ {
+ if ( depctl & USB_DIEP_CTL_EPENA )
+ {
+ depctl |= USB_DIEP_CTL_EPDIS;
+ }
+ USB_DINEPS[ ep->num ].CTL = depctl | USB_DIEP_CTL_STALL;
+ retVal = USB_STATUS_OK;
+ }
+ }
+ else
+ {
+ depctl = USB_DOUTEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
+ eptype = depctl & _USB_DOEP_CTL_EPTYPE_MASK;
+
+ if ( eptype != DIEPCTL_EPTYPE_ISOC )
+ {
+ USB_DOUTEPS[ ep->num ].CTL = depctl | USB_DOEP_CTL_STALL;
+ retVal = USB_STATUS_OK;
+ }
+ }
+
+ return retVal;
+}
+
+__STATIC_INLINE void USBDHAL_StartEp0In( uint32_t len, uint32_t ep0mps )
+{
+ USB->DIEP0TSIZ = ( len << _USB_DIEP0TSIZ_XFERSIZE_SHIFT ) |
+ ( 1 << _USB_DIEP0TSIZ_PKTCNT_SHIFT );
+
+ USB->DIEP0CTL = ( USB->DIEP0CTL & ~DEPCTL_WO_BITMASK )
+ | USB_DIEP0CTL_CNAK | USB_DIEP0CTL_EPENA
+ | ep0mps;
+}
+
+__STATIC_INLINE void USBDHAL_StartEp0Out( uint32_t len, uint32_t ep0mps )
+{
+ USB->DOEP0TSIZ = ( len << _USB_DOEP0TSIZ_XFERSIZE_SHIFT ) |
+ ( 1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT );
+
+ USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
+ | USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA
+ | ep0mps;
+}
+
+__STATIC_INLINE void USBDHAL_StartEp0Setup( USBD_Device_TypeDef *dev )
+{
+ dev->ep[ 0 ].in = false;
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+ USB->DOEP0TSIZ = ( 8*3 << _USB_DOEP0TSIZ_XFERSIZE_SHIFT ) |
+ ( 1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT ) |
+ ( 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT );
+#else
+ USB->DOEP0TSIZ = 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
+#endif
+
+ dev->setup = dev->setupPkt;
+ USB->DOEP0DMAADDR = (uint32_t)dev->setup;
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+ USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
+ | USB_DOEP0CTL_EPENA
+ | dev->ep0MpsCode;
+#else
+ USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK )
+ | USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA
+ | dev->ep0MpsCode;
+#endif
+}
+
+__STATIC_INLINE void USBDHAL_StartEpIn( USBD_Ep_TypeDef *ep )
+{
+ uint32_t pktcnt, xfersize;
+
+ if ( ep->remaining == 0 ) /* ZLP ? */
+ {
+ pktcnt = 1;
+ xfersize = 0;
+ }
+ else
+ {
+ pktcnt = ( ep->remaining - 1 + ep->packetSize ) / ep->packetSize;
+ xfersize = ep->remaining;
+ }
+
+ USB_DINEPS[ ep->num ].TSIZ =
+ ( USB_DINEPS[ ep->num ].TSIZ &
+ ~DIEP_XFERSIZE_PKTCNT_MASK ) |
+ ( xfersize << _USB_DIEP_TSIZ_XFERSIZE_SHIFT ) |
+ ( pktcnt << _USB_DIEP_TSIZ_PKTCNT_SHIFT );
+
+ USB_DINEPS[ ep->num ].DMAADDR = (uint32_t)ep->buf;
+ USB_DINEPS[ ep->num ].CTL =
+ ( USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK ) |
+ USB_DIEP_CTL_CNAK |
+ USB_DIEP_CTL_EPENA;
+}
+
+__STATIC_INLINE void USBDHAL_StartEpOut( USBD_Ep_TypeDef *ep )
+{
+ uint32_t pktcnt, xfersize;
+
+ if ( ep->remaining == 0 ) /* ZLP ? */
+ {
+ pktcnt = 1;
+ xfersize = ep->packetSize;
+ }
+ else
+ {
+ pktcnt = ( ep->remaining - 1 + ep->packetSize ) / ep->packetSize;
+ xfersize = pktcnt * ep->packetSize;
+ }
+
+ USB_DOUTEPS[ ep->num ].TSIZ =
+ ( USB_DOUTEPS[ ep->num ].TSIZ &
+ ~DOEP_XFERSIZE_PKTCNT_MASK ) |
+ ( xfersize << _USB_DOEP_TSIZ_XFERSIZE_SHIFT ) |
+ ( pktcnt << _USB_DOEP_TSIZ_PKTCNT_SHIFT );
+
+ ep->hwXferSize = xfersize;
+ USB_DOUTEPS[ ep->num ].DMAADDR = (uint32_t)ep->buf;
+ USB_DOUTEPS[ ep->num ].CTL =
+ ( USB_DOUTEPS[ ep->num ].CTL &
+ ~DEPCTL_WO_BITMASK ) |
+ USB_DOEP_CTL_CNAK |
+ USB_DOEP_CTL_EPENA;
+}
+
+__STATIC_INLINE USB_Status_TypeDef USBDHAL_UnStallEp( USBD_Ep_TypeDef *ep )
+{
+ uint32_t depctl, eptype;
+ USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
+
+ if ( ep->in == true )
+ {
+ depctl = USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
+ eptype = depctl & _USB_DIEP_CTL_EPTYPE_MASK;
+
+ if (( eptype == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_EPTYPE_BULK ))
+ {
+ depctl |= USB_DIEP_CTL_SETD0PIDEF;
+ depctl &= ~USB_DIEP_CTL_STALL;
+ USB_DINEPS[ ep->num ].CTL = depctl;
+ retVal = USB_STATUS_OK;
+ }
+ }
+ else
+ {
+ depctl = USB_DOUTEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK;
+ eptype = depctl & _USB_DOEP_CTL_EPTYPE_MASK;
+
+ if (( eptype == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_EPTYPE_BULK ))
+ {
+ depctl |= USB_DOEP_CTL_SETD0PIDEF;
+ depctl &= ~USB_DOEP_CTL_STALL;
+ USB_DOUTEPS[ ep->num ].CTL = depctl;
+ retVal = USB_STATUS_OK;
+ }
+ }
+
+ return retVal;
+}
+#endif /* defined( USB_DEVICE ) */
+
+#if defined( USB_HOST )
+__STATIC_INLINE void USBHHAL_HCActivate( int hcnum, uint32_t hcchar, bool intep )
+{
+ uint32_t oddframe;
+
+ if ( intep )
+ {
+ oddframe = USB->HFNUM & 1;
+
+ USB->HC[ hcnum ].CHAR =
+ ( hcchar &
+ ~( USB_HC_CHAR_CHDIS | _USB_HC_CHAR_ODDFRM_MASK ) ) |
+
+ /* Schedule INT transfers to start in next frame. */
+ ( oddframe & 1 ? 0 : USB_HC_CHAR_ODDFRM ) |
+
+ USB_HC_CHAR_CHENA;
+ }
+ else
+ {
+ USB->HC[ hcnum ].CHAR = ( hcchar & ~USB_HC_CHAR_CHDIS ) |
+ USB_HC_CHAR_CHENA;
+ }
+}
+
+__STATIC_INLINE bool USBHHAL_InitializedAndPowered( void )
+{
+ if ( ( USB->ROUTE & USB_ROUTE_PHYPEN ) &&
+ ( USB->HPRT & USB_HPRT_PRTPWR ) )
+ return true;
+ return false;
+}
+
+__STATIC_INLINE void USBHHAL_EnableInts( void )
+{
+ /* Disable all interrupts. */
+ USB->GINTMSK = 0;
+
+ /* Clear pending OTG interrupts */
+ USB->GOTGINT = 0xFFFFFFFF;
+
+ /* Clear pending interrupts */
+ USB->GINTSTS = 0xFFFFFFFF;
+
+ USB->GINTMSK = USB_GINTMSK_PRTINTMSK |
+ USB_GINTMSK_HCHINTMSK |
+ USB_GINTMSK_DISCONNINTMSK;
+}
+
+__STATIC_INLINE uint16_t USBHHAL_GetFrameNum( void )
+{
+ return USB->HFNUM;
+}
+
+__STATIC_INLINE uint32_t USBHHAL_GetHcChar( uint8_t hcnum )
+{
+ return USB->HC[ hcnum ].CHAR;
+}
+
+__STATIC_INLINE uint32_t USBHHAL_GetHcInts( uint8_t hcnum )
+{
+ uint32_t retVal;
+
+ retVal = USB->HC[ hcnum ].INT;
+ return retVal;
+}
+
+__STATIC_INLINE uint32_t USBHHAL_GetHostChannelInts( void )
+{
+ return USB->HAINT;
+}
+
+__STATIC_INLINE uint8_t USBHHAL_GetPortSpeed( void )
+{
+ return ( USB->HPRT & _USB_HPRT_PRTSPD_MASK ) >> _USB_HPRT_PRTSPD_SHIFT;
+}
+
+__STATIC_INLINE void USBHHAL_PortReset( bool on )
+{
+ if ( on )
+ {
+ DEBUG_USB_INT_LO_PUTCHAR( '+' );
+ USB->HPRT = ( USB->HPRT & ~HPRT_WC_MASK ) | USB_HPRT_PRTRST;
+ }
+ else
+ {
+ DEBUG_USB_INT_LO_PUTCHAR( '-' );
+ USB->HPRT &= ~( HPRT_WC_MASK | USB_HPRT_PRTRST );
+ }
+}
+
+__STATIC_INLINE void USBHHAL_PortResume( bool on )
+{
+ if ( on )
+ {
+ USB->HPRT = ( USB->HPRT & ~( HPRT_WC_MASK | USB_HPRT_PRTSUSP ) ) |
+ USB_HPRT_PRTRES;
+ }
+ else
+ {
+ USB->HPRT &= ~( HPRT_WC_MASK | USB_HPRT_PRTSUSP | USB_HPRT_PRTRES );
+ }
+}
+
+__STATIC_INLINE void USBHHAL_PortSuspend( void )
+{
+ USB->HPRT = ( USB->HPRT & ~HPRT_WC_MASK ) | USB_HPRT_PRTSUSP;
+}
+
+__STATIC_INLINE void USBHHAL_VbusOn( bool on )
+{
+ if ( on )
+ {
+ USB->HPRT = ( USB->HPRT & ~HPRT_WC_MASK ) | USB_HPRT_PRTPWR;
+ DEBUG_USB_INT_LO_PUTCHAR( '/' );
+ }
+ else
+ {
+ USB->HPRT &= ~( HPRT_WC_MASK | USB_HPRT_PRTPWR );
+ DEBUG_USB_INT_LO_PUTCHAR( '\\' );
+ }
+}
+#endif /* defined( USB_HOST ) */
+
+/** @endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
+#endif /* __EM_USBHAL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/inc/em_usbtypes.h Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,230 @@
+/***************************************************************************//**
+ * @file em_usbtypes.h
+ * @brief USB protocol stack library, internal type definitions.
+ * @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.
+ *
+ ******************************************************************************/
+
+#ifndef __EM_USBTYPES_H
+#define __EM_USBTYPES_H
+
+#include "em_device.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "em_usb.h"
+#if defined( USB_DEVICE ) || defined( USB_HOST )
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/* Limits imposed by the USB peripheral */
+#define NP_RX_QUE_DEPTH 8
+#define HP_RX_QUE_DEPTH 8
+#define MAX_XFER_LEN 524287L /* 2^19 - 1 bytes */
+#define MAX_PACKETS_PR_XFER 1023 /* 2^10 - 1 packets */
+#if defined( _USB_DIEPTXF6_MASK )
+ #define MAX_NUM_TX_FIFOS 6 /* In addition to EP0 Tx FIFO */
+ #define MAX_NUM_IN_EPS 6 /* In addition to EP0 */
+ #define MAX_NUM_OUT_EPS 6 /* In addition to EP0 */
+ #define MAX_DEVICE_FIFO_SIZE_INWORDS 512U
+#else
+ #define MAX_NUM_TX_FIFOS 3 /* In addition to EP0 Tx FIFO */
+ #define MAX_NUM_IN_EPS 3 /* In addition to EP0 */
+ #define MAX_NUM_OUT_EPS 3 /* In addition to EP0 */
+ #define MAX_DEVICE_FIFO_SIZE_INWORDS 384U
+#endif
+#define MIN_EP_FIFO_SIZE_INWORDS 16U /* Unit is words (32bit) */
+#define MIN_EP_FIFO_SIZE_INBYTES 64U /* Unit is bytes (8bit) */
+
+/* For MCU's without USB host capability. */
+#if !defined( USB_ROUTE_VBUSENPEN )
+#define USB_VBUS_SWITCH_NOT_PRESENT
+#endif
+
+/* Limit imposed by the USB standard */
+#define MAX_USB_EP_NUM 15
+
+#if defined( USB_DEVICE )
+ /* Check power saving modes. */
+ #ifndef USB_PWRSAVE_MODE
+ /* Default powersave-mode is OFF. */
+ #define USB_PWRSAVE_MODE USB_PWRSAVE_MODE_OFF
+ #else
+ #if ( USB_PWRSAVE_MODE & \
+ ~( USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF | \
+ USB_PWRSAVE_MODE_ENTEREM2 ) )
+ #error "Illegal USB powersave mode."
+ #endif
+ #endif /* ifndef USB_PWRSAVE_MODE */
+
+ /* Check power saving low frequency clock selection. */
+ #ifndef USB_USBC_32kHz_CLK
+ /* Default clock source is LFXO. */
+ #define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO
+ #else
+ #if ( ( USB_USBC_32kHz_CLK != USB_USBC_32kHz_CLK_LFXO ) && \
+ ( USB_USBC_32kHz_CLK != USB_USBC_32kHz_CLK_LFRCO ) )
+ #error "Illegal USB 32kHz powersave clock selection."
+ #endif
+ #endif /* ifndef USB_USBC_32kHz_CLK */
+#endif /* defined( USB_DEVICE ) */
+
+#if defined( USB_HOST )
+ /* Check VBUS overcurrent definitions. */
+ #ifndef USB_VBUSOVRCUR_PORT
+ #define USB_VBUSOVRCUR_PORT gpioPortE
+ #define USB_VBUSOVRCUR_PIN 2
+ #define USB_VBUSOVRCUR_POLARITY USB_VBUSOVRCUR_POLARITY_LOW
+ #endif
+#endif
+
+/* Developer mode debugging macro's */
+#if defined( DEBUG_USB_INT_LO )
+ #define DEBUG_USB_INT_LO_PUTS( s ) USB_PUTS( s )
+ #define DEBUG_USB_INT_LO_PUTCHAR( c ) USB_PUTCHAR( c )
+#else
+ #define DEBUG_USB_INT_LO_PUTS( s )
+ #define DEBUG_USB_INT_LO_PUTCHAR( c )
+#endif /* defined( DEBUG_USB_INT_LO ) */
+
+#if defined( DEBUG_USB_INT_HI )
+ #define DEBUG_USB_INT_HI_PUTS( s ) USB_PUTS( s )
+ #define DEBUG_USB_INT_HI_PUTCHAR( c ) USB_PUTCHAR( c )
+#else
+ #define DEBUG_USB_INT_HI_PUTS( s )
+ #define DEBUG_USB_INT_HI_PUTCHAR( c )
+#endif /* defined( DEBUG_USB_INT_HI ) */
+
+#if defined( USB_HOST )
+ #if defined( NUM_APP_TIMERS )
+ #define HOSTPORT_TIMER_INDEX (NUM_APP_TIMERS)
+ #else
+ #define HOSTPORT_TIMER_INDEX (0)
+ #endif
+ #define HOSTCH_TIMER_INDEX (HOSTPORT_TIMER_INDEX + 1 )
+#endif
+
+/* Macros for selecting a hardware timer. */
+#define USB_TIMER0 0
+#define USB_TIMER1 1
+#define USB_TIMER2 2
+#define USB_TIMER3 3
+
+#if defined( USB_HOST )
+#define HCS_NAK 0x01
+#define HCS_STALL 0x02
+#define HCS_XACT 0x04
+#define HCS_TGLERR 0x08
+#define HCS_BABBLE 0x10
+#define HCS_TIMEOUT 0x20
+#define HCS_COMPLETED 0x40
+#define HCS_RETRY 0x80
+#endif
+
+#if defined( USB_DEVICE )
+typedef enum
+{
+ D_EP_IDLE = 0,
+ D_EP_TRANSMITTING = 1,
+ D_EP_RECEIVING = 2,
+ D_EP0_IN_STATUS = 3,
+ D_EP0_OUT_STATUS = 4
+} USBD_EpState_TypeDef;
+
+typedef struct
+{
+ bool in;
+ uint8_t zlp;
+ uint8_t num;
+ uint8_t addr;
+ uint8_t type;
+ uint8_t txFifoNum;
+ uint8_t *buf;
+ uint16_t packetSize;
+ uint16_t mask;
+ uint32_t remaining;
+ uint32_t xferred;
+ uint32_t hwXferSize;
+ uint32_t fifoSize;
+ USBD_EpState_TypeDef state;
+ USB_XferCompleteCb_TypeDef xferCompleteCb;
+} USBD_Ep_TypeDef;
+
+typedef struct
+{
+ USB_Setup_TypeDef *setup;
+ USB_Setup_TypeDef setupPkt[3];
+ uint8_t configurationValue; /* Must be DWORD aligned */
+ bool remoteWakeupEnabled;
+ uint8_t numberOfStrings;
+ uint8_t numberOfInterfaces;
+ USBD_State_TypeDef state;
+ USBD_State_TypeDef savedState;
+ USBD_State_TypeDef lastState;
+ const USB_DeviceDescriptor_TypeDef *deviceDescriptor;
+ const USB_ConfigurationDescriptor_TypeDef *configDescriptor;
+ const void * const *stringDescriptors;
+ const USBD_Callbacks_TypeDef *callbacks;
+ USBD_Ep_TypeDef ep[ NUM_EP_USED + 1 ];
+ uint8_t inEpAddr2EpIndex[ MAX_USB_EP_NUM + 1 ];
+ uint8_t outEpAddr2EpIndex[ MAX_USB_EP_NUM + 1 ];
+ uint32_t ep0MpsCode;
+} USBD_Device_TypeDef;
+#endif /* defined( USB_DEVICE ) */
+
+#if defined( USB_HOST )
+typedef enum
+{
+ H_PORT_DISCONNECTED = 0,
+ H_PORT_CONNECTED_DEBOUNCING = 1,
+ H_PORT_CONNECTED_RESETTING = 2,
+ H_PORT_CONNECTED = 3,
+ H_PORT_OVERCURRENT = 4
+} USBH_PortState_TypeDef;
+
+typedef struct
+{
+ int debounceTime;
+ int resetTime;
+} USBH_AttachTiming_TypeDef;
+
+typedef struct
+{
+ uint8_t *buf;
+ int errorCnt;
+ uint32_t remaining;
+ uint32_t xferred;
+ uint32_t hwXferSize;
+ uint8_t status;
+ bool idle;
+ USBH_Ep_TypeDef *ep;
+} USBH_Hc_TypeDef;
+#endif /* defined( USB_HOST ) */
+
+/** @endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
+#endif /* __EM_USBTYPES_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/inc/usbconfig.h Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,88 @@
+/***************************************************************************//**
+ * @file usbconfig.h
+ * @brief USB protocol stack library, application supplied configuration options.
+ * @version 3.20.12
+ *******************************************************************************
+ * @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.
+ *
+ ******************************************************************************/
+
+#ifndef __USBCONFIG_H
+#define __USBCONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Compile stack for device mode. */
+#define USB_DEVICE
+
+/* Maximum number of endpoint used, EP0 excluded. If you change this, you must
+ also change USBEndpoints_EFM32.h to match. */
+#define NUM_EP_USED 6
+
+/* Power management modes. The following can be or'd toghether. See comments in
+ em_usbd.c under "Energy-saving modes" for more details.
+
+ USB_PWRSAVE_MODE_ONSUSPEND Set USB peripheral in low power mode on suspend
+
+ USB_PWRSAVE_MODE_ONVBUSOFF Set USB peripheral in low power mode when not
+ attached to a host. While this mode assumes that the internal voltage regulator
+ is used and that the VREGI pin of the chip is connected to VBUS it should
+ be safe to use given that VREGOSEN is always enabled. If you disable VREGOSEN
+ you must turn this off.
+
+ USB_PWRSAVE_MODE_ENTEREM2 Enter EM2 when USB peripheral is in low power mode.
+ On Mbed this allows the sleep() and deepsleep() calls to enter EM2, but
+ does not automatically enter any sleep states. Entering EM1 is always allowed.
+
+ Note for Happy Gecko, errata USB_E111: Entering EM2 when both the system clock
+ (HFCLK) and the USB core clock (USBCCLK) is running on USHFRCO will result in
+ a lock-up.
+*/
+#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND|USB_PWRSAVE_MODE_ONVBUSOFF|USB_PWRSAVE_MODE_ENTEREM2)
+
+/* Use dynamic memory to allocate rx/tx buffers in the HAL. Saves memory
+ as buffers are only allocated for used endpoints. The system malloc
+ must return memory that is aligned by 4.
+
+ Note: if you disable this, using isochronous endpoints with packet
+ sizes that are larger than the maximum for other EP types (64) will
+ not work. */
+#define USB_USE_DYNAMIC_MEMORY
+
+/* When the USB peripheral is set in low power mode, it must be clocked by a 32kHz
+ clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification
+ compliance. */
+#define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO
+
+/* Uncomment to get some debugging information. Default value for USER_PUTCHAR
+ should work for SiLabs Gecko boards. Printf requires a working retarget
+ implementation for write(). */
+//#define DEBUG_USB_API
+//#define USB_USE_PRINTF
+//#define USER_PUTCHAR ITM_SendChar
+//#define DEBUG_USB_INT_HI
+//#define DEBUG_USB_INT_LO
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBCONFIG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/src/em_usbd.c Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,1438 @@
+/**************************************************************************//**
+ * @file em_usbd.c
+ * @brief USB protocol stack library, device API.
+ * @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 )
+
+#include "em_cmu.h"
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+#include "em_usbd.h"
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+static USBD_Device_TypeDef device;
+USBD_Device_TypeDef *dev = &device;
+
+static uint32_t totalRxFifoSize = 0, totalTxFifoSize = 0;
+static int numEps = 0;
+static int txFifoNum = 1;
+
+static void USBD_ResetEndpoints(void);
+extern USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize,
+ uint32_t totalTxFifoSize );
+#ifndef __MBED__
+static const char *stateNames[] =
+{
+ [ USBD_STATE_NONE ] = "NONE ",
+ [ USBD_STATE_ATTACHED ] = "ATTACHED ",
+ [ USBD_STATE_POWERED ] = "POWERED ",
+ [ USBD_STATE_DEFAULT ] = "DEFAULT ",
+ [ USBD_STATE_ADDRESSED ] = "ADDRESSED ",
+ [ USBD_STATE_CONFIGURED ] = "CONFIGURED",
+ [ USBD_STATE_SUSPENDED ] = "SUSPENDED ",
+ [ USBD_STATE_LASTMARKER ] = "UNDEFINED "
+};
+#endif
+
+/** @endcond */
+
+/***************************************************************************//**
+ * @brief
+ * Abort all pending transfers.
+ *
+ * @details
+ * Aborts transfers for all endpoints currently in use. Pending
+ * transfers on the default endpoint (EP0) are not aborted.
+ ******************************************************************************/
+void USBD_AbortAllTransfers( void )
+{
+ INT_Disable();
+ USBDHAL_AbortAllTransfers( USB_STATUS_EP_ABORTED );
+ INT_Enable();
+}
+
+/***************************************************************************//**
+ * @brief
+ * Abort a pending transfer on a specific endpoint.
+ *
+ * @param[in] epAddr
+ * The address of the endpoint to abort.
+ ******************************************************************************/
+int USBD_AbortTransfer( int epAddr )
+{
+ USB_XferCompleteCb_TypeDef callback;
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ if ( ep == NULL )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( ep->num == 0 )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ INT_Disable();
+ if ( ep->state == D_EP_IDLE )
+ {
+ INT_Enable();
+ return USB_STATUS_OK;
+ }
+
+ USBD_AbortEp( ep );
+
+ 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( USB_STATUS_EP_ABORTED );
+ callback( USB_STATUS_EP_ABORTED, ep->xferred, ep->remaining );
+ }
+
+ INT_Enable();
+ return USB_STATUS_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Start USB device operation.
+ *
+ * @details
+ * Device operation is started by connecting a pullup resistor on the
+ * appropriate USB data line.
+ ******************************************************************************/
+void USBD_Connect( void )
+{
+ INT_Disable();
+ USBDHAL_Connect();
+ INT_Enable();
+}
+
+/***************************************************************************//**
+ * @brief
+ * Stop USB device operation.
+ *
+ * @details
+ * Device operation is stopped by disconnecting the pullup resistor from the
+ * appropriate USB data line. Often referred to as a "soft" disconnect.
+ ******************************************************************************/
+void USBD_Disconnect( void )
+{
+ INT_Disable();
+ USBDHAL_Disconnect();
+ INT_Enable();
+}
+
+/***************************************************************************//**
+ * @brief
+ * Check if an endpoint is busy doing a transfer.
+ *
+ * @param[in] epAddr
+ * The address of the endpoint to check.
+ *
+ * @return
+ * True if endpoint is busy, false otherwise.
+ ******************************************************************************/
+bool USBD_EpIsBusy( int epAddr )
+{
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ if ( ep == NULL )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_EpIsBusy(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( ep->state == D_EP_IDLE )
+ return false;
+
+ return true;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get current USB device state.
+ *
+ * @return
+ * Device USB state. See @ref USBD_State_TypeDef.
+ ******************************************************************************/
+USBD_State_TypeDef USBD_GetUsbState( void )
+{
+ return dev->state;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get a string naming a device USB state.
+ *
+ * @param[in] state
+ * Device USB state. See @ref USBD_State_TypeDef.
+ *
+ * @return
+ * State name string pointer.
+ ******************************************************************************/
+const char *USBD_GetUsbStateName( USBD_State_TypeDef state )
+{
+ if ( state > USBD_STATE_LASTMARKER )
+ state = USBD_STATE_LASTMARKER;
+
+#ifndef __MBED__
+ return stateNames[ state ];
+#else
+ return NULL;
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Initializes USB device hardware and internal protocol stack data structures,
+ * then connects the data-line (D+ or D-) pullup resistor to signal host that
+ * enumeration can begin.
+ *
+ * @note
+ * You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force
+ * reenumeration.
+ *
+ * @param[in] p
+ * Pointer to device initialization struct. See @ref USBD_Init_TypeDef.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_Init( const USBD_Init_TypeDef *p )
+{
+ USBD_Ep_TypeDef *ep;
+
+#if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
+ /* Devices supporting crystal-less USB can use HFRCO or HFXO as core clock. */
+ /* All other devices must use HFXO as core clock. */
+ if ( CMU_ClockSelectGet( cmuClock_HF ) != cmuSelect_HFXO )
+ {
+ CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
+ }
+#endif
+
+#if !defined( CMU_OSCENCMD_USHFRCOEN )
+#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, false);
+#else
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, false);
+#endif
+
+#else
+ CMU_ClockEnable(cmuClock_CORELE, true);
+ /* LFC clock is needed to detect USB suspend when LEMIDLE is activated. */
+#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
+ CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFXO);
+#else
+ CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFRCO);
+#endif
+ CMU_ClockEnable(cmuClock_USBLE, true);
+#endif
+
+ USBTIMER_Init();
+
+ memset( dev, 0, sizeof( USBD_Device_TypeDef ) );
+
+ dev->setup = dev->setupPkt;
+ dev->state = USBD_STATE_LASTMARKER;
+ dev->savedState = USBD_STATE_NONE;
+ dev->lastState = USBD_STATE_NONE;
+ dev->callbacks = p->callbacks;
+ dev->remoteWakeupEnabled = false;
+
+ /* Initialize EP0 */
+
+ ep = &dev->ep[ 0 ];
+ ep->in = false;
+ ep->buf = NULL;
+ ep->num = 0;
+ ep->mask = 1;
+ ep->addr = 0;
+ ep->type = USB_EPTYPE_CTRL;
+ ep->txFifoNum = 0;
+
+ /* FIXME! */
+ ep->packetSize = 64;
+ dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B;
+
+ ep->remaining = 0;
+ ep->xferred = 0;
+ ep->state = D_EP_IDLE;
+ ep->xferCompleteCb = NULL;
+ ep->fifoSize = ep->packetSize / 4;
+
+ totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ];
+ totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ];
+
+ /* Rx-FIFO size: SETUP packets : 4*n + 6 n=#CTRL EP's
+ * GOTNAK : 1
+ * Status info : 2*n n=#OUT EP's (EP0 included) in HW
+ */
+ totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );
+
+ INT_Disable();
+
+ /* Enable USB clock */
+ CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC;
+
+#if defined( CMU_OSCENCMD_USHFRCOEN )
+ CMU->USHFRCOCONF = CMU_USHFRCOCONF_BAND_48MHZ;
+ CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_USHFRCO );
+
+ /* Enable USHFRCO Clock Recovery mode. */
+ CMU->USBCRCTRL |= CMU_USBCRCTRL_EN;
+
+ /* Turn on Low Energy Mode (LEM) features. */
+ USB->CTRL = USB_CTRL_LEMOSCCTRL_GATE
+ | USB_CTRL_LEMIDLEEN
+ | USB_CTRL_LEMPHYCTRL;
+#else
+ CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );
+#endif
+
+ USBHAL_DisableGlobalInt();
+
+ if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK )
+ {
+ USBDHAL_EnableUsbResetAndSuspendInt();
+ USBHAL_EnableGlobalInt();
+ NVIC_ClearPendingIRQ( USB_IRQn );
+ NVIC_EnableIRQ( USB_IRQn );
+ }
+ else
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Init(), FIFO setup error" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
+ if ( USBHAL_VbusIsOn() )
+ {
+ USBD_SetUsbState( USBD_STATE_POWERED );
+ }
+ else
+#endif
+ {
+ USBD_SetUsbState( USBD_STATE_NONE );
+ }
+
+ INT_Enable();
+ return USB_STATUS_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Start a read (OUT) transfer on an endpoint.
+ *
+ * @note
+ * The transfer buffer length must be a multiple of 4 bytes in length and
+ * WORD (4 byte) aligned. When allocating the buffer, round buffer length up.
+ * If it is possible that the host will send more data than your device
+ * expects, round buffer size up to the next multiple of maxpacket size.
+ *
+ * @param[in] epAddr
+ * Endpoint address.
+ *
+ * @param[in] data
+ * Pointer to transfer data buffer.
+ *
+ * @param[in] byteCount
+ * Transfer length.
+ *
+ * @param[in] callback
+ * Function to be called on transfer completion. Supply NULL if no callback
+ * is needed. See @ref USB_XferCompleteCb_TypeDef.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_Read( int epAddr, void *data, int byteCount,
+ USB_XferCompleteCb_TypeDef callback )
+{
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ USB_PRINTF("USBD: Read addr %x, data %p, size %d, cb 0x%lx\n",
+ epAddr, data, byteCount, (uint32_t)callback);
+
+ if ( ep == NULL )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( ( byteCount > MAX_XFER_LEN ) ||
+ ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal transfer size" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( (uint32_t)data & 3 )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Misaligned data buffer" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ INT_Disable();
+ if ( USBDHAL_EpIsStalled( ep ) )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is halted" );
+ return USB_STATUS_EP_STALLED;
+ }
+
+ if ( ep->state != D_EP_IDLE )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is busy" );
+ return USB_STATUS_EP_BUSY;
+ }
+
+ if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Device not configured" );
+ return USB_STATUS_DEVICE_UNCONFIGURED;
+ }
+
+ ep->buf = (uint8_t*)data;
+ ep->remaining = byteCount;
+ ep->xferred = 0;
+
+ if ( ep->num == 0 )
+ {
+ ep->in = false;
+ }
+ else if ( ep->in != false )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal EP direction" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ ep->state = D_EP_RECEIVING;
+ ep->xferCompleteCb = callback;
+
+ USBD_ArmEp( ep );
+ INT_Enable();
+ return USB_STATUS_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Perform a remote wakeup signalling sequence.
+ *
+ * @note
+ * It is the responsibility of the application to ensure that remote wakeup
+ * is not attempted before the device has been suspended for at least 5
+ * miliseconds. This function should not be called from within an interrupt
+ * handler.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_RemoteWakeup( void )
+{
+ INT_Disable();
+
+ if ( ( dev->state != USBD_STATE_SUSPENDED ) ||
+ ( dev->remoteWakeupEnabled == false ) )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_RemoteWakeup(), Illegal remote wakeup" );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ USBDHAL_SetRemoteWakeup();
+ INT_Enable();
+ USBTIMER_DelayMs( 10 );
+ INT_Disable();
+ USBDHAL_ClearRemoteWakeup();
+ INT_Enable();
+ return USB_STATUS_OK;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Check if it is ok to enter energy mode EM2.
+ *
+ * @note
+ * Before entering EM2 both the USB hardware and the USB stack must be in a
+ * certain state, this function checks if all conditions for entering EM2
+ * is met.
+ * Refer to the @ref usb_device_powersave section for more information.
+ *
+ * @return
+ * True if ok to enter EM2, false otherwise.
+ ******************************************************************************/
+bool USBD_SafeToEnterEM2( void )
+{
+#if ( USB_PWRSAVE_MODE )
+ return USBD_poweredDown ? true : false;
+#else
+ return false;
+#endif
+}
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+void USBD_SetUsbState( USBD_State_TypeDef newState )
+{
+ USBD_State_TypeDef currentState;
+
+ currentState = dev->state;
+ if ( newState == USBD_STATE_SUSPENDED )
+ {
+ dev->savedState = currentState;
+ }
+
+ dev->lastState = dev->state;
+ dev->state = newState;
+
+ if ( ( dev->callbacks->usbStateChange ) &&
+ ( currentState != newState ) )
+ {
+ /* When we transition to a state "lower" than CONFIGURED
+ * we must reset the endpoint data
+ */
+ if ( (dev->lastState == USBD_STATE_CONFIGURED ||
+ dev->lastState == USBD_STATE_SUSPENDED ) &&
+ dev->state < USBD_STATE_CONFIGURED )
+ {
+ USBD_ResetEndpoints();
+ }
+
+ dev->callbacks->usbStateChange( currentState, newState );
+ }
+}
+
+/** @endcond */
+
+/***************************************************************************//**
+ * @brief
+ * Set an endpoint in the stalled (halted) state.
+ *
+ * @param[in] epAddr
+ * The address of the endpoint to stall.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_StallEp( int epAddr )
+{
+ USB_Status_TypeDef retVal;
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ if ( ep == NULL )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal request" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( ep->num == 0 )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ INT_Disable();
+ retVal = USBDHAL_StallEp( ep );
+ INT_Enable();
+
+ if ( retVal != USB_STATUS_OK )
+ {
+ retVal = USB_STATUS_ILLEGAL;
+ }
+
+ return retVal;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Stop USB device stack operation.
+ *
+ * @details
+ * The data-line pullup resistor is turned off, USB interrupts are disabled,
+ * and finally the USB pins are disabled.
+ ******************************************************************************/
+void USBD_Stop( void )
+{
+ USBD_Disconnect();
+ NVIC_DisableIRQ( USB_IRQn );
+ USBHAL_DisableGlobalInt();
+ USBHAL_DisableUsbInt();
+ USBHAL_DisablePhyPins();
+ USBD_SetUsbState( USBD_STATE_NONE );
+ /* Turn off USB clocks. */
+ CMU->HFCORECLKEN0 &= ~(CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Reset stall state on a stalled (halted) endpoint.
+ *
+ * @param[in] epAddr
+ * The address of the endpoint to un-stall.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_UnStallEp( int epAddr )
+{
+ USB_Status_TypeDef retVal;
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ if ( ep == NULL )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal request" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( ep->num == 0 )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ INT_Disable();
+ retVal = USBDHAL_UnStallEp( ep );
+ INT_Enable();
+
+ if ( retVal != USB_STATUS_OK )
+ {
+ retVal = USB_STATUS_ILLEGAL;
+ }
+
+ return retVal;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Start a write (IN) transfer on an endpoint.
+ *
+ * @param[in] epAddr
+ * Endpoint address.
+ *
+ * @param[in] data
+ * Pointer to transfer data buffer. This buffer must be WORD (4 byte) aligned.
+ *
+ * @param[in] byteCount
+ * Transfer length.
+ *
+ * @param[in] callback
+ * Function to be called on transfer completion. Supply NULL if no callback
+ * is needed. See @ref USB_XferCompleteCb_TypeDef.
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_Write( int epAddr, void *data, int byteCount,
+ USB_XferCompleteCb_TypeDef callback )
+{
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ USB_PRINTF("USBD: Write addr %x, data %p, size %d, cb 0x%lx\n",
+ epAddr, data, byteCount, (uint32_t)callback);
+
+ if ( ep == NULL )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal endpoint" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( ( byteCount > MAX_XFER_LEN ) ||
+ ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal transfer size" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ if ( (uint32_t)data & 3 )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Misaligned data buffer" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ INT_Disable();
+ if ( USBDHAL_EpIsStalled( ep ) )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is halted" );
+ return USB_STATUS_EP_STALLED;
+ }
+
+ if ( ep->state != D_EP_IDLE )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is busy" );
+ return USB_STATUS_EP_BUSY;
+ }
+
+ if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Device not configured" );
+ return USB_STATUS_DEVICE_UNCONFIGURED;
+ }
+
+ ep->buf = (uint8_t*)data;
+ ep->remaining = byteCount;
+ ep->xferred = 0;
+
+ if ( ep->num == 0 )
+ {
+ ep->in = true;
+ }
+ else if ( ep->in != true )
+ {
+ INT_Enable();
+ DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal EP direction" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+
+ ep->state = D_EP_TRANSMITTING;
+ ep->xferCompleteCb = callback;
+
+ USBD_ArmEp( ep );
+ INT_Enable();
+ return USB_STATUS_OK;
+}
+
+int USBD_SetAddress(uint8_t addr)
+{
+ int retVal = USB_STATUS_REQ_ERR;
+
+ if ( dev->state == USBD_STATE_DEFAULT )
+ {
+ if ( addr != 0 )
+ {
+ USBD_SetUsbState( USBD_STATE_ADDRESSED );
+ }
+ USBDHAL_SetAddr( addr );
+ retVal = USB_STATUS_OK;
+ }
+ else if ( dev->state == USBD_STATE_ADDRESSED )
+ {
+ if ( addr == 0 )
+ {
+ USBD_SetUsbState( USBD_STATE_DEFAULT );
+ }
+ USBDHAL_SetAddr( addr );
+ retVal = USB_STATUS_OK;
+ }
+
+ return retVal;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Query the stall state of an endpoint
+ *
+ * @param[in] epAddr
+ * The address of the endpoint to query.
+ *
+ * @return
+ * True if endpoint is stalled, false otherwise
+ ******************************************************************************/
+int USBD_EpIsStalled(int epAddr)
+{
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ if( !ep )
+ {
+ return false;
+ }
+
+ return USBDHAL_EpIsStalled(ep);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Reset (remove) all client endpoints
+ *
+ * @details
+ * Removes client endpoints, and resets the RX/TX fifos. No endpoints
+ * other than EP0 can be used until added with @ref USBD_AddEndpoint.
+ ******************************************************************************/
+static void USBD_ResetEndpoints(void)
+{
+ USBD_Ep_TypeDef *ep = &dev->ep[0];
+
+ numEps = 0;
+ txFifoNum = 1;
+
+ totalTxFifoSize = ep->fifoSize * 1;
+ totalRxFifoSize = (ep->fifoSize + 1) * 1;
+ totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );
+}
+
+/***************************************************************************//**
+ * @brief
+ * Add a new endpoint
+ *
+ * @param[in] epAddr
+ * Endpoint address
+ *
+ * @param[in] transferType
+ * Endpoint type, one of @ref USB_EPTYPE_BULK, @ref USB_EPTYPE_INTR or
+ * @ref USB_EPTYPE_ISOC.
+ *
+ * @param[in] maxPacketSize
+ * Maximum packet size of the new endpoint, in bytes
+ *
+ * @param[in] bufferMult
+ * FIFO buffer size multiplier
+ *
+ * @return
+ * @ref USB_STATUS_OK on success, else an appropriate error code.
+ ******************************************************************************/
+int USBD_AddEndpoint(int epAddr, int transferType,
+ int maxPacketSize, int bufferMult)
+{
+ USBD_Ep_TypeDef *ep;
+
+ numEps++;
+
+ ep = &dev->ep[ numEps ];
+ ep->in = ( epAddr & USB_SETUP_DIR_MASK ) != 0;
+ ep->buf = NULL;
+ ep->addr = epAddr;
+ ep->num = ep->addr & USB_EPNUM_MASK;
+ ep->mask = 1 << ep->num;
+ ep->type = transferType;
+ ep->packetSize = maxPacketSize;
+ ep->remaining = 0;
+ ep->xferred = 0;
+ ep->state = D_EP_IDLE;
+ ep->xferCompleteCb = NULL;
+
+ if ( ep->in )
+ {
+ ep->txFifoNum = txFifoNum++;
+ ep->fifoSize = ( ( ep->packetSize + 3 ) / 4 ) * bufferMult;
+ dev->inEpAddr2EpIndex[ ep->num ] = numEps;
+ totalTxFifoSize += ep->fifoSize;
+
+ if ( ep->num > MAX_NUM_IN_EPS )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal IN EP address" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+ }
+ else
+ {
+ ep->fifoSize = ( ( ( ep->packetSize + 3 ) / 4 ) + 1 ) * bufferMult;
+ dev->outEpAddr2EpIndex[ ep->num ] = numEps;
+ totalRxFifoSize += ep->fifoSize;
+
+ if ( ep->num > MAX_NUM_OUT_EPS )
+ {
+ DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal OUT EP address" );
+ EFM_ASSERT( false );
+ return USB_STATUS_ILLEGAL;
+ }
+ }
+
+ USB_PRINTF("USBD: Added endpoint %d to slot %d, in %d, addr 0x%x, type %d, ps %d, fifo %ld (total tx %ld, rx %ld)\n",
+ ep->num, numEps, ep->in, ep->addr, ep->type, ep->packetSize, ep->fifoSize,
+ totalTxFifoSize, totalRxFifoSize);
+
+ INT_Disable();
+#if defined( CMU_OSCENCMD_USHFRCOEN )
+ /* Happy Gecko workaround: disable LEM GATE mode if using ISOC endpoints. */
+ if ( transferType == USB_EPTYPE_ISOC )
+ {
+ USB->CTRL = (USB->CTRL & ~_USB_CTRL_LEMOSCCTRL_MASK) | USB_CTRL_LEMOSCCTRL_NONE;
+ }
+#endif
+
+ int ret = USBDHAL_ReconfigureFifos(totalRxFifoSize, totalTxFifoSize);
+ INT_Enable();
+
+ if( ret != USB_STATUS_OK ) {
+ return ret;
+ }
+
+ USBDHAL_ActivateEp(ep, false);
+
+ return USB_STATUS_OK;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ * Set an endpoint0 in the stalled (halted) state.
+ *
+ * @details
+ * Temporarily stalls endpoint 0. Used to signal a failure to respond to
+ * the host's setup packet.
+ ******************************************************************************/
+void USBD_StallEp0()
+{
+ int const epAddr = 0;
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+#if !defined( USB_DOEP0INT_STUPPKTRCVD )
+ USBDHAL_ReenableEp0Setup( dev ); /* Prepare for next SETUP pkt. */
+#else
+ USBDHAL_StartEp0Setup( dev );
+#endif
+ ep->state = D_EP_IDLE;
+}
+
+/******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************//**
+ * @{
+
+@page usb_device USB device stack library
+
+ The source files for the USB device stack resides in the usb directory
+ and follows the naming convention: em_usbd<em>nnn</em>.c/h.
+
+ @li @ref usb_device_intro
+ @li @ref usb_device_api
+ @li @ref usb_device_conf
+ @li @ref usb_device_powersave
+ @li @ref usb_device_example1
+
+
+@n @section usb_device_intro Introduction
+
+ The USB device protocol stack provides an API which makes it possible to
+ create USB devices with a minimum of effort. The device stack supports control,
+ bulk and interrupt transfers.
+
+ The stack is highly configurable to suit various needs, it does also contain
+ useful debugging features together with several demonstration projects to
+ get you started fast.
+
+ We recommend that you read through this documentation, then proceed to build
+ and test a few example projects before you start designing your own device.
+
+@n @section usb_device_api The device stack API
+
+ This section contains brief descriptions of the functions in the API. You will
+ find detailed information on input and output parameters and return values by
+ clicking on the hyperlinked function names. It is also a good idea to study
+ the code in the USB demonstration projects.
+
+ Your application code must include one header file: @em em_usb.h.
+
+ All functions defined in the API can be called from within interrupt handlers.
+
+ The USB stack use a hardware timer to keep track of time. TIMER0 is the
+ default choice, refer to @ref usb_device_conf for other possibilities.
+ Your application must not use the selected timer.
+
+ <b>Pitfalls:</b>@n
+ The USB peripheral will fill your receive buffers in quantities of WORD's
+ (4 bytes). Transmit and receive buffers must be WORD aligned, in
+ addition when allocating storage for receive buffers, round size up to
+ next WORD boundary. If it is possible that the host will send more data
+ than your device expects, round buffer size up to the next multiple of
+ maxpacket size for the relevant endpoint to avoid data corruption.
+
+ Transmit buffers passed to @htmlonly USBD_Write() @endhtmlonly must be
+ statically allocated because @htmlonly USBD_Write() @endhtmlonly only
+ initiates the transfer. When the host decide to actually perform the
+ transfer, your data must be available.
+
+ @n @ref USBD_Init() @n
+ This function is called to register your device and all its properties with
+ the device stack. The application must fill in a @ref USBD_Init_TypeDef
+ structure prior to calling. Refer to @ref DeviceInitCallbacks for the
+ optional callback functions defined within this structure. When this
+ function has been called your device is ready to be enumerated by the USB
+ host.
+
+ @ref USBD_Read(), @ref USBD_Write() @n
+ These functions initiate data transfers.
+ @n @htmlonly USBD_Read() @endhtmlonly initiate a transfer of data @em
+ from host @em to device (an @em OUT transfer in USB terminology).
+ @n @htmlonly USBD_Write() @endhtmlonly initiate a transfer of data @em from
+ device @em to host (an @em IN transfer).
+
+ When the USB host actually performs the transfer, your application will be
+ notified by means of a callback function which you provide (optionally).
+ Refer to @ref TransferCallback for details of the callback functionality.
+
+ @ref USBD_AbortTransfer(), @ref USBD_AbortAllTransfers() @n
+ These functions terminate transfers that are initiated, but has not yet
+ taken place. If a transfer is initiated with @htmlonly USBD_Read()
+ or USBD_Write(), @endhtmlonly but the USB host never actually peform
+ the transfers, these functions will deactivate the transfer setup to make
+ the USB device endpoint hardware ready for new (and potentially) different
+ transfers.
+
+ @ref USBD_Connect(), @ref USBD_Disconnect() @n
+ These functions turns the data-line (D+ or D-) pullup on or off. They can be
+ used to force reenumeration. It's good practice to delay at least one second
+ between @htmlonly USBD_Disconnect() and USBD_Connect() @endhtmlonly
+ to allow the USB host to unload the currently active device driver.
+
+ @ref USBD_EpIsBusy() @n
+ Check if an endpoint is busy.
+
+ @ref USBD_StallEp(), @ref USBD_UnStallEp() @n
+ These functions stalls or un-stalls an endpoint. This functionality may not
+ be needed by your application, but the USB device stack use them in response
+ to standard setup commands SET_FEATURE and CLEAR_FEATURE. They may be useful
+ when implementing some USB classes, e.g. a mass storage device use them
+ extensively.
+
+ @ref USBD_RemoteWakeup() @n
+ Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to
+ host. It's the applications responsibility to adhere to the USB standard
+ which states that a device can not signal resume before it has been
+ SUSPENDED for at least 5 ms. The function will also check the configuration
+ descriptor defined by the application to see if it is legal for the device
+ to signal resume.
+
+ @ref USBD_GetUsbState() @n
+ Returns the device USB state (see @ref USBD_State_TypeDef). Refer to
+ Figure 9-1. "Device State Diagram" in the USB revision 2.0 specification.
+
+ @ref USBD_GetUsbStateName() @n
+ Returns a text string naming a given USB device state.
+
+ @ref USBD_SafeToEnterEM2() @n
+ Check if it is ok to enter energy mode EM2. Refer to the
+ @ref usb_device_powersave section for more information.
+
+ @n @anchor TransferCallback <b>The transfer complete callback function:</b> @n
+ @n USB_XferCompleteCb_TypeDef() is called when a transfer completes. It is
+ called with three parameters, the status of the transfer, the number of
+ bytes transferred and the number of bytes remaining. It may not always be
+ needed to have a callback on transfer completion, but you should keep in
+ mind that a transfer may be aborted when you least expect it. A transfer
+ will be aborted if host stalls the endpoint, if host resets your device, if
+ host unconfigures your device or if you unplug your device cable and the
+ device is selfpowered.
+ @htmlonly USB_XferCompleteCb_TypeDef() @endhtmlonly is also called if your
+ application use @htmlonly USBD_AbortTransfer() or USBD_AbortAllTransfers()
+ @endhtmlonly calls.
+ @note This callback is called from within an interrupt handler with
+ interrupts disabled.
+
+ @n @anchor DeviceInitCallbacks <b>Optional callbacks passed to the stack via
+ the @ref USBD_Init() function:</b> @n
+ @n These callbacks are all optional, and it is up to the application
+ programmer to decide if the application needs the functionality they
+ provide.
+ @note These callbacks are all called from within an interrupt handler
+ with interrupts disabled.
+
+ USBD_UsbResetCb_TypeDef() is called each time reset signalling is sensed on
+ the USB wire.
+
+ @n USBD_SofIntCb_TypeDef() is called with framenumber as a parameter on
+ each SOF interrupt.
+
+ @n USBD_DeviceStateChangeCb_TypeDef() is called whenever the device state
+ change. Useful for detecting e.g. SUSPENDED state change in order to reduce
+ current consumption of buspowered devices. The USB HID keyboard example
+ project has a good example on how to use this callback.
+
+ @n USBD_IsSelfPoweredCb_TypeDef() is called by the device stack when host
+ queries the device with a standard setup GET_STATUS command to check if the
+ device is currently selfpowered or buspowered. This feature is only
+ applicable on selfpowered devices which also works when only buspower is
+ available.
+
+ @n USBD_SetupCmdCb_TypeDef() is called each time a setup command is
+ received from host. Use this callback to override or extend the default
+ handling of standard setup commands, and to implement class or vendor
+ specific setup commands. The USB HID keyboard example project has a good
+ example on how to use this callback.
+
+ @n <b>Utility functions:</b> @n
+ @n USB_PUTCHAR() Transmit a single char on the debug serial port.
+ @n @n USB_PUTS() Transmit a zero terminated string on the debug serial port.
+ @n @n USB_PRINTF() Transmit "printf" formated data on the debug serial port.
+ @n @n USB_GetErrorMsgString() Return an error message string for a given
+ error code.
+ @n @n USB_PrintErrorMsgString() Format and print a text string given an
+ error code, prepends an optional user supplied leader string.
+ @n @n USBTIMER_DelayMs() Active wait millisecond delay function. Can also be
+ used inside interrupt handlers.
+ @n @n USBTIMER_DelayUs() Active wait microsecond delay function. Can also be
+ used inside interrupt handlers.
+ @n @n USBTIMER_Init() Initialize the timer system. Called by @htmlonly
+ USBD_Init(), @endhtmlonly but your application must call it again to
+ reinitialize whenever you change the HFPERCLK frequency.
+ @n @n USBTIMER_Start() Start a timer. You can configure the USB device stack
+ to provide any number of timers. The timers have 1 ms resolution, your
+ application is notified of timeout by means of a callback.
+ @n @n USBTIMER_Stop() Stop a timer.
+
+@n @section usb_device_conf Configuring the device stack
+
+ Your application must provide a header file named @em usbconfig.h. This file
+ must contain the following \#define's:@n @n
+ @verbatim
+#define USB_DEVICE // Compile the stack for device mode.
+#define NUM_EP_USED n // Your application use 'n' endpoints in
+ // addition to endpoint 0. @endverbatim
+
+ @n @em usbconfig.h may define the following items: @n @n
+ @verbatim
+#define NUM_APP_TIMERS n // Your application needs 'n' timers
+
+#define DEBUG_USB_API // Turn on API debug diagnostics.
+
+// Some utility functions in the API needs printf. These
+// functions have "print" in their name. This macro enables
+// these functions.
+#define USB_USE_PRINTF // Enable utility print functions.
+
+// Define a function for transmitting a single char on the serial port.
+extern int RETARGET_WriteChar(char c);
+#define USER_PUTCHAR RETARGET_WriteChar
+
+#define USB_TIMER USB_TIMERn // Select which hardware timer the USB stack
+ // is allowed to use. Valid values are n=0,1,2...
+ // corresponding to TIMER0, TIMER1, ...
+ // If not specified, TIMER0 is used
+
+#define USB_VBUS_SWITCH_NOT_PRESENT // Hardware does not have a VBUS switch
+
+#define USB_CORECLK_HFRCO // Devices supporting crystal-less USB can use
+ // HFRCO as core clock, default is HFXO
+@endverbatim
+
+ @n You are strongly encouraged to start application development with DEBUG_USB_API
+ turned on. When DEBUG_USB_API is turned on and USER_PUTCHAR is defined, useful
+ debugging information will be output on the development kit serial port.
+ Compiling with the DEBUG_EFM_USER flag will also enable all asserts
+ in both @em emlib and in the USB stack. If asserts are enabled and
+ USER_PUTCHAR defined, assert texts will be output on the serial port.
+
+ You application must include @em retargetserial.c if DEBUG_USB_API is defined
+ and @em retargetio.c if USB_USE_PRINTF is defined.
+ These files reside in the @em drivers
+ directory in the software package for your development board. Refer to
+ @ref usb_device_powersave for energy-saving mode configurations.
+
+@n @section usb_device_powersave Energy-saving modes
+
+ The device stack provides two energy saving levels. The first level is to
+ set the USB peripheral in energy saving mode, the next level is to enter
+ Energy Mode 2 (EM2). These energy saving modes can be applied when the device
+ is suspended by the USB host, or when when the device is not connected to a
+ USB host.
+ In addition to this an application can use energy modes EM1 and EM2. There
+ are no restrictions on when EM1 can be entered, EM2 can only be entered
+ when the USB device is suspended or detached from host.
+
+ Energy-saving modes are selected with a \#define in @em usbconfig.h, default
+ selection is to not use any energy saving modes.@n @n
+ @verbatim
+#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ENTEREM2)@endverbatim
+
+ There are three flags available, the flags can be or'ed together as shown above.
+
+ <b>\#define USB_PWRSAVE_MODE_ONSUSPEND</b>@n Set USB peripheral in low power
+ mode on suspend.
+
+ <b>\#define USB_PWRSAVE_MODE_ONVBUSOFF</b>@n Set USB peripheral in low power
+ mode when not attached to a host. This mode assumes that the internal voltage
+ regulator is used and that the VREGI pin of the chip is connected to VBUS.
+ This option can not be used with bus-powered devices.
+
+ <b>\#define USB_PWRSAVE_MODE_ENTEREM2</b>@n Enter EM2 when USB peripheral is
+ in low power mode.
+
+ When the USB peripheral is set in low power mode, it must be clocked by a 32kHz
+ clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification
+ compliance. Selection is done with a \#define in @em usbconfig.h.@n @n
+ @verbatim
+#define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO @endverbatim
+ Two flags are available, <b>USB_USBC_32kHz_CLK_LFXO</b> and
+ <b>USB_USBC_32kHz_CLK_LFRCO</b>. <b>USB_USBC_32kHz_CLK_LFXO</b> is selected
+ by default.
+
+ The USB HID keyboard and Mass Storage device example projects demonstrate
+ different energy-saving modes.
+
+ <b>Example 1:</b>
+ Leave all energy saving to the stack, the device enters EM2 on suspend and
+ when detached from host. @n
+ @verbatim
+In usbconfig.h:
+
+#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF | USB_PWRSAVE_MODE_ENTEREM2)
+ @endverbatim
+
+ @n <b>Example 2:</b>
+ Let the stack control energy saving in the USB periheral but let your
+ application control energy modes EM1 and EM2. @n
+ @verbatim
+In usbconfig.h:
+
+#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF)
+
+In application code:
+
+if ( USBD_SafeToEnterEM2() )
+ EMU_EnterEM2(true);
+else
+ EMU_EnterEM1(); @endverbatim
+
+@n @section usb_device_example1 Vendor unique device example application
+
+ This example represents the most simple USB device imaginable. It's purpose
+ is to turn user LED's on or off under control of vendor unique setup commands.
+ The device will rely on @em libusb device driver on the host, a host
+ application @em EFM32-LedApp.exe is bundled with the example.
+
+ The main() is really simple ! @n @n
+ @verbatim
+#include "em_usb.h"
+
+#include "descriptors.h"
+
+int main( void )
+{
+ BSP_Init(BSP_INIT_DEFAULT); // Initialize DK board register access
+ CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
+ BSP_LedsSet(0); // Turn off all LED's
+
+ ConsoleDebugInit(); // Initialize UART for debug diagnostics
+
+ USB_PUTS( "\nEFM32 USB LED Vendor Unique Device example\n" );
+
+ USBD_Init( &initstruct ); // GO !
+
+ //When using a debugger it is pratical to uncomment the following three
+ //lines to force host to re-enumerate the device.
+
+ //USBD_Disconnect();
+ //USBTIMER_DelayMs( 1000 );
+ //USBD_Connect();
+
+ for (;;) {}
+} @endverbatim
+
+ @n Configure the device stack in <em>usbconfig.h</em>: @n @n
+ @verbatim
+#define USB_DEVICE // Compile stack for device mode.
+
+// **************************************************************************
+** **
+** Specify number of endpoints used (in addition to EP0). **
+** **
+*****************************************************************************
+#define NUM_EP_USED 0 // EP0 is the only endpoint used.
+
+// **************************************************************************
+** **
+** Configure serial port debug output. **
+** **
+*****************************************************************************
+// Prototype a function for transmitting a single char on the serial port.
+extern int RETARGET_WriteChar(char c);
+#define USER_PUTCHAR RETARGET_WriteChar
+
+// Enable debug diagnostics from API functions (illegal input params etc.)
+#define DEBUG_USB_API @endverbatim
+
+ @n Define device properties and fill in USB initstruct in
+ <em>descriptors.h</em>: @n @n
+ @verbatim
+EFM32_ALIGN(4)
+static const USB_DeviceDescriptor_TypeDef deviceDesc __attribute__ ((aligned(4))) =
+{
+ .bLength = USB_DEVICE_DESCSIZE,
+ .bDescriptorType = USB_DEVICE_DESCRIPTOR,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = 0xFF,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = USB_FS_CTRL_EP_MAXSIZE,
+ .idVendor = 0x10C4,
+ .idProduct = 0x0001,
+ .bcdDevice = 0x0000,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 3,
+ .bNumConfigurations = 1
+};
+
+EFM32_ALIGN(4)
+static const uint8_t configDesc[] __attribute__ ((aligned(4)))=
+{
+ // *** Configuration descriptor ***
+ USB_CONFIG_DESCSIZE, // bLength
+ USB_CONFIG_DESCRIPTOR, // bDescriptorType
+ USB_CONFIG_DESCSIZE + // wTotalLength (LSB)
+ USB_INTERFACE_DESCSIZE,
+ (USB_CONFIG_DESCSIZE + // wTotalLength (MSB)
+ USB_INTERFACE_DESCSIZE)>>8,
+ 1, // bNumInterfaces
+ 1, // bConfigurationValue
+ 0, // iConfiguration
+ CONFIG_DESC_BM_RESERVED_D7 | // bmAttrib: Self powered
+ CONFIG_DESC_BM_SELFPOWERED,
+ CONFIG_DESC_MAXPOWER_mA( 100 ), // bMaxPower: 100 mA
+
+ // *** Interface descriptor ***
+ USB_INTERFACE_DESCSIZE, // bLength
+ USB_INTERFACE_DESCRIPTOR, // bDescriptorType
+ 0, // bInterfaceNumber
+ 0, // bAlternateSetting
+ NUM_EP_USED, // bNumEndpoints
+ 0xFF, // bInterfaceClass
+ 0, // bInterfaceSubClass
+ 0, // bInterfaceProtocol
+ 0, // iInterface
+};
+
+STATIC_CONST_STRING_DESC_LANGID( langID, 0x04, 0x09 );
+STATIC_CONST_STRING_DESC( iManufacturer, 'E','n','e','r','g','y',' ', \
+ 'M','i','c','r','o',' ','A','S' );
+STATIC_CONST_STRING_DESC( iProduct , 'V','e','n','d','o','r',' ', \
+ 'U','n','i','q','u','e',' ', \
+ 'L','E','D',' ', \
+ 'D','e','v','i','c','e' );
+STATIC_CONST_STRING_DESC( iSerialNumber, '0','0','0','0','0','0', \
+ '0','0','1','2','3','4' );
+
+static const void * const strings[] =
+{
+ &langID,
+ &iManufacturer,
+ &iProduct,
+ &iSerialNumber
+};
+
+// Endpoint buffer sizes
+// 1 = single buffer, 2 = double buffering, 3 = tripple buffering ...
+static const uint8_t bufferingMultiplier[ NUM_EP_USED + 1 ] = { 1 };
+
+static const USBD_Callbacks_TypeDef callbacks =
+{
+ .usbReset = NULL,
+ .usbStateChange = NULL,
+ .setupCmd = SetupCmd,
+ .isSelfPowered = NULL,
+ .sofInt = NULL
+};
+
+static const USBD_Init_TypeDef initstruct =
+{
+ .deviceDescriptor = &deviceDesc,
+ .configDescriptor = configDesc,
+ .stringDescriptors = strings,
+ .numberOfStrings = sizeof(strings)/sizeof(void*),
+ .callbacks = &callbacks,
+ .bufferingMultiplier = bufferingMultiplier
+}; @endverbatim
+
+ @n Now we have to implement vendor unique USB setup commands to control the
+ LED's (see callbacks variable above). Notice that the buffer variable below is
+ statically allocated because @htmlonly USBD_Write() @endhtmlonly only
+ initiates the transfer. When the host actually performs the transfer, the
+ SetupCmd() function will have returned ! @n @n
+
+ @verbatim
+#define VND_GET_LEDS 0x10
+#define VND_SET_LED 0x11
+
+static int SetupCmd( const USB_Setup_TypeDef *setup )
+{
+ int retVal;
+ uint16_t leds;
+ static uint32_t buffer;
+ uint8_t *pBuffer = (uint8_t*)&buffer;
+
+ retVal = USB_STATUS_REQ_UNHANDLED;
+
+ if ( setup->Type == USB_SETUP_TYPE_VENDOR )
+ {
+ switch ( setup->bRequest )
+ {
+ case VND_GET_LEDS:
+ // ********************
+ *pBuffer = BSP_LedsGet() & 0x1F;
+ retVal = USBD_Write( 0, pBuffer, setup->wLength, NULL );
+ break;
+
+ case VND_SET_LED:
+ // ********************
+ leds = DVK_getLEDs() & 0x1F;
+ if ( setup->wValue )
+ {
+ leds |= LED0 << setup->wIndex;
+ }
+ else
+ {
+ leds &= ~( LED0 << setup->wIndex );
+ }
+ BSP_LedsSet( leds );
+ retVal = USB_STATUS_OK;
+ break;
+ }
+ }
+
+ return retVal;
+}@endverbatim
+
+ * @}**************************************************************************/
+
+#endif /* defined( USB_DEVICE ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/src/em_usbdep.c Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,446 @@
+/**************************************************************************//**
+ * @file em_usbdep.c
+ * @brief USB protocol stack library, USB device endpoint handlers.
+ * @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 )
+
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+#include "em_usbd.h"
+
+#ifdef USB_USE_PRINTF
+static const char *epStatusStr[] = {
+ "IDLE","TRANS","RECV","IN_S","OUT_S"
+};
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/*
+ * USBDEP_Ep0Handler() is called each time a packet has been transmitted
+ * or recieved on the default endpoint.
+ * A state machine navigate us through the phases of a control transfer
+ * according to "chapter 9" in the USB spec.
+ */
+#if !defined( USB_DOEP0INT_STUPPKTRCVD )
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
+{
+ int status;
+ USBD_Ep_TypeDef *ep;
+ static bool statusIn;
+ static uint32_t xferred;
+ static USB_XferCompleteCb_TypeDef callback;
+
+ ep = &device->ep[ 0 ];
+
+#ifdef __MBED__
+
+ (void)xferred;
+ (void)statusIn;
+ (void)status;
+
+ USB_PRINTF("USBDEP: ep0 %s, rem %ld, z %d\n", epStatusStr[ep->state], ep->remaining, ep->zlp);
+
+ if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
+ {
+ ep->state = D_EP_IDLE;
+
+ if ( ep->xferCompleteCb )
+ {
+ callback = ep->xferCompleteCb;
+ ep->xferCompleteCb = NULL;
+ callback( USB_STATUS_OK, ep->xferred, ep->remaining );
+ }
+
+ USBDHAL_ReenableEp0Setup(device);
+ }
+ else
+ {
+ device->callbacks->setupCmd(device->setup);
+ }
+
+#else /* not __MBED__ */
+
+ switch ( ep->state )
+ {
+ case D_EP_IDLE:
+ ep->remaining = 0;
+ ep->zlp = 0;
+ callback = NULL;
+ statusIn = false;
+
+ status = USBDCH9_SetupCmd( device );
+
+ if ( status == USB_STATUS_REQ_ERR )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP packet*/
+ }
+ else /* ( Status == USB_STATUS_OK ) */
+ {
+ if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
+ {
+ callback = ep->xferCompleteCb;
+ }
+
+ if ( ep->state != D_EP_RECEIVING )
+ {
+ if ( ep->remaining )
+ {
+ /* Data will be sent to host, check if a ZLP must be appended */
+ if ( ( ep->remaining < device->setup->wLength ) &&
+ ( ep->remaining % ep->packetSize == 0 ) )
+ {
+ ep->zlp = 1;
+ }
+ }
+ else
+ {
+ /* Prepare for next SETUP packet*/
+ USBDHAL_ReenableEp0Setup( device );
+
+ /* No data stage, a ZLP may have been sent. If not, send one */
+
+ xferred = 0;
+ if ( ep->zlp == 0 )
+ {
+ USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
+ ep->state = D_EP0_IN_STATUS;
+ }
+ else
+ {
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ }
+ }
+ }
+ }
+ break;
+
+ case D_EP_RECEIVING:
+ if ( ep->remaining )
+ {
+ /* There is more data to receive */
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ status = USB_STATUS_OK;
+ if ( callback != NULL )
+ {
+ status = callback( USB_STATUS_OK, ep->xferred, 0 );
+ callback = NULL;
+ }
+
+ if ( status != USB_STATUS_OK )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP pkt. */
+ ep->state = D_EP_IDLE;
+ }
+ else /* Everything OK, send a ZLP (ACK) to host */
+ {
+ USBDHAL_ReenableEp0Setup( device );/* Prepare for next SETUP packet*/
+
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back*/
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL );
+ ep->state = D_EP0_IN_STATUS;
+ }
+ }
+ break;
+
+ case D_EP_TRANSMITTING:
+ if ( ep->remaining )
+ {
+ /* There is more data to transmit */
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ /* All data transferred, is a ZLP packet needed ? */
+ if ( ep->zlp == 1 )
+ {
+ xferred = ep->xferred;
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
+ ep->zlp = 2;
+ }
+ else
+ {
+ if ( ep->zlp == 0 )
+ {
+ xferred = ep->xferred;
+ }
+
+ ep->state = D_EP_IDLE;
+ USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
+ statusIn = true;
+ ep->state = D_EP0_OUT_STATUS;
+ }
+ }
+ break;
+
+ case D_EP0_IN_STATUS:
+ case D_EP0_OUT_STATUS:
+ if ( statusIn )
+ {
+ USBDHAL_ReenableEp0Setup( device );
+ }
+
+ if ( callback != NULL )
+ {
+ callback( USB_STATUS_OK, xferred, 0 );
+ }
+
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ break;
+
+ default:
+ EFM_ASSERT( false );
+ break;
+ }
+#endif /* __MBED__ */
+}
+#endif
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
+{
+ int status;
+ USBD_Ep_TypeDef *ep;
+ static uint32_t xferred;
+ static USB_XferCompleteCb_TypeDef callback;
+
+#ifdef __MBED__
+
+ (void)xferred;
+ (void)status;
+
+ ep = &device->ep[ 0 ];
+
+ if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
+ {
+ ep->state = D_EP_IDLE;
+
+ if ( ep->xferCompleteCb )
+ {
+ callback = ep->xferCompleteCb;
+ ep->xferCompleteCb = NULL;
+ callback( USB_STATUS_OK, ep->xferred, ep->remaining );
+ }
+
+ USBDHAL_StartEp0Setup( dev );
+ }
+ else
+ {
+ device->callbacks->setupCmd(device->setup);
+ }
+
+#else
+
+ ep = &device->ep[ 0 ];
+
+ switch ( ep->state )
+ {
+ case D_EP_IDLE:
+ ep->zlp = 0;
+ ep->remaining = 0;
+ callback = NULL;
+
+ status = USBDCH9_SetupCmd( device );
+
+ if ( status == USB_STATUS_REQ_ERR )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
+ }
+ else /* ( Status == USB_STATUS_OK ) */
+ {
+ if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
+ {
+ callback = ep->xferCompleteCb;
+ }
+
+ if ( ep->state != D_EP_RECEIVING )
+ {
+ if ( ep->remaining )
+ {
+ /* Data will be sent to host, check if a ZLP must be appended */
+ if ( ( ep->remaining < device->setup->wLength ) &&
+ ( ep->remaining % ep->packetSize == 0 ) )
+ {
+ ep->zlp = 1;
+ }
+ }
+ else
+ {
+ /* No data stage, a ZLP may have been sent. If not, send one */
+ xferred = 0;
+ if ( ep->zlp == 0 )
+ {
+ ep->state = D_EP_IDLE;
+ USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
+ ep->state = D_EP0_IN_STATUS;
+ }
+ }
+ }
+ }
+ break;
+
+ case D_EP_RECEIVING:
+ if ( ep->remaining )
+ {
+ ep->in = false;
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ status = USB_STATUS_OK;
+ if ( callback != NULL )
+ {
+ status = callback( USB_STATUS_OK, ep->xferred, 0 );
+ callback = NULL;
+ }
+
+ if ( status != USB_STATUS_OK )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP pkt. */
+ ep->state = D_EP_IDLE;
+ }
+ else
+ {
+
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL );
+ ep->state = D_EP0_IN_STATUS;
+ }
+ }
+ break;
+
+ case D_EP_TRANSMITTING:
+ if ( ep->remaining )
+ {
+ ep->in = true;
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ if ( ep->zlp == 1 )
+ {
+ xferred = ep->xferred;
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
+ ep->zlp = 2;
+ }
+ else
+ {
+ if ( ep->zlp == 0 )
+ {
+ xferred = ep->xferred;
+ }
+
+ ep->state = D_EP_IDLE;
+ USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
+ ep->state = D_EP0_OUT_STATUS;
+ }
+ }
+ break;
+
+ case D_EP0_IN_STATUS:
+ if ( ( USB->DOEP0CTL & USB_DOEP0CTL_EPENA ) == 0 )
+ {
+ /* Prepare for more SETUP Packets */
+ USBDHAL_StartEp0Setup( dev );
+ }
+ if ( callback != NULL )
+ {
+ callback( USB_STATUS_OK, xferred, 0 );
+ }
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ break;
+
+ case D_EP0_OUT_STATUS:
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for more SETUP Packets */
+ if ( callback != NULL )
+ {
+ callback( USB_STATUS_OK, xferred, 0 );
+ }
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ break;
+ }
+#endif /* __MBED__ */
+}
+#endif
+
+/*
+ * USBDEP_EpHandler() is called each time a packet has been transmitted
+ * or recieved on an endpoint other than the default endpoint.
+ */
+void USBDEP_EpHandler( uint8_t epAddr )
+{
+ USB_XferCompleteCb_TypeDef callback;
+ USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
+
+ if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) )
+ {
+ ep->state = D_EP_IDLE;
+ if ( ep->xferCompleteCb )
+ {
+ callback = ep->xferCompleteCb;
+ ep->xferCompleteCb = NULL;
+ callback( USB_STATUS_OK, ep->xferred, ep->remaining );
+ }
+ }
+ else
+ {
+ EFM_ASSERT( false );
+ }
+}
+
+/** @endcond */
+
+#endif /* defined( USB_DEVICE ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/src/em_usbdint.c Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,946 @@
+/**************************************************************************//**
+ * @file em_usbdint.c
+ * @brief USB protocol stack library, USB device peripheral interrupt handlers.
+ * @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 )
+
+#include "em_cmu.h"
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+#include "em_usbd.h"
+
+#ifdef __MBED__
+extern void usbhal_allow_em2(bool em2_allow);
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#define HANDLE_INT( x ) if ( status & x ) { Handle_##x(); status &= ~x; }
+
+static void Handle_USB_GINTSTS_ENUMDONE ( void );
+static void Handle_USB_GINTSTS_IEPINT ( void );
+static void Handle_USB_GINTSTS_OEPINT ( void );
+static void Handle_USB_GINTSTS_RESETDET ( void );
+static void Handle_USB_GINTSTS_SOF ( void );
+static void Handle_USB_GINTSTS_USBRST ( void );
+static void Handle_USB_GINTSTS_USBSUSP ( void );
+static void Handle_USB_GINTSTS_WKUPINT ( void );
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+static void HandleOutEpIntr( uint32_t status, USBD_Ep_TypeDef *ep );
+#else
+static void ProcessSetup ( void );
+static void ProcessOepData ( USBD_Ep_TypeDef *ep );
+#endif
+
+#if ( USB_PWRSAVE_MODE )
+/* Variables and prototypes for USB powerdown (suspend) functionality. */
+static bool UsbPowerDown( void );
+static bool UsbPowerUp( void );
+
+volatile bool USBD_poweredDown = false;
+
+/* Storage for backing up USB core registers. */
+static uint32_t x_USB_GINTMSK;
+#if defined(_USB_GOTGCTL_MASK)
+static uint32_t x_USB_GOTGCTL;
+#endif
+static uint32_t x_USB_GAHBCFG;
+static uint32_t x_USB_GUSBCFG;
+static uint32_t x_USB_GRXFSIZ;
+static uint32_t x_USB_GNPTXFSIZ;
+static uint32_t x_USB_DCFG;
+static uint32_t x_USB_DCTL;
+static uint32_t x_USB_DAINTMSK;
+static uint32_t x_USB_DIEPMSK;
+static uint32_t x_USB_DOEPMSK;
+static uint32_t x_USB_PCGCCTL;
+
+#if ( NUM_EP_USED > 0 )
+static uint32_t x_USB_EP_CTL[ NUM_EP_USED ];
+static uint32_t x_USB_EP_TSIZ[ NUM_EP_USED ];
+static uint32_t x_USB_EP_DMAADDR[ NUM_EP_USED ];
+#endif
+
+#if ( NUM_EP_USED > MAX_NUM_TX_FIFOS )
+#define FIFO_CNT MAX_NUM_TX_FIFOS
+#else
+#define FIFO_CNT NUM_EP_USED
+#endif
+
+#if ( FIFO_CNT > 0 )
+static uint32_t x_USB_DIEPTXFS[ FIFO_CNT ];
+#endif
+
+#if ( USB_PWRSAVE_MODE )
+static uint32_t cmuStatus = 0;
+#endif
+
+#endif /* if ( USB_PWRSAVE_MODE ) */
+
+/*
+ * USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
+ */
+void USB_IRQHandler( void )
+{
+ uint32_t status;
+ bool servedVbusInterrupt = false;
+
+ INT_Disable();
+
+#if ( USB_PWRSAVE_MODE )
+ if ( USBD_poweredDown )
+ {
+ /* Switch USBC clock from 32kHz to a 48MHz clock to be able to */
+ /* read USB peripheral registers. */
+ /* If we woke up from EM2, HFCLK is now HFRCO. */
+
+ /* Restore clock oscillators.*/
+#if defined( CMU_OSCENCMD_USHFRCOEN )
+ if ( ( CMU->STATUS & CMU_STATUS_USHFRCOENS ) == 0 )/*Wakeup from EM2 ?*/
+ {
+ CMU->OSCENCMD = ( cmuStatus
+ & ( CMU_STATUS_AUXHFRCOENS | CMU_STATUS_HFXOENS ) )
+ | CMU_OSCENCMD_USHFRCOEN;
+ }
+#else
+ if ( ( CMU->STATUS & CMU_STATUS_HFXOENS ) == 0 ) /* Wakeup from EM2 ? */
+ {
+ CMU->OSCENCMD = cmuStatus
+ & ( CMU_STATUS_AUXHFRCOENS | CMU_STATUS_HFXOENS );
+ }
+#endif
+
+ /* Select correct USBC clock.*/
+#if defined( CMU_OSCENCMD_USHFRCOEN )
+ CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
+ while ( ( CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL ) == 0 ){}
+#else
+ CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
+ while ( ( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) == 0 ){}
+#endif
+ }
+#endif /* if ( USB_PWRSAVE_MODE ) */
+
+ if ( USB->IF && ( USB->CTRL & USB_CTRL_VREGOSEN ) )
+ {
+ if ( USB->IF & USB_IF_VREGOSH )
+ {
+ USB->IFC = USB_IFC_VREGOSH;
+
+ if ( USB->STATUS & USB_STATUS_VREGOS )
+ {
+ servedVbusInterrupt = true;
+ DEBUG_USB_INT_LO_PUTS( "\nVboN" );
+
+#if ( USB_PWRSAVE_MODE )
+ if ( UsbPowerUp() )
+ {
+ USBDHAL_EnableUsbResetAndSuspendInt();
+ }
+ USBD_SetUsbState( USBD_STATE_POWERED );
+#endif
+ }
+ }
+
+ if ( USB->IF & USB_IF_VREGOSL )
+ {
+ USB->IFC = USB_IFC_VREGOSL;
+
+ if ( ( USB->STATUS & USB_STATUS_VREGOS ) == 0 )
+ {
+ servedVbusInterrupt = true;
+ DEBUG_USB_INT_LO_PUTS( "\nVboF" );
+
+#if ( USB_PWRSAVE_MODE )
+#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
+ if ( !USBD_poweredDown )
+ {
+ USB->GINTMSK = 0;
+ USB->GINTSTS = 0xFFFFFFFF;
+ }
+
+ UsbPowerDown();
+#endif
+ USBD_SetUsbState( USBD_STATE_NONE );
+#endif
+ }
+ }
+ }
+
+ status = USBHAL_GetCoreInts();
+ if ( status == 0 )
+ {
+ INT_Enable();
+ if ( !servedVbusInterrupt )
+ {
+ DEBUG_USB_INT_LO_PUTS( "\nSinT" );
+ }
+ return;
+ }
+
+ HANDLE_INT( USB_GINTSTS_RESETDET )
+ HANDLE_INT( USB_GINTSTS_WKUPINT )
+ HANDLE_INT( USB_GINTSTS_USBSUSP )
+ HANDLE_INT( USB_GINTSTS_SOF )
+ HANDLE_INT( USB_GINTSTS_ENUMDONE )
+ HANDLE_INT( USB_GINTSTS_USBRST )
+ HANDLE_INT( USB_GINTSTS_IEPINT )
+ HANDLE_INT( USB_GINTSTS_OEPINT )
+
+ INT_Enable();
+
+ if ( status != 0 )
+ {
+ DEBUG_USB_INT_LO_PUTS( "\nUinT" );
+ }
+}
+
+/*
+ * Handle port enumeration interrupt. This has nothing to do with normal
+ * device enumeration.
+ */
+static void Handle_USB_GINTSTS_ENUMDONE( void )
+{
+#if ( USB_PWRSAVE_MODE )
+ UsbPowerUp();
+#endif
+
+ USBDHAL_Ep0Activate( dev->ep0MpsCode );
+ dev->ep[ 0 ].state = D_EP_IDLE;
+ USBDHAL_EnableInts( dev );
+ DEBUG_USB_INT_LO_PUTS( "EnumD" );
+}
+
+/*
+ * Handle IN endpoint transfer interrupt.
+ */
+static void Handle_USB_GINTSTS_IEPINT( void )
+{
+ int epnum;
+ uint16_t epint;
+ uint16_t epmask;
+ uint32_t status;
+ USBD_Ep_TypeDef *ep;
+
+ DEBUG_USB_INT_HI_PUTCHAR( 'i' );
+
+ epint = USBDHAL_GetAllInEpInts();
+ for ( epnum = 0, epmask = 1;
+ epnum <= MAX_NUM_IN_EPS;
+ epnum++, epmask <<= 1 )
+ {
+ if ( epint & epmask )
+ {
+ ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | epnum );
+ status = USBDHAL_GetInEpInts( ep );
+
+ if ( status & USB_DIEP_INT_XFERCOMPL )
+ {
+ USB_DINEPS[ epnum ].INT = USB_DIEP_INT_XFERCOMPL;
+
+ DEBUG_USB_INT_HI_PUTCHAR( 'c' );
+
+ if ( epnum == 0 )
+ {
+ if ( ep->remaining > ep->packetSize )
+ {
+ ep->remaining -= ep->packetSize;
+ ep->xferred += ep->packetSize;
+ }
+ else
+ {
+ ep->xferred += ep->remaining;
+ ep->remaining = 0;
+ }
+ USBDEP_Ep0Handler( dev );
+ }
+ else
+ {
+ ep->xferred = ep->remaining -
+ ( ( USB_DINEPS[ epnum ].TSIZ &
+ _USB_DIEP_TSIZ_XFERSIZE_MASK ) >>
+ _USB_DIEP_TSIZ_XFERSIZE_SHIFT );
+ ep->remaining -= ep->xferred;
+
+ USBDEP_EpHandler( ep->addr );
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+ if ( USB_DINEPS[ ep->num ].INT & USB_DIEP_INT_NAKINTRPT )
+ {
+ USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_NAKINTRPT;
+ }
+#endif
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Handle OUT endpoint transfer interrupt.
+ */
+static void Handle_USB_GINTSTS_OEPINT( void )
+{
+ int epnum;
+ uint16_t epint;
+ uint16_t epmask;
+ uint32_t status;
+ USBD_Ep_TypeDef *ep;
+
+ DEBUG_USB_INT_HI_PUTCHAR( 'o' );
+
+ epint = USBDHAL_GetAllOutEpInts();
+ for ( epnum = 0, epmask = 1;
+ epnum <= MAX_NUM_OUT_EPS;
+ epnum++, epmask <<= 1 )
+ {
+ if ( epint & epmask )
+ {
+ ep = USBD_GetEpFromAddr( epnum );
+ status = USBDHAL_GetOutEpInts( ep );
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+ HandleOutEpIntr( status, ep );
+#else
+ if ( status & USB_DOEP_INT_XFERCOMPL )
+ {
+ USB_DOUTEPS[ epnum ].INT = USB_DOEP_INT_XFERCOMPL;
+ DEBUG_USB_INT_HI_PUTCHAR( 'c' );
+ ProcessOepData( ep );
+ }
+
+ /* Setup Phase Done */
+ if ( status & USB_DOEP0INT_SETUP )
+ {
+ ProcessSetup();
+ }
+#endif
+ }
+ }
+}
+
+#if !defined( USB_DOEP0INT_STUPPKTRCVD )
+static void ProcessOepData( USBD_Ep_TypeDef *ep )
+{
+ if ( ep->num == 0 )
+ {
+
+#ifdef __MBED__
+ int xfer_size = ep->packetSize - (( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_XFERSIZE_MASK )
+ >> _USB_DOEP0TSIZ_XFERSIZE_SHIFT);
+ int setup_pkt_received = USBDHAL_GetOutEpInts( ep ) & USB_DOEP0INT_SETUP;
+
+ if ( (!setup_pkt_received && xfer_size == 0) ||
+ (setup_pkt_received && xfer_size == 8) )
+ {
+ /* Higher levels need to see the correct transfer amount for ZLPs */
+ ep->remaining = 0;
+ ep->xferred = 0;
+ }
+ else
+ {
+ /* FIXME - does not work if actual read size > 56 */
+ if ( setup_pkt_received ) xfer_size -= 8;
+
+ ep->xferred = xfer_size;
+ ep->remaining -= xfer_size;
+ }
+#else
+ if ( ep->remaining > ep->packetSize )
+ {
+ ep->remaining -= ep->packetSize;
+ ep->xferred += ep->packetSize;
+ }
+ else
+ {
+ ep->xferred += ep->remaining;
+ ep->remaining = 0;
+ }
+#endif
+
+ USBDEP_Ep0Handler( dev );
+ }
+ else
+ {
+ ep->xferred = ep->hwXferSize -
+ ( ( USB_DOUTEPS[ ep->num ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK )>>
+ _USB_DOEP_TSIZ_XFERSIZE_SHIFT );
+ ep->remaining -= ep->xferred;
+ USBDEP_EpHandler( ep->addr );
+ }
+}
+#endif
+
+#if !defined( USB_DOEP0INT_STUPPKTRCVD )
+static void ProcessSetup( void )
+{
+ DEBUG_USB_INT_LO_PUTS( "\nS" );
+
+ if ( USB->DOEP0INT & USB_DOEP0INT_BACK2BACKSETUP )
+ { /* Back to back setup packets received */
+ USB->DOEP0INT = USB_DOEP0INT_BACK2BACKSETUP;
+ DEBUG_USB_INT_LO_PUTS( "B2B" );
+
+ dev->setup = (USB_Setup_TypeDef*)( USB->DOEP0DMAADDR - USB_SETUP_PKT_SIZE );
+ }
+ else
+ {
+ /* Read SETUP packet counter from hw. */
+ int supCnt = ( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_SUPCNT_MASK )
+ >> _USB_DOEP0TSIZ_SUPCNT_SHIFT;
+
+ if ( supCnt == 3 )
+ supCnt = 2;
+
+ dev->setup = &dev->setupPkt[ 2 - supCnt ];
+ }
+ USB->DOEP0TSIZ |= 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
+ USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
+ USB->DOEP0INT = USB_DOEP0INT_SETUP;
+
+ USBDEP_Ep0Handler( dev ); /* Call the SETUP handler for EP0 */
+}
+#endif
+
+/*
+ * Handle USB reset detected interrupt in suspend mode.
+ */
+static void Handle_USB_GINTSTS_RESETDET ( void )
+{
+#if ( USB_PWRSAVE_MODE )
+ if ( ! USBD_poweredDown )
+ {
+ USB->GINTSTS = USB_GINTSTS_RESETDET;
+ }
+
+ if ( UsbPowerUp() )
+ {
+ USB->GINTSTS = USB_GINTSTS_RESETDET;
+ }
+
+#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
+ /* Power down immediately if VBUS is off. */
+ if ( ! ( USB->STATUS & USB_STATUS_VREGOS ) )
+ {
+ UsbPowerDown();
+ }
+#endif
+
+#else
+ USB->GINTSTS = USB_GINTSTS_RESETDET;
+#endif /* if ( USB_PWRSAVE_MODE ) */
+
+ if ( USB->STATUS & USB_STATUS_VREGOS )
+ {
+ USBD_SetUsbState( USBD_STATE_DEFAULT );
+ }
+ else
+ {
+ USBD_SetUsbState( USBD_STATE_NONE );
+ }
+ DEBUG_USB_INT_LO_PUTS( "RsuP\n" );
+}
+
+/*
+ * Handle Start Of Frame (SOF) interrupt.
+ */
+static void Handle_USB_GINTSTS_SOF( void )
+{
+ USB->GINTSTS = USB_GINTSTS_SOF;
+
+ if ( dev->callbacks->sofInt )
+ {
+ dev->callbacks->sofInt(
+ ( USB->DSTS & _USB_DSTS_SOFFN_MASK ) >> _USB_DSTS_SOFFN_SHIFT );
+ }
+}
+
+/*
+ * Handle USB port reset interrupt.
+ */
+static void Handle_USB_GINTSTS_USBRST( void )
+{
+ int i;
+
+ DEBUG_USB_INT_LO_PUTS( "ReseT" );
+
+ /* Clear Remote Wakeup Signalling */
+ USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_RMTWKUPSIG );
+ USBHAL_FlushTxFifo( 0 );
+
+ /* Clear pending interrupts */
+ for ( i = 0; i <= MAX_NUM_IN_EPS; i++ )
+ {
+ USB_DINEPS[ i ].INT = 0xFFFFFFFF;
+ }
+
+ for ( i = 0; i <= MAX_NUM_OUT_EPS; i++ )
+ {
+ USB_DOUTEPS[ i ].INT = 0xFFFFFFFF;
+ }
+
+ USB->DAINTMSK = USB_DAINTMSK_INEPMSK0 | USB_DAINTMSK_OUTEPMSK0;
+#if defined( USB_DOEPMSK_STSPHSERCVDMSK )
+ USB->DOEPMSK = USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK
+ | USB_DOEPMSK_STSPHSERCVDMSK;
+#else
+ USB->DOEPMSK = USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK;
+#endif
+ USB->DIEPMSK = USB_DIEPMSK_XFERCOMPLMSK;
+
+ /* Reset Device Address */
+ USB->DCFG &= ~_USB_DCFG_DEVADDR_MASK;
+
+ /* Setup EP0 to receive SETUP packets */
+ USBDHAL_StartEp0Setup( dev );
+ USBDHAL_EnableInts( dev );
+
+ if ( dev->callbacks->usbReset )
+ {
+ dev->callbacks->usbReset();
+ }
+
+ USBD_SetUsbState( USBD_STATE_DEFAULT );
+ USBDHAL_AbortAllTransfers( USB_STATUS_DEVICE_RESET );
+}
+
+/*
+ * Handle USB port suspend interrupt.
+ */
+static void Handle_USB_GINTSTS_USBSUSP( void )
+{
+ USBD_State_TypeDef state;
+
+ USB->GINTSTS = USB_GINTSTS_USBSUSP;
+ USBDHAL_AbortAllTransfers( USB_STATUS_DEVICE_SUSPENDED );
+ DEBUG_USB_INT_LO_PUTS( "\nSusP" );
+
+ if ( USBD_GetUsbState() == USBD_STATE_NONE )
+ {
+ USBD_SetUsbState( USBD_STATE_POWERED );
+ }
+
+ state = USBD_GetUsbState();
+ if ( ( state == USBD_STATE_POWERED ) ||
+ ( state == USBD_STATE_DEFAULT ) ||
+ ( state == USBD_STATE_ADDRESSED ) ||
+ ( state == USBD_STATE_CONFIGURED ) )
+ {
+#if ( USB_PWRSAVE_MODE )
+ UsbPowerDown();
+#endif
+ USBD_SetUsbState( USBD_STATE_SUSPENDED );
+ }
+}
+
+/*
+ * Handle USB port wakeup interrupt.
+ */
+static void Handle_USB_GINTSTS_WKUPINT( void )
+{
+#if ( USB_PWRSAVE_MODE )
+ if ( ! USBD_poweredDown )
+ {
+ USB->GINTSTS = USB_GINTSTS_WKUPINT;
+ }
+
+ if ( UsbPowerUp() )
+ {
+ USB->GINTSTS = USB_GINTSTS_WKUPINT;
+ USBDHAL_StartEp0Setup( dev );
+ USBDHAL_Ep0Activate( dev->ep0MpsCode );
+ }
+#else
+ USB->GINTSTS = USB_GINTSTS_WKUPINT;
+#endif
+
+ USBD_SetUsbState( dev->savedState );
+ DEBUG_USB_INT_LO_PUTS( "WkuP\n" );
+}
+
+#if ( USB_PWRSAVE_MODE )
+/*
+ * Backup essential USB core registers, and set the core in partial powerdown
+ * mode. Optionally prepare entry into EM2.
+ */
+static bool UsbPowerDown( void )
+{
+#if ( NUM_EP_USED > 0 ) || ( FIFO_CNT > 0 )
+ int i;
+#endif
+#if ( NUM_EP_USED > 0 )
+ int epNum;
+ USBD_Ep_TypeDef *ep;
+#endif
+
+ if ( !USBD_poweredDown )
+ {
+ USBD_poweredDown = true;
+ DEBUG_USB_INT_LO_PUTCHAR( '\\' );
+
+ /* Backup USB core registers. */
+ x_USB_GINTMSK = USB->GINTMSK;
+#if defined(_USB_GOTGCTL_MASK)
+ x_USB_GOTGCTL = USB->GOTGCTL;
+#endif
+ x_USB_GAHBCFG = USB->GAHBCFG;
+ x_USB_GUSBCFG = USB->GUSBCFG;
+ x_USB_GRXFSIZ = USB->GRXFSIZ;
+ x_USB_GNPTXFSIZ = USB->GNPTXFSIZ;
+ x_USB_DCFG = USB->DCFG;
+ x_USB_DCTL = USB->DCTL;
+ x_USB_DAINTMSK = USB->DAINTMSK;
+ x_USB_DIEPMSK = USB->DIEPMSK;
+ x_USB_DOEPMSK = USB->DOEPMSK;
+ x_USB_PCGCCTL = USB->PCGCCTL;
+
+#if ( NUM_EP_USED > 0 )
+ for ( i = 0; i < NUM_EP_USED; i++ )
+ {
+ ep = &dev->ep[ i+1 ];
+ epNum = ep->num;
+ if ( ep->in )
+ {
+ x_USB_EP_CTL[ i ] = USB_DINEPS[ epNum ].CTL;
+ x_USB_EP_TSIZ[ i ] = USB_DINEPS[ epNum ].TSIZ;
+ x_USB_EP_DMAADDR[ i ] = USB_DINEPS[ epNum ].DMAADDR;
+ }
+ else
+ {
+ x_USB_EP_CTL[ i ] = USB_DOUTEPS[ epNum ].CTL;
+ x_USB_EP_TSIZ[ i ] = USB_DOUTEPS[ epNum ].TSIZ;
+ x_USB_EP_DMAADDR[ i ] = USB_DOUTEPS[ epNum ].DMAADDR;
+ }
+ }
+#endif
+
+#if ( FIFO_CNT > 0 )
+ for ( i = 0; i < FIFO_CNT; i++ )
+ {
+ x_USB_DIEPTXFS[ i ] = USB_DIEPTXFS[ i ];
+ }
+#endif
+
+ /* Prepare for wakeup on resume and reset. */
+ USB->DCFG = (USB->DCFG & ~_USB_DCFG_RESVALID_MASK) |
+ (4 << _USB_DCFG_RESVALID_SHIFT);
+ USB->DCFG |= USB_DCFG_ENA32KHZSUSP;
+ USB->GINTMSK = USB_GINTMSK_RESETDETMSK | USB_GINTMSK_WKUPINTMSK;
+
+ /* Enter partial powerdown mode. */
+ USB->PCGCCTL |= USB_PCGCCTL_PWRCLMP;
+ USB->PCGCCTL |= USB_PCGCCTL_RSTPDWNMODULE;
+ USB->PCGCCTL |= USB_PCGCCTL_STOPPCLK;
+
+ /* Record current clock settings. */
+ cmuStatus = CMU->STATUS;
+
+#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
+#ifndef __MBED__
+ /* Enter EM2 on interrupt exit. */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk;
+#else
+ usbhal_allow_em2(true);
+#endif
+#endif
+
+ /* Switch USBC clock to 32 kHz. */
+#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
+ CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;
+ while ( ( CMU->STATUS & CMU_STATUS_USBCLFXOSEL ) == 0 ){}
+#else
+ CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;
+ while ( ( CMU->STATUS & CMU_STATUS_USBCLFRCOSEL ) == 0 ){}
+#endif
+
+ return true;
+ }
+ return false;
+}
+#endif /* if ( USB_PWRSAVE_MODE ) */
+
+#if ( USB_PWRSAVE_MODE )
+/*
+ * Exit USB core partial powerdown mode, restore essential USB core registers.
+ * Will prevent re-entry back to EM2.
+ * Returns true if a powerup sequence was performed.
+ */
+static bool UsbPowerUp( void )
+{
+#if ( NUM_EP_USED > 0 ) || ( FIFO_CNT > 0 )
+ int i;
+#endif
+#if ( NUM_EP_USED > 0 )
+ int epNum;
+ uint32_t tmp;
+ USBD_Ep_TypeDef *ep;
+#endif
+
+ if ( USBD_poweredDown )
+ {
+ USBD_poweredDown = false;
+ DEBUG_USB_INT_LO_PUTCHAR( '/' );
+
+#if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
+ /* Switch HFCLK from HFRCO to HFXO. */
+ CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
+#endif
+
+ /* Turn off HFRCO when not needed. */
+ if ( ( cmuStatus & CMU_STATUS_HFRCOENS ) == 0 )
+ {
+ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
+ }
+
+ /* Exit partial powerdown mode. */
+ USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
+ USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE);
+
+ if (( USB->GINTSTS & ( USB_GINTSTS_WKUPINT | USB_GINTSTS_RESETDET ) ) == 0)
+ {
+ USB->DCTL = x_USB_DCTL | USB_DCTL_RMTWKUPSIG;
+ USB->DCTL = x_USB_DCTL;
+ }
+
+ /* Restore USB core registers. */
+ USB->GUSBCFG = x_USB_GUSBCFG;
+ USB->DCFG = x_USB_DCFG;
+
+#if ( FIFO_CNT > 0 )
+ for ( i = 0; i < FIFO_CNT; i++ )
+ {
+ USB_DIEPTXFS[ i ] = x_USB_DIEPTXFS[ i ];
+ }
+#endif
+
+#if ( NUM_EP_USED > 0 )
+ for ( i = 0; i < NUM_EP_USED; i++ )
+ {
+ ep = &dev->ep[ i+1 ];
+ epNum = ep->num;
+
+ tmp = x_USB_EP_CTL[ i ] &
+ ~( USB_DIEP_CTL_CNAK | USB_DIEP_CTL_SNAK |
+ USB_DIEP_CTL_SETD0PIDEF | USB_DIEP_CTL_SETD1PIDOF );
+
+ if ( x_USB_EP_CTL[ i ] & USB_DIEP_CTL_DPIDEOF )
+ tmp |= USB_DIEP_CTL_SETD1PIDOF;
+ else
+ tmp |= USB_DIEP_CTL_SETD0PIDEF;
+
+ if ( x_USB_EP_CTL[ i ] & USB_DIEP_CTL_NAKSTS )
+ tmp |= USB_DIEP_CTL_SNAK;
+ else
+ tmp |= USB_DIEP_CTL_CNAK;
+
+ if ( ep->in )
+ {
+ USB_DINEPS[ epNum ].CTL = tmp;
+ USB_DINEPS[ epNum ].TSIZ = x_USB_EP_TSIZ[ i ];
+ USB_DINEPS[ epNum ].DMAADDR = x_USB_EP_DMAADDR[ i ];
+ }
+ else
+ {
+ USB_DOUTEPS[ epNum ].CTL = tmp;
+ USB_DOUTEPS[ epNum ].TSIZ = x_USB_EP_TSIZ[ i ];
+ USB_DOUTEPS[ epNum ].DMAADDR = x_USB_EP_DMAADDR[ i ];
+ }
+ }
+#endif
+
+ USB->PCGCCTL = x_USB_PCGCCTL;
+ USB->DOEPMSK = x_USB_DOEPMSK;
+ USB->DIEPMSK = x_USB_DIEPMSK;
+ USB->DAINTMSK = x_USB_DAINTMSK;
+ USB->DCTL = x_USB_DCTL;
+ USB->GNPTXFSIZ = x_USB_GNPTXFSIZ;
+ USB->GRXFSIZ = x_USB_GRXFSIZ;
+ USB->GAHBCFG = x_USB_GAHBCFG;
+#if defined(_USB_GOTGCTL_MASK)
+ USB->GOTGCTL = x_USB_GOTGCTL;
+#endif
+ USB->GINTMSK = x_USB_GINTMSK;
+
+ USB->DCTL |= USB_DCTL_PWRONPRGDONE;
+
+#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
+#ifndef __MBED__
+ /* Do not reenter EM2 on interrupt exit. */
+ SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk);
+#else
+ usbhal_allow_em2(false);
+#endif
+#endif
+
+ return true;
+ }
+ return false;
+}
+#endif /* if ( USB_PWRSAVE_MODE ) */
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+static void HandleOutEpIntr( uint32_t status, USBD_Ep_TypeDef *ep )
+{
+ uint32_t doeptsiz;
+
+ if ( ep->num == 0 )
+ {
+ if ( status & USB_DOEP0INT_XFERCOMPL )
+ {
+ USB->DOEP0INT = USB_DOEP0INT_XFERCOMPL;
+ doeptsiz = USB->DOEP0TSIZ;
+
+ if ( ep->state == D_EP_IDLE )
+ {
+ if ( status & USB_DOEP0INT_STUPPKTRCVD )
+ {
+ USB->DOEP0INT = USB_DOEP0INT_STUPPKTRCVD;
+ }
+ status = USBDHAL_GetOutEpInts( ep );
+ doeptsiz = USB->DOEP0TSIZ;
+
+ if ( status & USB_DOEP0INT_SETUP )
+ {
+retry:
+ /* Already started data stage, clear setup */
+ USB->DOEP0INT = USB_DOEP0INT_SETUP;
+ status &= ~USB_DOEP0INT_SETUP;
+ {
+ int supCnt = ( doeptsiz & _USB_DOEP0TSIZ_SUPCNT_MASK )
+ >> _USB_DOEP0TSIZ_SUPCNT_SHIFT;
+
+ if ( supCnt == 3 )
+ supCnt = 2;
+
+ dev->setup = &dev->setupPkt[ 2 - supCnt ];
+ }
+ DEBUG_USB_INT_LO_PUTS( "\nS" );
+ USBDEP_Ep0Handler( dev );
+
+ /* Prepare for more setup packets */
+ if ( ep->state == D_EP0_IN_STATUS || ep->state == D_EP_TRANSMITTING )
+ {
+ USBDHAL_StartEp0Setup( dev );
+ }
+ }
+ else /* xfercompl && idle && !setup */
+ {
+ status = USBDHAL_GetOutEpInts( ep );
+ if ( status & USB_DOEP0INT_SETUP )
+ goto retry;
+ USBDHAL_StartEp0Setup( dev );
+ }
+ }
+ else /* ep0state != EP0_IDLE */
+ {
+#ifdef __MBED__
+ if ( ep->state == D_EP_RECEIVING )
+ {
+ int xfer_size = ep->packetSize - (( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_XFERSIZE_MASK )
+ >> _USB_DOEP0TSIZ_XFERSIZE_SHIFT);
+ int setup_pkt_received = status & USB_DOEP0INT_SETUP;
+
+ if ( (!setup_pkt_received && xfer_size == 0) ||
+ (setup_pkt_received && xfer_size == 8) )
+ {
+ /* Higher levels need to see the correct transfer amount for ZLPs */
+ ep->remaining = 0;
+ ep->xferred = 0;
+ }
+ else
+ {
+ /* FIXME - does not work if actual read size > 56 */
+ if ( setup_pkt_received ) xfer_size -= 8;
+
+ ep->xferred = xfer_size;
+ ep->remaining -= xfer_size;
+ }
+
+ USBDEP_Ep0Handler( dev );
+ }
+#else
+ if ( ep->state == D_EP_RECEIVING )
+ {
+ if ( ep->remaining > ep->packetSize )
+ {
+ ep->remaining -= ep->packetSize;
+ ep->xferred += ep->packetSize;
+ }
+ else
+ {
+ ep->xferred += ep->remaining;
+ ep->remaining = 0;
+ }
+ USBDEP_Ep0Handler( dev );
+ }
+ else if ( ep->state == D_EP0_OUT_STATUS )
+ {
+ USBDEP_Ep0Handler( dev );
+ }
+#endif
+ }
+ } /* if ( status & USB_DOEP0INT_XFERCOMPL ) */
+
+ if ( status & USB_DOEP0INT_STSPHSERCVD )
+ {
+ USB->DOEP0INT = USB_DOEP0INT_STSPHSERCVD;
+ }
+
+ if ( status & USB_DOEP0INT_SETUP )
+ {
+ USB->DOEP0INT = USB_DOEP0INT_SETUP;
+ {
+ int supCnt = ( USB->DOEP0TSIZ & _USB_DOEP0TSIZ_SUPCNT_MASK )
+ >> _USB_DOEP0TSIZ_SUPCNT_SHIFT;
+
+ if ( supCnt == 3 )
+ supCnt = 2;
+
+ dev->setup = &dev->setupPkt[ 2 - supCnt ];
+ }
+ DEBUG_USB_INT_LO_PUTS( "\nS" );
+ USBDEP_Ep0Handler( dev );
+ }
+ }
+ else /* epnum != 0 */
+ {
+ if ( status & USB_DOEP_INT_XFERCOMPL )
+ {
+ USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_XFERCOMPL;
+
+ ep->xferred = ep->hwXferSize -
+ ( ( USB_DOUTEPS[ ep->num ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK )>>
+ _USB_DOEP_TSIZ_XFERSIZE_SHIFT );
+ ep->remaining -= ep->xferred;
+
+ USBDEP_EpHandler( ep->addr );
+ }
+ }
+}
+#endif
+
+/** @endcond */
+
+#endif /* defined( USB_DEVICE ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/src/em_usbhal.c Thu Aug 13 15:46:06 2015 +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 ) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/src/em_usbtimer.c Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,381 @@
+/***************************************************************************//**
+ * @file em_usbtimer.c
+ * @brief USB protocol stack library, timer API.
+ * @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_cmu.h"
+#include "em_timer.h"
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+
+#include "device_peripherals.h"
+
+/*
+ * Use one HW timer to serve n software milisecond timers.
+ * A timer is, when running, in a linked list of timers.
+ * A given timers timeout period is the acculmulated timeout
+ * of all timers preceeding it in the queue.
+ * This makes timer start (linked list insertion) computing intensive,
+ * but the checking of the queue at each tick very effective.
+ * ______ ______ ______
+ * | | --->| | --->| |
+ * head --> | | | | | | | |
+ * |______|--- |______|--- |______|---/ NULL
+ */
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#ifndef USB_TIMER
+#error HW platform must define the timer to use for USB
+#endif
+
+#if ( USB_TIMER == USB_TIMER0 ) && ( TIMER_COUNT >= 1 )
+ #define TIMER TIMER0
+ #define TIMER_CLK cmuClock_TIMER0
+ #define TIMER_IRQ TIMER0_IRQn
+ #define TIMER_IRQHandler TIMER0_IRQHandler
+
+#elif ( USB_TIMER == USB_TIMER1 ) && ( TIMER_COUNT >= 2 )
+ #define TIMER TIMER1
+ #define TIMER_CLK cmuClock_TIMER1
+ #define TIMER_IRQ TIMER1_IRQn
+ #define TIMER_IRQHandler TIMER1_IRQHandler
+
+#elif ( USB_TIMER == USB_TIMER2 ) && ( TIMER_COUNT >= 3 )
+ #define TIMER TIMER2
+ #define TIMER_CLK cmuClock_TIMER2
+ #define TIMER_IRQ TIMER2_IRQn
+ #define TIMER_IRQHandler TIMER2_IRQHandler
+
+#elif ( USB_TIMER == USB_TIMER3 ) && ( TIMER_COUNT == 4 )
+ #define TIMER TIMER3
+ #define TIMER_CLK cmuClock_TIMER3
+ #define TIMER_IRQ TIMER3_IRQn
+ #define TIMER_IRQHandler TIMER3_IRQHandler
+
+#else
+#error "Illegal USB TIMER definition"
+#endif
+
+typedef struct _timer
+{
+ uint32_t timeout; /* Delta value relative to prev. timer */
+ struct _timer *next;
+ USBTIMER_Callback_TypeDef callback;
+ bool running;
+} USBTIMER_Timer_TypeDef;
+
+#if ( NUM_QTIMERS > 0 )
+static USBTIMER_Timer_TypeDef timers[ NUM_QTIMERS ];
+static USBTIMER_Timer_TypeDef *head = NULL;
+#endif
+
+static uint32_t ticksPrMs, ticksPr1us, ticksPr10us, ticksPr100us;
+
+#if ( NUM_QTIMERS > 0 )
+
+static void TimerTick( void );
+
+void TIMER_IRQHandler( void )
+{
+ uint32_t flags;
+
+ flags = TIMER_IntGet( TIMER );
+
+ if ( flags & TIMER_IF_CC0 )
+ {
+ TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
+ TIMER_CompareSet( TIMER, 0, TIMER_CaptureGet( TIMER, 0 ) + ticksPrMs );
+ TimerTick();
+ }
+}
+#endif /* ( NUM_QTIMERS > 0 ) */
+
+static void DelayTicks( uint16_t ticks )
+{
+ uint16_t startTime;
+ volatile uint16_t now;
+
+ if ( ticks )
+ {
+ startTime = TIMER_CounterGet( TIMER );
+ do
+ {
+ now = TIMER_CounterGet(TIMER);
+ } while ( (uint16_t)( now - startTime ) < ticks );
+ }
+}
+
+/** @endcond */
+
+/** @addtogroup USB_COMMON
+ * @{*/
+
+/***************************************************************************//**
+ * @brief
+ * Active wait millisecond delay function. Can also be used inside
+ * interrupt handlers.
+ *
+ * @param[in] msec
+ * Number of milliseconds to wait.
+ ******************************************************************************/
+void USBTIMER_DelayMs( uint32_t msec )
+{
+ uint64_t totalTicks;
+
+ totalTicks = (uint64_t)ticksPrMs * msec;
+ while ( totalTicks > 20000 )
+ {
+ DelayTicks( 20000 );
+ totalTicks -= 20000;
+ }
+ DelayTicks( (uint16_t)totalTicks );
+}
+
+/***************************************************************************//**
+ * @brief
+ * Active wait microsecond delay function. Can also be used inside
+ * interrupt handlers.
+ *
+ * @param[in] usec
+ * Number of microseconds to wait.
+ ******************************************************************************/
+void USBTIMER_DelayUs( uint32_t usec )
+{
+ uint64_t totalTicks;
+
+ totalTicks = (uint64_t)ticksPr1us * usec;
+ if ( totalTicks == 0 )
+ {
+ usec /= 10;
+ totalTicks = (uint64_t)ticksPr10us * usec;
+
+ if ( totalTicks == 0 )
+ {
+ usec /= 10;
+ totalTicks = (uint64_t)ticksPr100us * usec;
+ }
+ }
+
+ while ( totalTicks > 60000 )
+ {
+ DelayTicks( 60000 );
+ totalTicks -= 60000;
+ }
+ DelayTicks( (uint16_t)totalTicks );
+}
+
+/***************************************************************************//**
+ * @brief
+ * Activate the hardware timer used to pace the 1 millisecond timer system.
+ *
+ * @details
+ * Call this function whenever the HFPERCLK frequency is changed.
+ * This function is initially called by HOST and DEVICE stack xxxx_Init()
+ * functions.
+ ******************************************************************************/
+void USBTIMER_Init( void )
+{
+ uint32_t freq;
+ TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
+ TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;
+
+ freq = CMU_ClockFreqGet( cmuClock_HFPER );
+ ticksPrMs = ( freq + 500 ) / 1000;
+ ticksPr1us = ( freq + 500000 ) / 1000000;
+ ticksPr10us = ( freq + 50000 ) / 100000;
+ ticksPr100us = ( freq + 5000 ) / 10000;
+
+ timerCCInit.mode = timerCCModeCompare;
+ CMU_ClockEnable( TIMER_CLK, true );
+ TIMER_TopSet( TIMER, 0xFFFF );
+ TIMER_InitCC( TIMER, 0, &timerCCInit );
+ TIMER_Init( TIMER, &timerInit );
+
+#if ( NUM_QTIMERS > 0 )
+ TIMER_IntClear( TIMER, 0xFFFFFFFF );
+ TIMER_IntEnable( TIMER, TIMER_IEN_CC0 );
+ TIMER_CompareSet( TIMER, 0, TIMER_CounterGet( TIMER ) + ticksPrMs );
+ NVIC_ClearPendingIRQ( TIMER_IRQ );
+ NVIC_EnableIRQ( TIMER_IRQ );
+#endif /* ( NUM_QTIMERS > 0 ) */
+}
+
+#if ( NUM_QTIMERS > 0 ) || defined( DOXY_DOC_ONLY )
+/***************************************************************************//**
+ * @brief
+ * Start a timer.
+ *
+ * @details
+ * If the timer is already running, it will be restarted with new timeout.
+ *
+ * @param[in] id
+ * Timer id (0..).
+ *
+ * @param[in] timeout
+ * Number of milliseconds before timer will elapse.
+ *
+ * @param[in] callback
+ * Function to be called on timer elapse, ref. @ref USBTIMER_Callback_TypeDef.
+ ******************************************************************************/
+void USBTIMER_Start( uint32_t id, uint32_t timeout,
+ USBTIMER_Callback_TypeDef callback )
+{
+ uint32_t accumulated;
+ USBTIMER_Timer_TypeDef *this, **last;
+
+ INT_Disable();
+
+ if ( timers[ id ].running )
+ {
+ USBTIMER_Stop( id );
+ }
+
+ if ( timeout == 0 )
+ {
+ callback();
+ INT_Enable();
+ return;
+ }
+
+ timers[ id ].running = true;
+ timers[ id ].callback = callback;
+ timers[ id ].next = NULL;
+
+ if ( !head ) /* Queue empty ? */
+ {
+ timers[ id ].timeout = timeout;
+ head = &timers[ id ];
+ }
+ else
+ {
+ this = head;
+ last = &head;
+ accumulated = 0;
+
+ /* Do a sorted insert */
+ while ( this )
+ {
+ if ( timeout < accumulated + this->timeout ) /* Insert before "this" ? */
+ {
+ timers[ id ].timeout = timeout - accumulated;
+ timers[ id ].next = this;
+ *last = &timers[ id ];
+ this->timeout -= timers[ id ].timeout; /* Adjust timeout */
+ break;
+ }
+ else if ( this->next == NULL ) /* At end of queue ? */
+ {
+ timers[ id ].timeout = timeout - accumulated - this->timeout;
+ this->next = &timers[ id ];
+ break;
+ }
+ accumulated += this->timeout;
+ last = &this->next;
+ this = this->next;
+ }
+ }
+
+ INT_Enable();
+}
+
+/***************************************************************************//**
+ * @brief
+ * Stop a timer.
+ *
+ * @param[in] id
+ * Timer id (0..).
+ ******************************************************************************/
+void USBTIMER_Stop( uint32_t id )
+{
+ USBTIMER_Timer_TypeDef *this, **last;
+
+ INT_Disable();
+
+ if ( head ) /* Queue empty ? */
+ {
+ this = head;
+ last = &head;
+ timers[ id ].running = false;
+
+ while ( this )
+ {
+ if ( this == &timers[ id ] ) /* Correct timer ? */
+ {
+ if ( this->next )
+ {
+ this->next->timeout += timers[ id ].timeout; /* Adjust timeout */
+ }
+ *last = this->next;
+ break;
+ }
+ last = &this->next;
+ this = this->next;
+ }
+ }
+
+ INT_Enable();
+}
+#endif /* ( NUM_QTIMERS > 0 ) */
+
+/** @} (end addtogroup USB_COMMON) */
+
+#if ( NUM_QTIMERS > 0 )
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+static void TimerTick( void )
+{
+ USBTIMER_Callback_TypeDef cb;
+
+ INT_Disable();
+
+ if ( head )
+ {
+ head->timeout--;
+
+ while ( head )
+ {
+ if ( head->timeout == 0 )
+ {
+ cb = head->callback;
+ head->running = false;
+ head = head->next;
+ /* The callback may place new items in the queue !!! */
+ if ( cb )
+ {
+ (cb)();
+ }
+ continue; /* There might be more than one timeout pr. tick */
+ }
+ break;
+ }
+ }
+
+ INT_Enable();
+}
+/** @endcond */
+#endif /* ( NUM_QTIMERS > 0 ) */
+
+#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
--- a/USBDevice/USBEndpoints.h Wed Jul 08 14:46:06 2015 +0100 +++ b/USBDevice/USBEndpoints.h Thu Aug 13 15:46:06 2015 +0100 @@ -49,6 +49,8 @@ #include "USBEndpoints_RZ_A1H.h" #elif defined(TARGET_Maxim) #include "USBEndpoints_Maxim.h" +#elif defined(TARGET_EFM32GG_STK3700) || defined(TARGET_EFM32LG_STK3600) || defined(TARGET_EFM32WG_STK3800) || defined(TARGET_EFM32HG_STK3400) +#include "USBEndpoints_EFM32.h" #else #error "Unknown target type" #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice/USBEndpoints_EFM32.h Thu Aug 13 15:46:06 2015 +0100 @@ -0,0 +1,65 @@ + +#ifndef TARGET_EFM32HG_STK3400 +# define NUMBER_OF_LOGICAL_ENDPOINTS (6) +#else +# define NUMBER_OF_LOGICAL_ENDPOINTS (3) +#endif + +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) +#define NUMBER_OF_ENDPOINTS (NUMBER_OF_PHYSICAL_ENDPOINTS + 2) /* Includes EP0 */ + +#define EP0OUT (0) +#define EP0IN (1) +#define EP1OUT (2) +#define EP1IN (3) +#define EP2OUT (4) +#define EP2IN (5) +#define EP3OUT (6) +#define EP3IN (7) +#ifndef TARGET_EFM32HG_STK3400 +# define EP4OUT (8) +# define EP4IN (9) +# define EP5OUT (10) +# define EP5IN (11) +# define EP6OUT (12) +# define EP6IN (13) +#endif + +#define USB_EP_TO_INDEX(ep) (ep) +#define USB_EP_TO_ADDR(ep) (((ep)>>1) | (((ep) & 1 ) ? 0x80 : 0x00)) +#define USB_ADDR_TO_EP(ep) (((ep)<<1) | (((ep) & 0x80) ? 0x01 : 0x00)) + +/* Maximum Packet sizes */ + +#define MAX_PACKET_SIZE_EP0 64 +#define MAX_PACKET_SIZE_EP1 64 +#define MAX_PACKET_SIZE_EP2 64 +#define MAX_PACKET_SIZE_EP3 64 +#ifndef TARGET_EFM32HG_STK3400 +# define MAX_PACKET_SIZE_EP4 64 +# define MAX_PACKET_SIZE_EP5 64 +# define MAX_PACKET_SIZE_EP6 64 +#endif + +/* Generic endpoints - intended to be portable accross devices */ +/* and be suitable for simple USB devices. */ + +/* Bulk endpoints */ +#define EPBULK_OUT EP2OUT +#define EPBULK_IN EP2IN +#define EPBULK_OUT_callback EP2_OUT_callback +#define EPBULK_IN_callback EP2_IN_callback +/* Interrupt endpoints */ +#define EPINT_OUT EP1OUT +#define EPINT_IN EP1IN +#define EPINT_OUT_callback EP1_OUT_callback +#define EPINT_IN_callback EP1_IN_callback +/* Isochronous endpoints */ +#define EPISO_OUT EP3OUT +#define EPISO_IN EP3IN +#define EPISO_OUT_callback EP3_OUT_callback +#define EPISO_IN_callback EP3_IN_callback + +#define MAX_PACKET_SIZE_EPBULK 64 +#define MAX_PACKET_SIZE_EPINT 64 +#define MAX_PACKET_SIZE_EPISO 1023
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHAL_EFM32.cpp Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,775 @@
+/* Copyright 2015 Silicon Labs, http://www.silabs.com
+ *
+ * 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.
+ */
+
+#if defined TARGET_EFM32GG_STK3700 || \
+ defined TARGET_EFM32LG_STK3600 || \
+ defined TARGET_EFM32WG_STK3800 || \
+ defined TARGET_EFM32HG_STK3400
+
+#include "USBHAL.h"
+#include "em_usb.h"
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+#include "em_usbd.h"
+
+#include "sleepmodes.h"
+
+enum USBISRCommand {
+ CMD_HANDLED = 0,
+ CMD_EP0SETUP,
+ CMD_EP0IN,
+ CMD_EP0OUT,
+ CMD_EP_XFER_COMPLETED,
+ CMD_SOF,
+ CMD_BUSRESET,
+ CMD_SUSPEND_STATE_CHANGED,
+ CMD_ENUM_END_MARKER
+};
+
+enum IEPStatus {
+ NOT_CONFIGURED = 0,
+ IDLE = 1,
+ READ_PENDING = 2,
+ WRITE_PENDING = 3,
+ READ_COMPLETE = 4,
+ WRITE_COMPLETE = 5,
+ FAILED_INVALID = 6,
+ FAILED_STALLED = 7
+};
+
+typedef struct {
+ IEPStatus status;
+ uint32_t byte_count;
+ uint32_t max_packet;
+ USB_XferCompleteCb_TypeDef intern_cb;
+ uint8_t *data_buf;
+} ep_state_t;
+
+USBHAL * USBHAL::instance;
+static uint8_t ep0setupdata[8];
+static ep_state_t ep_state[NUMBER_OF_ENDPOINTS];
+#ifdef USB_USE_DYNAMIC_MEMORY
+static uint8_t ep0in_data_buf[MAX_PACKET_SIZE_EP0] __attribute__ ((aligned (4)));
+static uint8_t ep0out_data_buf[MAX_PACKET_SIZE_EP0]; // FIXME: does this need to be this big?
+#else
+static uint8_t ep_data_buf[NUMBER_OF_ENDPOINTS][64] __attribute__ ((aligned (4)));
+#endif
+
+static void run_cmd(USBISRCommand cmd, uint32_t param);
+static void (*isrptr)() = NULL;
+static USBISRCommand usb_isrcmd = CMD_HANDLED;
+static uint32_t usb_isrcmd_param = 0;
+
+extern "C" void usbhal_allow_em2(bool allow_em2);
+
+#ifdef DEBUG_USB_API
+#define TRACE(fmt,...) printf("USB: %s: " fmt "\n", __func__, __VA_ARGS__);
+#define TRACE_FUNC_IN printf("USB: > %s\n",__func__);
+#define TRACE_FUNC_IN_P(fmt, ...) printf("USB: > %s: " fmt "\n", __func__, __VA_ARGS__);
+#else
+#define TRACE(fmt,...)
+#define TRACE_FUNC_IN
+#define TRACE_FUNC_IN_P(fmt, ...)
+#endif
+
+static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize);
+
+static int usbhal_xfer_complete_cb(uint8_t epaddr, USB_Status_TypeDef status,
+ uint32_t xferred, uint32_t remaining);
+static void usbhal_free_buffers(void);
+
+/* Internal EP transfer complete callbacks */
+#define EPCB(n) static int usbhal_xfer_complete_cb_##n(USB_Status_TypeDef status, \
+ uint32_t xferred, uint32_t remaining) { \
+ return usbhal_xfer_complete_cb(n, status, xferred, remaining); \
+}
+/* ------^ */
+EPCB(EP0OUT)
+EPCB(EP0IN)
+EPCB(EP1OUT)
+EPCB(EP1IN)
+EPCB(EP2OUT)
+EPCB(EP2IN)
+EPCB(EP3OUT)
+EPCB(EP3IN)
+#ifndef TARGET_EFM32HG_STK3400
+EPCB(EP4OUT)
+EPCB(EP4IN)
+EPCB(EP5OUT)
+EPCB(EP5IN)
+EPCB(EP6OUT)
+EPCB(EP6IN)
+#endif
+
+static inline bool is_aligned(const void *pointer, size_t byte_count)
+{
+ return ((uintptr_t)pointer % byte_count == 0);
+}
+
+USBHAL::USBHAL(void)
+{
+ TRACE_FUNC_IN;
+
+ isrptr = &USBHAL::_usbisr;
+
+ if (instance) {
+ TRACE("Assert self failed! instance=%p", instance);
+ abort();
+ }
+ instance = this;
+
+ // When USB is active, we can't go below EM1. This block may
+ // be dynamically removed/reinstated to allow deeper sleep.
+ usbhal_allow_em2(false);
+
+ // When in suspend / Vbus off we can go to EM2, but never below
+ // that as long as USB is being used. Despite the name the call here
+ // blocks entering modes _below_ EM2, but allows EM2.
+ blockSleepMode(EM2);
+
+ epCallback[EP0OUT] = NULL;
+ epCallback[EP0IN ] = NULL;
+ epCallback[EP1OUT] = &USBHAL::EP1_OUT_callback;
+ epCallback[EP1IN ] = &USBHAL::EP1_IN_callback;
+ epCallback[EP2OUT] = &USBHAL::EP2_OUT_callback;
+ epCallback[EP2IN ] = &USBHAL::EP2_IN_callback;
+ epCallback[EP3OUT] = &USBHAL::EP3_OUT_callback;
+ epCallback[EP3IN ] = &USBHAL::EP3_IN_callback;
+#ifndef TARGET_EFM32HG_STK3400
+ epCallback[EP4OUT] = &USBHAL::EP4_OUT_callback;
+ epCallback[EP4IN ] = &USBHAL::EP4_IN_callback;
+ epCallback[EP5OUT] = &USBHAL::EP5_OUT_callback;
+ epCallback[EP5IN ] = &USBHAL::EP5_IN_callback;
+ epCallback[EP6OUT] = &USBHAL::EP6_OUT_callback;
+ epCallback[EP6IN ] = &USBHAL::EP6_IN_callback;
+#endif
+
+ memset(ep_state, 0, sizeof(ep_state));
+
+ ep_state[EP0OUT].intern_cb = usbhal_xfer_complete_cb_EP0OUT;
+ ep_state[EP0IN ].intern_cb = usbhal_xfer_complete_cb_EP0IN;
+ ep_state[EP1OUT].intern_cb = usbhal_xfer_complete_cb_EP1OUT;
+ ep_state[EP1IN ].intern_cb = usbhal_xfer_complete_cb_EP1IN;
+ ep_state[EP2OUT].intern_cb = usbhal_xfer_complete_cb_EP2OUT;
+ ep_state[EP2IN ].intern_cb = usbhal_xfer_complete_cb_EP2IN;
+ ep_state[EP3OUT].intern_cb = usbhal_xfer_complete_cb_EP3OUT;
+ ep_state[EP3IN ].intern_cb = usbhal_xfer_complete_cb_EP3IN;
+#ifndef TARGET_EFM32HG_STK3400
+ ep_state[EP4OUT].intern_cb = usbhal_xfer_complete_cb_EP4OUT;
+ ep_state[EP4IN ].intern_cb = usbhal_xfer_complete_cb_EP4IN;
+ ep_state[EP5OUT].intern_cb = usbhal_xfer_complete_cb_EP5OUT;
+ ep_state[EP5IN ].intern_cb = usbhal_xfer_complete_cb_EP5IN;
+ ep_state[EP6OUT].intern_cb = usbhal_xfer_complete_cb_EP6OUT;
+ ep_state[EP6IN ].intern_cb = usbhal_xfer_complete_cb_EP6IN;
+#endif
+
+#ifdef USB_USE_DYNAMIC_MEMORY
+ ep_state[EP0OUT].data_buf = ep0out_data_buf;
+ ep_state[EP0IN].data_buf = ep0in_data_buf;
+#else
+ for (int i=0 ; i<NUMBER_OF_ENDPOINTS ; i++) {
+ ep_state[i].data_buf = ep_data_buf[i];
+ }
+#endif
+}
+
+USBHAL::~USBHAL(void)
+{
+ TRACE_FUNC_IN;
+ USBD_AbortAllTransfers();
+ USBD_Disconnect();
+ usbhal_free_buffers();
+
+ usbhal_allow_em2(true);
+ unblockSleepMode(EM2);
+}
+
+extern "C" void usbhal_allow_em2(bool allow_em2)
+{
+ if (allow_em2) {
+ // unblockSleepMode is safe to call even if we would unblock
+ // an already unblocked mode, so no checks here.
+ unblockSleepMode(EM1);
+ } else {
+ blockSleepMode(EM1);
+ }
+}
+
+static void usbhal_reset_cb(void)
+{
+ TRACE_FUNC_IN;
+ run_cmd(CMD_BUSRESET, 0);
+}
+
+#ifdef DEBUG_USB_API
+static const char *usbstate[] = { "NONE", "ATTACHED", "POWERED", "DEFAULT",
+ "ADDRESSED", "CONFIGURED", "SUSPENDED", "???" };
+#endif
+
+static void usbhal_state_change_cb(USBD_State_TypeDef oldState,
+ USBD_State_TypeDef newState)
+{
+ TRACE("state changed %s -> %s", usbstate[oldState], usbstate[newState]);
+
+ if (oldState == USBD_STATE_SUSPENDED) {
+ run_cmd(CMD_SUSPEND_STATE_CHANGED, 0);
+ }
+
+ if (newState == USBD_STATE_SUSPENDED) {
+ run_cmd(CMD_SUSPEND_STATE_CHANGED, 1);
+ }
+
+ // Should call connectStateChanged from here as well but there is
+ // no documentation on when to actually do so. (And the implementation
+ // in USBDevice.cpp is a stub)
+
+ // HACK! Since connectStateChanged is not used, indicate the loss
+ // off connection by reporting a bus reset. This causes USBDevice
+ // to realise that at least it's not in CONFIGURED anymore, and
+ // stop trying to read/write in a busyloop.
+ if (newState == USBD_STATE_NONE) {
+ run_cmd(CMD_BUSRESET, 0);
+ }
+}
+
+static int usbhal_setupcmd_cb(const USB_Setup_TypeDef *setup)
+{
+ TRACE_FUNC_IN;
+ if (!setup) {
+ EFM_ASSERT(false);
+ return USB_STATUS_REQ_ERR;
+ }
+
+ memcpy(ep0setupdata, setup, 8);
+ run_cmd(CMD_EP0SETUP, 0);
+
+ return USB_STATUS_OK;
+}
+
+static void usbhal_sof_cb(uint16_t frameNum)
+{
+ run_cmd(CMD_SOF, frameNum);
+}
+
+static void usbhal_free_buffers(void)
+{
+#ifdef USB_USE_DYNAMIC_MEMORY
+ TRACE_FUNC_IN;
+
+ for (int i=EP1OUT ; i<NUMBER_OF_ENDPOINTS ; i++ ) {
+ if (ep_state[i].data_buf) {
+ free(ep_state[i].data_buf);
+ ep_state[i].data_buf = NULL;
+ }
+ }
+#endif
+}
+
+void USBHAL::connect(void)
+{
+ TRACE_FUNC_IN;
+
+ // Init datastructures must be static - driver will use these even after the init function exits!
+
+ static const uint8_t buffer_multiplier[] = { 1 }; // Mult 1 for control EP
+ static const USBD_Callbacks_TypeDef usbd_callbacks = {
+ .usbReset = usbhal_reset_cb,
+ .usbStateChange = usbhal_state_change_cb,
+ .setupCmd = usbhal_setupcmd_cb,
+ .isSelfPowered = NULL,
+ .sofInt = usbhal_sof_cb
+ };
+
+ USBD_Init_TypeDef initdata = {
+ .deviceDescriptor = NULL,
+ .configDescriptor = NULL,
+ .stringDescriptors = NULL,
+ .numberOfStrings = 0,
+ .bufferingMultiplier = buffer_multiplier,
+ .callbacks = &usbd_callbacks,
+ .reserved = 0
+ };
+
+ int ret = USBD_Init(&initdata);
+
+ TRACE("init = %d, devicedesc = %lx, configdesc = %lx", ret,
+ (uint32_t) initdata.deviceDescriptor,
+ (uint32_t) initdata.configDescriptor);
+
+ EFM_ASSERT(ret == USB_STATUS_OK);
+}
+
+void USBHAL::disconnect(void)
+{
+ TRACE_FUNC_IN;
+ USBD_Disconnect();
+}
+
+void USBHAL::configureDevice(void)
+{
+ TRACE_FUNC_IN;
+ USBD_SetUsbState(USBD_STATE_CONFIGURED);
+}
+
+void USBHAL::unconfigureDevice(void)
+{
+ TRACE_FUNC_IN;
+ USBD_SetUsbState(USBD_STATE_DEFAULT);
+ usbhal_free_buffers();
+}
+
+void USBHAL::setAddress(uint8_t address)
+{
+ TRACE_FUNC_IN_P("addr 0x%x", (unsigned)address);
+ USBD_SetAddress(address);
+}
+
+void USBHAL::remoteWakeup(void)
+{
+ TRACE_FUNC_IN;
+ USBD_RemoteWakeup();
+}
+
+void USBHAL::EP0setup(uint8_t *buffer)
+{
+ TRACE_FUNC_IN;
+ EFM_ASSERT(buffer);
+ if (buffer) {
+ memcpy(buffer, ep0setupdata, 8);
+ }
+}
+
+void USBHAL::EP0read(void)
+{
+ TRACE_FUNC_IN;
+ (void)internEndpointRead(0, MAX_PACKET_SIZE_EP0);
+}
+
+void USBHAL::EP0readStage(void)
+{
+ TRACE_FUNC_IN;
+ // Not needed
+}
+
+uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
+{
+ TRACE_FUNC_IN;
+ EFM_ASSERT(buffer);
+
+ uint32_t read = 0;
+ endpointReadResult(0, buffer, &read);
+ return read;
+}
+
+static int usbhal_xfer_complete_cb(uint8_t ep, USB_Status_TypeDef status,
+ uint32_t xferred, uint32_t remaining)
+{
+ TRACE_FUNC_IN_P("ep 0x%x, status %u, xferred %lu, rem %lu",
+ ep, status, xferred, remaining);
+
+ if (ep >= NUMBER_OF_ENDPOINTS) {
+ EFM_ASSERT(false);
+ return USB_STATUS_REQ_ERR;
+ }
+
+ switch (ep) {
+ case EP0OUT:
+ if (ep_state[EP0OUT].status == READ_PENDING) {
+ ep_state[EP0OUT].status = READ_COMPLETE;
+ ep_state[EP0OUT].byte_count = xferred;
+ // drop zlp
+ if (xferred == 0) {
+ break;
+ }
+ }
+ run_cmd(CMD_EP0OUT, 0);
+ break;
+
+ case EP0IN:
+ run_cmd(CMD_EP0IN, 0);
+ break;
+
+ default:
+ bool write = ep & 1;
+
+ if (status == USB_STATUS_OK) {
+ if (!write && ep_state[ep].status == READ_PENDING) {
+ ep_state[ep].status = READ_COMPLETE;
+ ep_state[ep].byte_count = xferred;
+ } else if (write && ep_state[ep].status == WRITE_PENDING) {
+ ep_state[ep].status = WRITE_COMPLETE;
+ } else {
+ ep_state[ep].status = FAILED_INVALID;
+ }
+ } else {
+ ep_state[ep].status = FAILED_INVALID;
+ }
+
+ if (ep_state[ep].status != FAILED_INVALID) {
+ run_cmd(CMD_EP_XFER_COMPLETED, ep);
+ }
+ break;
+ }
+
+ return USB_STATUS_OK;
+}
+
+void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
+{
+ //TRACE_FUNC_IN_P("buffer %lx, size %lu", (uint32_t) buffer, size);
+
+ int ret;
+ USB_XferCompleteCb_TypeDef cb = ep_state[EP0IN].intern_cb;
+
+ EFM_ASSERT((buffer != NULL) || (size == 0));
+ EFM_ASSERT(size <= MAX_PACKET_SIZE_EP0);
+
+ if (!buffer || size == 0) {
+ // No callback after writing EP0 ZLP
+ cb = NULL;
+ }
+
+ if (buffer && !is_aligned(buffer,4)) {
+ // Copy unaligned data to write-buffer before USBD_Write
+ memcpy(ep_state[EP0IN].data_buf, buffer, size);
+ ret = USBD_Write(0, ep_state[EP0IN].data_buf, size, cb);
+ } else {
+ ret = USBD_Write(0, buffer, size, cb);
+ }
+
+ if (ret != USB_STATUS_OK) {
+ TRACE("FAILED - ret %d", ret);
+ }
+}
+
+void USBHAL::EP0stall(void)
+{
+ TRACE_FUNC_IN;
+ USBD_StallEp0();
+}
+
+static EP_STATUS internEndpointRead(uint8_t ep, uint32_t maxSize)
+{
+ //TRACE_FUNC_IN_P("endpoint 0x%x, size %ld, cb %d", (unsigned)ep, maxSize, useCallback);
+
+ if (ep >= NUMBER_OF_ENDPOINTS) {
+ EFM_ASSERT(false);
+ return EP_INVALID;
+ }
+
+ ep_state[ep].status = READ_PENDING;
+
+ int ret = USBD_Read(USB_EP_TO_ADDR(ep), ep_state[ep].data_buf, maxSize,
+ ep_state[ep].intern_cb);
+
+ if (ret == USB_STATUS_OK) {
+ return EP_PENDING;
+ } else {
+ TRACE("FAILED - ret %d", ret);
+
+ if (ret == USB_STATUS_EP_STALLED) {
+ return EP_STALLED;
+ } else {
+ return EP_INVALID;
+ }
+ }
+}
+
+EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
+{
+ return internEndpointRead(endpoint, maximumSize);
+}
+
+EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead)
+{
+ TRACE_FUNC_IN;
+
+ if (endpoint >= NUMBER_OF_ENDPOINTS) {
+ EFM_ASSERT(false);
+ return EP_INVALID;
+ }
+
+ EFM_ASSERT(data);
+ EFM_ASSERT(bytesRead);
+ if (!data || !bytesRead) {
+ return EP_INVALID;
+ }
+
+ switch (ep_state[endpoint].status) {
+ case READ_PENDING:
+ return EP_PENDING;
+
+ case READ_COMPLETE:
+ memcpy(data, ep_state[endpoint].data_buf, ep_state[endpoint].byte_count);
+ *bytesRead = ep_state[endpoint].byte_count;
+ ep_state[endpoint].status = IDLE;
+ return EP_COMPLETED;
+
+ case FAILED_STALLED:
+ ep_state[endpoint].status = IDLE;
+ return EP_STALLED;
+
+ default:
+ ep_state[endpoint].status = IDLE;
+ return EP_INVALID;
+ }
+}
+
+EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
+{
+ TRACE_FUNC_IN_P("endpoint 0x%x, data 0x%lx, size %lu", (unsigned )endpoint, (uint32_t)data, size);
+
+ EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
+ EFM_ASSERT(endpoint > EP0IN);
+ EFM_ASSERT(size <= ep_state[endpoint].max_packet);
+ EFM_ASSERT(data);
+
+ uint8_t ep = USB_EP_TO_INDEX(endpoint);
+
+ if (endpoint >= NUMBER_OF_ENDPOINTS || endpoint <= EP0IN) {
+ return EP_INVALID;
+ }
+
+ if (size > ep_state[endpoint].max_packet) {
+ return EP_INVALID;
+ }
+
+ if (!data) {
+ return EP_INVALID;
+ }
+
+ memcpy(ep_state[ep].data_buf, data, size);
+
+ ep_state[ep].status = WRITE_PENDING;
+ int ret = USBD_Write(USB_EP_TO_ADDR(endpoint), ep_state[ep].data_buf, size, ep_state[ep].intern_cb);
+
+ if (ret == USB_STATUS_EP_STALLED) {
+ ep_state[ep].status = IDLE;
+ return EP_STALLED;
+ } else if (ret != USB_STATUS_OK) {
+ ep_state[ep].status = IDLE;
+ return EP_INVALID;
+ }
+
+ return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
+{
+ if (endpoint >= NUMBER_OF_ENDPOINTS) {
+ EFM_ASSERT(false);
+ return EP_INVALID;
+ }
+
+ switch (ep_state[endpoint].status) {
+ case WRITE_PENDING:
+ return EP_PENDING;
+
+ case WRITE_COMPLETE:
+ ep_state[endpoint].status = IDLE;
+ return EP_COMPLETED;
+
+ case FAILED_STALLED:
+ ep_state[endpoint].status = IDLE;
+ return EP_STALLED;
+
+ default:
+ ep_state[endpoint].status = IDLE;
+ return EP_INVALID;
+ }
+}
+
+void USBHAL::stallEndpoint(uint8_t endpoint)
+{
+ TRACE_FUNC_IN;
+
+ EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
+ EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN));
+
+ USBD_StallEp(USB_EP_TO_ADDR(endpoint));
+}
+
+void USBHAL::unstallEndpoint(uint8_t endpoint)
+{
+ TRACE_FUNC_IN;
+
+ EFM_ASSERT(endpoint < NUMBER_OF_ENDPOINTS);
+ EFM_ASSERT((endpoint != EP0OUT) && (endpoint != EP0IN));
+
+ USBD_UnStallEp(USB_EP_TO_ADDR(endpoint));
+}
+
+bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options)
+{
+ TRACE_FUNC_IN_P("endpoint %d, packetsize %ld, options 0x%lx", endpoint,
+ maxPacket, options);
+
+ int mult = 1; // RX/TX buffer size multiplier
+ int type = USB_EPTYPE_INTR;
+
+ if (endpoint >= NUMBER_OF_ENDPOINTS) {
+ EFM_ASSERT(false);
+ return false;
+ }
+
+ if (endpoint == EP0IN || endpoint == EP0OUT) {
+ EFM_ASSERT(false);
+ return false;
+ }
+
+ ep_state[endpoint].max_packet = 0;
+
+ if (endpoint == EPISO_OUT || endpoint == EPISO_IN) {
+ if (maxPacket > MAX_PACKET_SIZE_EPISO) {
+ EFM_ASSERT(false);
+ return false;
+ }
+ } else if ((maxPacket > MAX_PACKET_SIZE_EPBULK) || (maxPacket > MAX_PACKET_SIZE_EPINT)) {
+ EFM_ASSERT(false);
+ return false;
+ }
+
+ // USBDevice performs a read right after creating the endpoints,
+ // before calling configureDevice. The read will fail since
+ // at that point the device state is still ADDRESSED. Workaround
+ // is to force configured state here.
+ //
+ // This relies on USBDevice to not call realiseEndpoint unless
+ // it is transitioning to the CONFIGURED state.
+ USBD_SetUsbState(USBD_STATE_CONFIGURED);
+
+ // Why doesn't this function have a type param? This is silly...
+ switch (endpoint) {
+ case EPBULK_OUT:
+ case EPBULK_IN:
+ type = USB_EPTYPE_BULK;
+ mult = 2;
+ break;
+ case EPINT_OUT:
+ case EPINT_IN:
+ type = USB_EPTYPE_INTR;
+ mult = 1;
+ break;
+ case EPISO_OUT:
+ case EPISO_IN:
+ type = USB_EPTYPE_ISOC;
+ mult = 2; // ?
+ break;
+ }
+
+ // Some options force the endpoint to a specific type
+ if( options & ISOCHRONOUS ) {
+ type = USB_EPTYPE_ISOC;
+ mult = 2; // ?
+ } else if ( options & RATE_FEEDBACK_MODE ) {
+ // No support for whatever rate feedback is, but for interrupt only
+ type = USB_EPTYPE_INTR;
+ mult = 1;
+ }
+
+#ifdef USB_USE_DYNAMIC_MEMORY
+ if (ep_state[endpoint].data_buf) {
+ free(ep_state[endpoint].data_buf);
+ }
+
+ ep_state[endpoint].data_buf = (uint8_t *)malloc(maxPacket);
+
+ if (!ep_state[endpoint].data_buf) {
+ EFM_ASSERT(false);
+ return false;
+ }
+#endif
+
+ int ret = USBD_AddEndpoint(USB_EP_TO_ADDR(endpoint), type, maxPacket, mult);
+
+ if (ret == USB_STATUS_OK) {
+ ep_state[endpoint].status = IDLE;
+ ep_state[endpoint].max_packet = maxPacket;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool USBHAL::getEndpointStallState(unsigned char endpoint)
+{
+ TRACE_FUNC_IN;
+ if (endpoint >= NUMBER_OF_ENDPOINTS) {
+ EFM_ASSERT(false);
+ return false;
+ }
+ return USBD_EpIsStalled(USB_EP_TO_ADDR(endpoint));
+}
+
+static void run_cmd(USBISRCommand cmd, uint32_t param)
+{
+ if (usb_isrcmd != CMD_HANDLED || cmd >= CMD_ENUM_END_MARKER) {
+ EFM_ASSERT(false);
+ abort();
+ }
+
+ usb_isrcmd = cmd;
+ usb_isrcmd_param = param;
+ isrptr();
+}
+
+void USBHAL::_usbisr(void)
+{
+ EFM_ASSERT(instance);
+ instance->usbisr();
+}
+
+void USBHAL::usbisr(void)
+{
+ //TRACE_FUNC_IN;
+
+ // This "ISR" is used just to route callbacks from SiL USB driver
+ // callback context (which can not call protected/private USBHAL
+ // methods), to the actual USBHAL.
+
+ EFM_ASSERT(usb_isrcmd != CMD_HANDLED);
+ switch (usb_isrcmd) {
+ case CMD_EP0SETUP:
+ this->EP0setupCallback();
+ break;
+ case CMD_EP0IN:
+ this->EP0in();
+ break;
+ case CMD_EP0OUT:
+ this->EP0out();
+ break;
+ case CMD_BUSRESET:
+ this->busReset();
+ break;
+ case CMD_EP_XFER_COMPLETED:
+ if (epCallback[usb_isrcmd_param] && instance) {
+ (instance->*(epCallback[usb_isrcmd_param]))();
+ }
+ break;
+ case CMD_SOF:
+ this->SOF(usb_isrcmd_param);
+ break;
+ case CMD_SUSPEND_STATE_CHANGED:
+ this->suspendStateChanged(usb_isrcmd_param);
+ break;
+ default:
+ EFM_ASSERT(false);
+ break;
+ }
+ usb_isrcmd = CMD_HANDLED;
+}
+#endif
+
+// End of file
