efm32: Add usb library. Not linked in yet.
This commit is contained in:
parent
c3d05fc576
commit
181c267825
|
@ -0,0 +1,54 @@
|
|||
================ Revision history ============================================
|
||||
3.20.0:
|
||||
- Documentation changes only.
|
||||
|
||||
3.0.3:
|
||||
- Fixed compile time error when using USB stack energy saving on devices with
|
||||
no endpoints in addition to EP0.
|
||||
- Fixed bug when repeatedly unplugging/replugging a device USB cable and using
|
||||
energy saving modes.
|
||||
|
||||
3.0.2:
|
||||
- Bugfix: USBD_Init() may now be called when USB peripheral is in partial
|
||||
powerdown mode.
|
||||
- New function USBD_EpIsBusy( int epAddr ) added to API.
|
||||
- Changed USBD_AbortTransfer() from USBD_AbortTransfer( uint8_t ) to
|
||||
USBD_AbortTransfer( int ).
|
||||
- Added configuration of which hw TIMER the stack will use.
|
||||
|
||||
3.0.1:
|
||||
- USBD_Stop() now disables all USB related interrupts correctly.
|
||||
- Minor documentation changes.
|
||||
- Added more flexibility for taking advantage of energymodes in USB applications.
|
||||
- Fixed bug in device stack partial powerdown procedure.
|
||||
|
||||
3.0.0:
|
||||
- Updated to CMSIS_V3, "efm32lib" is now called "emlib"
|
||||
- This library has been renamed from "efm32usb" to "usb"
|
||||
- Prefixes changed from efm32_ to em_, to reflect changes in emlib
|
||||
- Updated software license, see top of every file for details
|
||||
|
||||
2.4.1:
|
||||
- Corrected USBC clock enable for header file updates
|
||||
|
||||
2.4.0:
|
||||
- Added raw transfer API in the host USB stack for internal testing purposes.
|
||||
- Added USB energy-saving modes in device protocol stack.
|
||||
|
||||
2.3.2:
|
||||
- 19/12-2011: MSD updates
|
||||
|
||||
2.3.0:
|
||||
- 29/11-2011: Initial version of host stack.
|
||||
- 11/11-2011: Added Doxygen doc for host stack.
|
||||
|
||||
2.2.2:
|
||||
- 18/10-2011: Fixed bug in USBDHAL_AbortEpOut() which in some scenarios would hang.
|
||||
- 18/10-2011: Added function USBD_Stop(), which disables device stack operation.
|
||||
|
||||
2.2.1:
|
||||
- 23/03-2011: Initial version.
|
||||
- 15/04-2011: Added host device stack.
|
||||
- 24/05-2011: First release candidate.
|
||||
- 06/06-2011: Host driver port plug/unplug code improvements.
|
||||
- 18/08-2011: Redesign of device abort transfer function.
|
|
@ -0,0 +1,63 @@
|
|||
================ Energy Micro USB STACK =====================================
|
||||
|
||||
This directory, "usb", contains the Energy Micro USB stack for the EFM32
|
||||
Giant Gecko and Leopard Gecko series of microcontrollers.
|
||||
|
||||
Some design guidelines for this library is:
|
||||
|
||||
* Follow the guidelines established by ARM's and Energy Micro's adaptation
|
||||
of the CMSIS (see below) standard
|
||||
|
||||
* Be usable as a starting point for developing richer, more target specific
|
||||
functionality (i.e. copy and modify further)
|
||||
|
||||
* Ability to be used as a standalone software component, used by other drivers
|
||||
that should cover "the most common cases"
|
||||
|
||||
* Readability of the code and usability preferred before optimization for speed
|
||||
and size or covering a particular "narrow" purpose
|
||||
|
||||
* As little "cross-dependency" between modules as possible, to enable users to
|
||||
pick and choose what they want
|
||||
|
||||
================ About CMSIS ================================================
|
||||
|
||||
The USB APIs are built on top of EFM32 CMSIS headers and em_lib API'S, which
|
||||
again are based on the Cortex Microcontroller Software Interface Standard.
|
||||
These files are supplied together with this archive in separate folders.
|
||||
|
||||
The library requires basic C99-support. You might have to enable C99 support
|
||||
in your compiler. Comments are in doxygen compatible format, and can be viewed
|
||||
online from Energy Micro's web site.
|
||||
|
||||
To download updates of this EFM32 CMSIS release, go to
|
||||
http://www.energymicro.com/downloads
|
||||
|
||||
For more information about CMSIS see
|
||||
http://www.onarm.com
|
||||
|
||||
================ File structure ==============================================
|
||||
|
||||
inc/ - header files
|
||||
src/ - source files
|
||||
|
||||
================ License =====================================================
|
||||
|
||||
See the top of each file for SW license. Basically you are free to use the
|
||||
Energy Micro code for any project using Energy Micro devices. Parts of the
|
||||
CMSIS library is copyrighted by ARM Inc. See "License.doc" for ARM's CMSIS
|
||||
license.
|
||||
|
||||
================ Software updates ============================================
|
||||
|
||||
Energy Micro continually works to provide updated and improved emlib, usb
|
||||
stack, example code and other software of use for Energy Micro customers.
|
||||
Please check the download section of Energy Micro's web site at
|
||||
|
||||
http://www.energymicro.com/downloads
|
||||
|
||||
for the latest releases, news and updates. If you download and install the
|
||||
Simplicity Studio application, you will be notified about updates when
|
||||
available.
|
||||
|
||||
(C) Copyright Energy Micro AS, 2012
|
|
@ -0,0 +1,932 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library API for EFM32.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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>
|
||||
#include <stdlib.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.
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/* 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. */
|
||||
|
||||
/* 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_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_HUB_DESCRIPTOR 0x29 /**< HUB descriptor value. */
|
||||
#define USB_HID_DESCRIPTOR 0x21 /**< HID descriptor value. */
|
||||
#define USB_HID_REPORT_DESCRIPTOR 0x22 /**< HID REPORT descriptor value. */
|
||||
#define USB_CS_INTERFACE_DESCRIPTOR 0x24 /**< Audio Class-specific Descriptor Type. */
|
||||
|
||||
#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_HID_DESCSIZE 9 /**< HID 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.*/
|
||||
|
||||
/* Misc. USB definitions */
|
||||
#define USB_EP0_SIZE 64 /**< The size of endpoint 0. */
|
||||
#define USB_MAX_EP_SIZE 64 /**< The max size of any full speed endpoint. */
|
||||
#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_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 PORT_FULL_SPEED 1 /**< Full speed return value for USBH_GetPortSpeed(). */
|
||||
#define PORT_LOW_SPEED 2 /**< Low speed return value for USBH_GetPortSpeed(). */
|
||||
|
||||
/** Macro for creating USB compliant UTF-16LE UNICODE string descriptors.
|
||||
* @n Example: STATIC_CONST_STRING_DESC( iManufacturer, L"Energy Micro AS" );
|
||||
*/
|
||||
|
||||
#define STATIC_CONST_STRING_DESC( name, value ) \
|
||||
typedef struct \
|
||||
{ \
|
||||
uint8_t len; \
|
||||
uint8_t type; \
|
||||
wchar_t name[sizeof( value )/2]; \
|
||||
} __attribute__ ((packed)) _##name; \
|
||||
EFM32_ALIGN( 4 ) \
|
||||
EFM32_PACK_START( 1 ) \
|
||||
static const _##name name __attribute__ ((aligned(4)))= \
|
||||
{ \
|
||||
.len = sizeof(value), \
|
||||
.type = USB_STRING_DESCRIPTOR, \
|
||||
.name = value \
|
||||
} \
|
||||
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 )\
|
||||
typedef struct \
|
||||
{ \
|
||||
uint8_t len; \
|
||||
uint8_t type; \
|
||||
uint8_t name[ 2 ]; \
|
||||
} __attribute__ ((packed)) _##name; \
|
||||
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. */
|
||||
wchar_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
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
/* In DMA mode the DMA engine use one FIFO ram word for each host channel. */
|
||||
#define MAX_FIFO_SIZE_INWORDS (512-MAX_NUM_HOSTCHANNELS) /* Unit is 4 bytes */
|
||||
#else
|
||||
#define MAX_FIFO_SIZE_INWORDS 512 /* Unit is 4 bytes */
|
||||
#endif
|
||||
|
||||
#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 );
|
||||
|
||||
/** @} (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_FIFO_SIZE_INWORDS * 2,/* 1024 bytes Rx FIFO size. */ \
|
||||
MAX_FIFO_SIZE_INWORDS, /* 512 bytes non-periodic Tx FIFO size. */ \
|
||||
MAX_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 */
|
|
@ -0,0 +1,222 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library API for EFM32.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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;
|
||||
}
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USBDHAL_SetEp0InDmaPtr( ep->buf );
|
||||
#endif
|
||||
|
||||
USBDHAL_StartEp0In( EFM32_MIN( ep->remaining, ep->packetSize ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USBDHAL_SetEp0OutDmaPtr( ep->buf );
|
||||
#endif
|
||||
|
||||
USBDHAL_StartEp0Out( ep->packetSize );
|
||||
}
|
||||
}
|
||||
|
||||
__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 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
USBDHAL_StartEp0Out( ep->packetSize );
|
||||
}
|
||||
}
|
||||
|
||||
__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 */
|
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library API for EFM32.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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 */
|
|
@ -0,0 +1,965 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, low level USB peripheral access.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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 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, uint32_t eptype );
|
||||
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_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 void USBHAL_ReadFifo( uint8_t *dest, uint16_t byteCount )
|
||||
{
|
||||
#if 0
|
||||
int words, i;
|
||||
#else
|
||||
int words, loops;
|
||||
#endif
|
||||
|
||||
uint32_t *data;
|
||||
__IO uint32_t *fifo;
|
||||
|
||||
words = (byteCount + 3) / 4;
|
||||
data = (uint32_t*)dest;
|
||||
fifo = USB->FIFO0D;
|
||||
|
||||
#if 0
|
||||
for ( i=0; i<words; i++ )
|
||||
{
|
||||
*data++ = *fifo;
|
||||
}
|
||||
#else
|
||||
/* Duff's Device ! */
|
||||
loops = ( words + 7 ) / 8;
|
||||
switch( words % 8)
|
||||
{
|
||||
case 0: do
|
||||
{
|
||||
*data++ = *fifo;
|
||||
case 7: *data++ = *fifo;
|
||||
case 6: *data++ = *fifo;
|
||||
case 5: *data++ = *fifo;
|
||||
case 4: *data++ = *fifo;
|
||||
case 3: *data++ = *fifo;
|
||||
case 2: *data++ = *fifo;
|
||||
case 1: *data++ = *fifo;
|
||||
} while ( --loops );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void USBHAL_FlushFifo( uint16_t byteCount )
|
||||
{
|
||||
int words, loops;
|
||||
__IO uint32_t *fifo;
|
||||
|
||||
words = (byteCount + 3) / 4;
|
||||
fifo = USB->FIFO0D;
|
||||
|
||||
/* Duff's Device ! */
|
||||
loops = ( words + 7 ) / 8;
|
||||
switch( words % 8)
|
||||
{
|
||||
case 0: do
|
||||
{
|
||||
*fifo;
|
||||
case 7: *fifo;
|
||||
case 6: *fifo;
|
||||
case 5: *fifo;
|
||||
case 4: *fifo;
|
||||
case 3: *fifo;
|
||||
case 2: *fifo;
|
||||
case 1: *fifo;
|
||||
} while ( --loops );
|
||||
}
|
||||
}
|
||||
|
||||
__STATIC_INLINE bool USBHAL_VbusIsOn( void )
|
||||
{
|
||||
return ( USB->STATUS & USB_STATUS_VREGOS ) != 0;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void USBHAL_WriteFifo( int epnum, uint8_t *src,
|
||||
uint16_t byteCount )
|
||||
{
|
||||
#if 0
|
||||
int words, i;
|
||||
#else
|
||||
int words, loops;
|
||||
#endif
|
||||
|
||||
uint32_t *data;
|
||||
__IO uint32_t *fifo;
|
||||
|
||||
words = (byteCount + 3) / 4;
|
||||
data = (uint32_t*)src;
|
||||
fifo = USB_FIFOS[ epnum ];
|
||||
|
||||
#if 0
|
||||
for ( i=0; i<words; i++ )
|
||||
{
|
||||
*fifo = *data++;
|
||||
}
|
||||
#else
|
||||
/* Duff's Device ! */
|
||||
loops = ( words + 7 ) / 8;
|
||||
switch( words % 8)
|
||||
{
|
||||
case 0: do
|
||||
{
|
||||
*fifo = *data++;
|
||||
case 7: *fifo = *data++;
|
||||
case 6: *fifo = *data++;
|
||||
case 5: *fifo = *data++;
|
||||
case 4: *fifo = *data++;
|
||||
case 3: *fifo = *data++;
|
||||
case 2: *fifo = *data++;
|
||||
case 1: *fifo = *data++;
|
||||
} while ( --loops );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#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 |
|
||||
#if defined( USB_SLAVEMODE )
|
||||
USB_GINTMSK_RXFLVLMSK |
|
||||
#endif
|
||||
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_EnableUsbResetInt( void )
|
||||
{
|
||||
/* Disable all interrupts. */
|
||||
USB->GINTMSK = 0;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
USB->GINTSTS = 0xFFFFFFFF;
|
||||
|
||||
USB->GINTMSK = USB_GINTMSK_USBRSTMSK;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void USBDHAL_Ep0Activate( void )
|
||||
{
|
||||
USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGNPINNAK;
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK ) |
|
||||
USB_DOEP_CTL_CNAK | USB_DOEP_CTL_EPENA;
|
||||
#endif
|
||||
}
|
||||
|
||||
__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;
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
__STATIC_INLINE void USBDHAL_FillFifo( USBD_Ep_TypeDef *ep )
|
||||
{
|
||||
uint32_t len, words, fifoSpace;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
len = EFM32_MIN( ep->remaining, ep->packetSize );
|
||||
words = (len + 3) / 4;
|
||||
fifoSpace = USB_DINEPS[ ep->num ].TXFSTS & _USB_DIEP_TXFSTS_SPCAVAIL_MASK;
|
||||
|
||||
if ( ( fifoSpace >= words ) && len )
|
||||
{
|
||||
USBHAL_WriteFifo( ep->num, ep->buf, len );
|
||||
ep->xferred += len;
|
||||
ep->remaining -= len;
|
||||
ep->buf += len;
|
||||
if ( ep->num == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( len == 0 )
|
||||
{
|
||||
/* Disable Tx FIFO empty interrupt */
|
||||
USB->DIEPEMPMSK &= ~ep->mask;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__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;
|
||||
#if defined( USB_SLAVEMODE )
|
||||
uint32_t emp;
|
||||
#endif
|
||||
|
||||
msk = USB->DIEPMSK;
|
||||
#if defined( USB_SLAVEMODE )
|
||||
emp = USB->DIEPEMPMSK;
|
||||
msk |= ((emp >> ep->num) & 0x1) << 7;
|
||||
#endif
|
||||
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;
|
||||
retVal &= USB->DOEPMSK;
|
||||
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 == DIEPCTL_EPTYPE_INTR ) || ( eptype == DIEPCTL_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 )
|
||||
|
||||
{
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
|
||||
#else
|
||||
(void)dev;
|
||||
#endif
|
||||
|
||||
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK ) | USB_DOEP_CTL_EPENA;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void USBDHAL_SetAddr( uint8_t addr )
|
||||
{
|
||||
USB->DCFG = ( USB->DCFG &
|
||||
~_USB_DCFG_DEVADDR_MASK ) |
|
||||
(addr << _USB_DCFG_DEVADDR_SHIFT );
|
||||
}
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
__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;
|
||||
}
|
||||
#endif
|
||||
|
||||
__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 )
|
||||
{
|
||||
USB->DIEP0TSIZ = ( len << _USB_DIEP0TSIZ_XFERSIZE_SHIFT ) |
|
||||
( 1 << _USB_DIEP0TSIZ_PKTCNT_SHIFT );
|
||||
|
||||
USB->DIEP0CTL = ( USB->DIEP0CTL & ~DEPCTL_WO_BITMASK ) |
|
||||
USB_DIEP_CTL_CNAK | USB_DIEP_CTL_EPENA;
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
if ( len ) /* Enable Tx FIFO Empty Interrupt */
|
||||
{
|
||||
USB->DIEPEMPMSK |= 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void USBDHAL_StartEp0Out( uint32_t len )
|
||||
{
|
||||
USB->DOEP0TSIZ = ( len << _USB_DOEP0TSIZ_XFERSIZE_SHIFT ) |
|
||||
( 1 << _USB_DOEP0TSIZ_PKTCNT_SHIFT );
|
||||
|
||||
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK ) |
|
||||
USB_DOEP_CTL_CNAK | USB_DOEP_CTL_EPENA;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void USBDHAL_StartEp0Setup( USBD_Device_TypeDef *dev )
|
||||
{
|
||||
dev->ep[ 0 ].in = false;
|
||||
|
||||
USB->DOEP0TSIZ = 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
dev->setup = dev->setupPkt;
|
||||
USB->DOEP0DMAADDR = (uint32_t)dev->setup;
|
||||
|
||||
USB->DOEP0CTL = ( USB->DOEP0CTL & ~DEPCTL_WO_BITMASK ) |
|
||||
USB_DOEP_CTL_CNAK | USB_DOEP_CTL_EPENA;
|
||||
#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 );
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
if ( ep->remaining ) /* Enable Tx FIFO Empty Interrupt */
|
||||
{
|
||||
USB->DIEPEMPMSK |= ep->mask;
|
||||
}
|
||||
#else
|
||||
USB_DINEPS[ ep->num ].DMAADDR = (uint32_t)ep->buf;
|
||||
#endif
|
||||
|
||||
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 );
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
ep->hwXferSize = xfersize;
|
||||
USB_DOUTEPS[ ep->num ].DMAADDR = (uint32_t)ep->buf;
|
||||
#endif
|
||||
|
||||
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 |
|
||||
#if defined( USB_SLAVEMODE )
|
||||
USB_GINTMSK_RXFLVLMSK |
|
||||
#endif
|
||||
USB_GINTMSK_HCHINTMSK |
|
||||
USB_GINTMSK_DISCONNINTMSK;
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
__STATIC_INLINE void USBHHAL_FillFifo( uint8_t hcnum,
|
||||
uint32_t fifoStatus,
|
||||
USBH_Hc_TypeDef *hc )
|
||||
{
|
||||
uint16_t words, len;
|
||||
|
||||
if ( hc->remaining > 0 )
|
||||
{
|
||||
len = EFM32_MIN( hc->remaining, hc->ep->packetSize );
|
||||
words = ( len + 3 ) / 4;
|
||||
|
||||
if ( ( fifoStatus & _USB_GNPTXSTS_NPTXQSPCAVAIL_MASK ) &&
|
||||
( ( fifoStatus & _USB_GNPTXSTS_NPTXFSPCAVAIL_MASK ) >= words ) )
|
||||
{
|
||||
hc->pending = len;
|
||||
USBHAL_WriteFifo( hcnum, hc->buf, len );
|
||||
if ( hc->ep->type == USB_EPTYPE_INTR )
|
||||
{
|
||||
hc->txPFempIntOn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
hc->txNpFempIntOn = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write to FIFO on "empty" int. */
|
||||
if ( hc->ep->type == USB_EPTYPE_INTR )
|
||||
{
|
||||
USB->GINTMSK |= USB_GINTSTS_PTXFEMP;
|
||||
hc->txPFempIntOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
USB->GINTMSK |= USB_GINTSTS_NPTXFEMP; /* Write FIFO on "empty" int. */
|
||||
hc->txNpFempIntOn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__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;
|
||||
#if defined( USB_SLAVEMODE )
|
||||
retVal &= USB->HC[ hcnum ].INTMSK;
|
||||
#endif
|
||||
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 */
|
|
@ -0,0 +1,237 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, internal type definitions.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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 */
|
||||
#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 */
|
||||
|
||||
/* 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_EP_STATUS = 3
|
||||
} 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;
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
uint32_t hwXferSize;
|
||||
#endif
|
||||
uint32_t fifoSize;
|
||||
USBD_EpState_TypeDef state;
|
||||
USB_XferCompleteCb_TypeDef xferCompleteCb;
|
||||
} USBD_Ep_TypeDef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USB_Setup_TypeDef *setup;
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB_Setup_TypeDef setupPkt[3];
|
||||
#else
|
||||
USB_Setup_TypeDef setupPkt[1];
|
||||
#endif
|
||||
uint8_t configurationValue; /* Must be DWORD aligned */
|
||||
bool remoteWakeupEnabled;
|
||||
uint8_t numberOfStrings;
|
||||
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 ];
|
||||
} 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;
|
||||
#if defined( USB_SLAVEMODE )
|
||||
uint32_t pending;
|
||||
#else
|
||||
uint32_t hwXferSize;
|
||||
#endif
|
||||
uint8_t status;
|
||||
bool idle;
|
||||
#if defined( USB_SLAVEMODE )
|
||||
bool txNpFempIntOn;
|
||||
bool txPFempIntOn;
|
||||
#endif
|
||||
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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,532 @@
|
|||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, USB chapter 9 command handler.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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"
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
static USB_Status_TypeDef ClearFeature ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef GetConfiguration ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef GetDescriptor ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef GetInterface ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef GetStatus ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef SetAddress ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef SetConfiguration ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef SetFeature ( USBD_Device_TypeDef *pDev );
|
||||
static USB_Status_TypeDef SetInterface ( USBD_Device_TypeDef *pDev );
|
||||
|
||||
static uint32_t txBuf;
|
||||
|
||||
int USBDCH9_SetupCmd( USBD_Device_TypeDef *device )
|
||||
{
|
||||
int status;
|
||||
USB_Setup_TypeDef *p = device->setup;
|
||||
|
||||
/* Vendor unique, Class or Standard setup commands override ? */
|
||||
if ( device->callbacks->setupCmd )
|
||||
{
|
||||
status = device->callbacks->setupCmd( p );
|
||||
|
||||
if ( status != USB_STATUS_REQ_UNHANDLED )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( p->Type == USB_SETUP_TYPE_STANDARD )
|
||||
{
|
||||
switch ( p->bRequest )
|
||||
{
|
||||
case GET_STATUS:
|
||||
status = GetStatus( device );
|
||||
break;
|
||||
|
||||
case CLEAR_FEATURE:
|
||||
status = ClearFeature( device );
|
||||
break;
|
||||
|
||||
case SET_FEATURE:
|
||||
status = SetFeature( device );
|
||||
break;
|
||||
|
||||
case SET_ADDRESS:
|
||||
status = SetAddress( device );
|
||||
break;
|
||||
|
||||
case GET_DESCRIPTOR:
|
||||
status = GetDescriptor( device );
|
||||
break;
|
||||
|
||||
case GET_CONFIGURATION:
|
||||
status = GetConfiguration( device );
|
||||
break;
|
||||
|
||||
case SET_CONFIGURATION:
|
||||
status = SetConfiguration( device );
|
||||
break;
|
||||
|
||||
case GET_INTERFACE:
|
||||
status = GetInterface( device );
|
||||
break;
|
||||
|
||||
case SET_INTERFACE:
|
||||
status = SetInterface( device );
|
||||
break;
|
||||
|
||||
case SYNCH_FRAME: /* Synch frame is for isochronous endpoints */
|
||||
case SET_DESCRIPTOR: /* Set descriptor is optional */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef ClearFeature( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USBD_Ep_TypeDef *ep;
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( p->wLength != 0 )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
switch ( p->Recipient )
|
||||
{
|
||||
case USB_SETUP_RECIPIENT_DEVICE:
|
||||
if ( ( p->wIndex == 0 ) && /* ITF no. 0 */
|
||||
( p->wValue == USB_FEATURE_DEVICE_REMOTE_WAKEUP ) &&
|
||||
( ( pDev->state == USBD_STATE_ADDRESSED ) ||
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) ) )
|
||||
{
|
||||
/* Remote wakeup feature clear */
|
||||
if ( pDev->configDescriptor->bmAttributes & CONFIG_DESC_BM_REMOTEWAKEUP )
|
||||
{
|
||||
/* The device is capable of signalling remote wakeup */
|
||||
pDev->remoteWakeupEnabled = false;
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_SETUP_RECIPIENT_ENDPOINT:
|
||||
ep = USBD_GetEpFromAddr( p->wIndex & 0xFF );
|
||||
if ( ep )
|
||||
{
|
||||
if ( ( ep->num > 0 ) &&
|
||||
( p->wValue == USB_FEATURE_ENDPOINT_HALT ) &&
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) )
|
||||
{
|
||||
retVal = USBDHAL_UnStallEp( ep );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef GetConfiguration( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
uint8_t *pConfigValue = (uint8_t*)&txBuf;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( ( p->wIndex != 0 ) ||
|
||||
( p->wLength != 1 ) ||
|
||||
( p->wValue != 0 ) ||
|
||||
( p->Direction != USB_SETUP_DIR_IN ) ||
|
||||
( p->Recipient != USB_SETUP_RECIPIENT_DEVICE ) )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
if ( pDev->state == USBD_STATE_ADDRESSED )
|
||||
{
|
||||
*pConfigValue = 0;
|
||||
USBD_Write( 0, pConfigValue, 1, NULL );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
else if ( pDev->state == USBD_STATE_CONFIGURED )
|
||||
{
|
||||
USBD_Write( 0, &pDev->configurationValue, 1, NULL );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef GetDescriptor( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
int index;
|
||||
uint16_t length = 0;
|
||||
const void *data = NULL;
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( ( p->Recipient != USB_SETUP_RECIPIENT_DEVICE ) ||
|
||||
( p->Direction != USB_SETUP_DIR_IN ) )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
index = p->wValue & 0xFF;
|
||||
switch ( p->wValue >> 8 )
|
||||
{
|
||||
case USB_DEVICE_DESCRIPTOR :
|
||||
if ( index != 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
data = pDev->deviceDescriptor;
|
||||
length = pDev->deviceDescriptor->bLength;
|
||||
break;
|
||||
|
||||
case USB_CONFIG_DESCRIPTOR :
|
||||
if ( index != 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
data = pDev->configDescriptor;
|
||||
length = pDev->configDescriptor->wTotalLength;
|
||||
break;
|
||||
|
||||
case USB_STRING_DESCRIPTOR :
|
||||
if ( index < pDev->numberOfStrings )
|
||||
{
|
||||
USB_StringDescriptor_TypeDef *s;
|
||||
s = ((USB_StringDescriptor_TypeDef**)pDev->stringDescriptors)[index];
|
||||
|
||||
data = s;
|
||||
length = s->len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( length )
|
||||
{
|
||||
USBD_Write( 0, (void*)data, EFM32_MIN( length, p->wLength ), NULL );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef GetInterface( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
uint8_t *pAlternateSetting = (uint8_t*)&txBuf;
|
||||
|
||||
/* There is currently support for one interface and no alternate settings */
|
||||
|
||||
if ( ( p->wIndex != 0 ) ||
|
||||
( p->wLength != 1 ) ||
|
||||
( p->wValue != 0 ) ||
|
||||
( p->Direction != USB_SETUP_DIR_IN ) ||
|
||||
( p->Recipient != USB_SETUP_RECIPIENT_INTERFACE ) )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
if ( pDev->state == USBD_STATE_CONFIGURED )
|
||||
{
|
||||
*pAlternateSetting = 0;
|
||||
USBD_Write( 0, pAlternateSetting, 1, NULL );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef GetStatus( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USBD_Ep_TypeDef *ep;
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
uint16_t *pStatus = (uint16_t*)&txBuf;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( ( p->wValue != 0 ) ||
|
||||
( p->wLength != 2 ) ||
|
||||
( p->Direction != USB_SETUP_DIR_IN ) )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
switch ( p->Recipient )
|
||||
{
|
||||
case USB_SETUP_RECIPIENT_DEVICE:
|
||||
if ( ( p->wIndex == 0 ) &&
|
||||
( ( pDev->state == USBD_STATE_ADDRESSED ) ||
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) ) )
|
||||
{
|
||||
*pStatus = 0;
|
||||
|
||||
/* Remote wakeup feature status */
|
||||
if ( pDev->remoteWakeupEnabled )
|
||||
*pStatus |= REMOTE_WAKEUP_ENABLED;
|
||||
|
||||
/* Current self/bus power status */
|
||||
if ( pDev->callbacks->isSelfPowered != NULL )
|
||||
{
|
||||
if ( pDev->callbacks->isSelfPowered() )
|
||||
{
|
||||
*pStatus |= DEVICE_IS_SELFPOWERED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pDev->configDescriptor->bmAttributes & CONFIG_DESC_BM_SELFPOWERED )
|
||||
{
|
||||
*pStatus |= DEVICE_IS_SELFPOWERED;
|
||||
}
|
||||
}
|
||||
|
||||
USBD_Write( 0, pStatus, 2, NULL );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_SETUP_RECIPIENT_INTERFACE:
|
||||
if ( ( p->wIndex == 0 ) &&
|
||||
( ( pDev->state == USBD_STATE_ADDRESSED ) ||
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) ) )
|
||||
{
|
||||
*pStatus = 0;
|
||||
USBD_Write( 0, pStatus, 2, NULL );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_SETUP_RECIPIENT_ENDPOINT:
|
||||
ep = USBD_GetEpFromAddr( p->wIndex & 0xFF );
|
||||
if ( ep )
|
||||
{
|
||||
if ( ( ep->num > 0 ) &&
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) )
|
||||
{
|
||||
/* Send 2 bytes w/halt status for endpoint */
|
||||
retVal = USBDHAL_GetStallStatusEp( ep, pStatus );
|
||||
if ( retVal == USB_STATUS_OK )
|
||||
{
|
||||
USBD_Write( 0, pStatus, 2, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef SetAddress( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( ( p->wIndex != 0 ) ||
|
||||
( p->wLength != 0 ) ||
|
||||
( p->wValue > 127 ) ||
|
||||
( p->Recipient != USB_SETUP_RECIPIENT_DEVICE ) )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
if ( pDev->state == USBD_STATE_DEFAULT )
|
||||
{
|
||||
if ( p->wValue != 0 )
|
||||
{
|
||||
USBD_SetUsbState( USBD_STATE_ADDRESSED );
|
||||
}
|
||||
USBDHAL_SetAddr( p->wValue );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
else if ( pDev->state == USBD_STATE_ADDRESSED )
|
||||
{
|
||||
if ( p->wValue == 0 )
|
||||
{
|
||||
USBD_SetUsbState( USBD_STATE_DEFAULT );
|
||||
}
|
||||
USBDHAL_SetAddr( p->wValue );
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef SetConfiguration( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( ( p->wIndex != 0 ) ||
|
||||
( p->wLength != 0 ) ||
|
||||
( (p->wValue>>8) != 0 ) ||
|
||||
( p->Recipient != USB_SETUP_RECIPIENT_DEVICE ) )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
if ( pDev->state == USBD_STATE_ADDRESSED )
|
||||
{
|
||||
if ( ( p->wValue == 0 ) ||
|
||||
( p->wValue == pDev->configDescriptor->bConfigurationValue ) )
|
||||
{
|
||||
pDev->configurationValue = p->wValue;
|
||||
if ( p->wValue == pDev->configDescriptor->bConfigurationValue )
|
||||
{
|
||||
USBD_ActivateAllEps( true );
|
||||
USBD_SetUsbState( USBD_STATE_CONFIGURED );
|
||||
}
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( pDev->state == USBD_STATE_CONFIGURED )
|
||||
{
|
||||
if ( ( p->wValue == 0 ) ||
|
||||
( p->wValue == pDev->configDescriptor->bConfigurationValue ) )
|
||||
{
|
||||
pDev->configurationValue = p->wValue;
|
||||
if ( p->wValue == 0 )
|
||||
{
|
||||
USBD_SetUsbState( USBD_STATE_ADDRESSED );
|
||||
USBD_DeactivateAllEps( USB_STATUS_DEVICE_UNCONFIGURED );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reenable device endpoints, will reset data toggles */
|
||||
USBD_ActivateAllEps( false );
|
||||
}
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef SetFeature( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USBD_Ep_TypeDef *ep;
|
||||
USB_XferCompleteCb_TypeDef callback;
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
if ( p->wLength != 0 )
|
||||
{
|
||||
return USB_STATUS_REQ_ERR;
|
||||
}
|
||||
|
||||
switch ( p->Recipient )
|
||||
{
|
||||
case USB_SETUP_RECIPIENT_DEVICE:
|
||||
if ( ( p->wIndex == 0 ) && /* ITF no. 0 */
|
||||
( p->wValue == USB_FEATURE_DEVICE_REMOTE_WAKEUP ) &&
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) )
|
||||
{
|
||||
/* Remote wakeup feature set */
|
||||
if ( pDev->configDescriptor->bmAttributes & CONFIG_DESC_BM_REMOTEWAKEUP )
|
||||
{
|
||||
/* The device is capable of signalling remote wakeup */
|
||||
pDev->remoteWakeupEnabled = true;
|
||||
retVal = USB_STATUS_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_SETUP_RECIPIENT_ENDPOINT:
|
||||
ep = USBD_GetEpFromAddr( p->wIndex & 0xFF );
|
||||
if ( ep )
|
||||
{
|
||||
if ( ( ep->num > 0 ) &&
|
||||
( p->wValue == USB_FEATURE_ENDPOINT_HALT ) &&
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) )
|
||||
{
|
||||
retVal = USBDHAL_StallEp( ep );
|
||||
|
||||
ep->state = D_EP_IDLE;
|
||||
/* Call end of transfer callback for endpoint */
|
||||
if ( ( retVal == USB_STATUS_OK ) &&
|
||||
( ep->state != D_EP_IDLE ) &&
|
||||
( ep->xferCompleteCb ) )
|
||||
{
|
||||
callback = ep->xferCompleteCb;
|
||||
ep->xferCompleteCb = NULL;
|
||||
DEBUG_USB_API_PUTS( "\nEP cb(), EP stalled" );
|
||||
callback( USB_STATUS_EP_STALLED, ep->xferred, ep->remaining);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static USB_Status_TypeDef SetInterface( USBD_Device_TypeDef *pDev )
|
||||
{
|
||||
USB_Setup_TypeDef *p = pDev->setup;
|
||||
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
|
||||
|
||||
/* There is currently support for one interface and no alternate settings */
|
||||
|
||||
if ( ( p->wIndex == 0 ) &&
|
||||
( p->wLength == 0 ) &&
|
||||
( p->wValue == 0 ) &&
|
||||
( pDev->state == USBD_STATE_CONFIGURED ) &&
|
||||
( p->Recipient == USB_SETUP_RECIPIENT_INTERFACE ) )
|
||||
{
|
||||
/* Reset data toggles on EP's */
|
||||
USBD_ActivateAllEps( false );
|
||||
return USB_STATUS_OK;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif /* defined( USB_DEVICE ) */
|
||||
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
|
|
@ -0,0 +1,237 @@
|
|||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, USB device endpoint handlers.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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"
|
||||
|
||||
/** @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.
|
||||
*/
|
||||
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 ];
|
||||
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_EP_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_EP_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_EP_STATUS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case D_EP_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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ) */
|
|
@ -0,0 +1,752 @@
|
|||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, USB device peripheral interrupt handlers.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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 */
|
||||
|
||||
#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 );
|
||||
#if defined( USB_SLAVEMODE )
|
||||
static void Handle_USB_GINTSTS_RXFLVL ( void );
|
||||
#endif
|
||||
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 ( USB_PWRSAVE_MODE )
|
||||
/* Variables and prototypes for USB powerdown (suspend) functionality. */
|
||||
volatile bool USBD_poweredDown = false;
|
||||
static bool UsbPowerDown( void );
|
||||
static bool UsbPowerUp( void );
|
||||
|
||||
/* Storage for backing up USB core registers. */
|
||||
static uint32_t x_USB_GINTMSK;
|
||||
static uint32_t x_USB_GOTGCTL;
|
||||
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
|
||||
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
/*
|
||||
* USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
|
||||
*/
|
||||
void USB_IRQHandler( void )
|
||||
{
|
||||
uint32_t status;
|
||||
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
|
||||
bool servedVbusInterrupt = false;
|
||||
#endif
|
||||
|
||||
INT_Disable();
|
||||
|
||||
#if ( USB_PWRSAVE_MODE )
|
||||
if ( USBD_poweredDown )
|
||||
{
|
||||
/* Switch USBC clock from 32kHz to HFCLK to be able to read USB */
|
||||
/* peripheral registers. */
|
||||
/* If we woke up from EM2, HFCLK is now HFRCO. */
|
||||
|
||||
CMU_OscillatorEnable( cmuOsc_HFXO, true, false); /* Prepare HFXO. */
|
||||
CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
|
||||
while ( !( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) ){}
|
||||
}
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
|
||||
if ( USB->IF )
|
||||
{
|
||||
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 ( UsbPowerUp() )
|
||||
USBDHAL_EnableUsbResetInt();
|
||||
|
||||
USBD_SetUsbState( USBD_STATE_POWERED );
|
||||
}
|
||||
}
|
||||
|
||||
if ( USB->IF & USB_IF_VREGOSL )
|
||||
{
|
||||
USB->IFC = USB_IFC_VREGOSL;
|
||||
|
||||
if ( !( USB->STATUS & USB_STATUS_VREGOS ) )
|
||||
{
|
||||
servedVbusInterrupt = true;
|
||||
DEBUG_USB_INT_LO_PUTS( "\nVboF" );
|
||||
|
||||
USB->GINTMSK = 0;
|
||||
USB->GINTSTS = 0xFFFFFFFF;
|
||||
|
||||
UsbPowerDown();
|
||||
USBD_SetUsbState( USBD_STATE_NONE );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
status = USBHAL_GetCoreInts();
|
||||
if ( status == 0 )
|
||||
{
|
||||
INT_Enable();
|
||||
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
|
||||
if ( !servedVbusInterrupt )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTS( "\nSinT" );
|
||||
}
|
||||
#else
|
||||
DEBUG_USB_INT_LO_PUTS( "\nSinT" );
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE_INT( USB_GINTSTS_RESETDET )
|
||||
HANDLE_INT( USB_GINTSTS_WKUPINT )
|
||||
HANDLE_INT( USB_GINTSTS_USBSUSP )
|
||||
HANDLE_INT( USB_GINTSTS_SOF )
|
||||
#if defined( USB_SLAVEMODE )
|
||||
HANDLE_INT( USB_GINTSTS_RXFLVL )
|
||||
#endif
|
||||
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 /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
USBDHAL_Ep0Activate();
|
||||
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 )
|
||||
{
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/* Disable Tx FIFO empty interrupt */
|
||||
USB->DIEPEMPMSK &= ~epmask;
|
||||
USB_DINEPS[ epnum ].INT = USB_DIEP_INT_TXFEMP;
|
||||
status &= ~USB_DIEP_INT_TXFEMP;
|
||||
#endif
|
||||
USB_DINEPS[ epnum ].INT = USB_DIEP_INT_XFERCOMPL;
|
||||
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
|
||||
|
||||
if ( epnum == 0 )
|
||||
{
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
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
|
||||
{
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
ep->xferred = ep->remaining -
|
||||
( ( USB_DINEPS[ epnum ].TSIZ &
|
||||
_USB_DIEP_TSIZ_XFERSIZE_MASK ) >>
|
||||
_USB_DIEP_TSIZ_XFERSIZE_SHIFT );
|
||||
ep->remaining -= ep->xferred;
|
||||
#endif
|
||||
USBDEP_EpHandler( ep->addr );
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
if ( status & USB_DIEP_INT_TXFEMP )
|
||||
{
|
||||
USB_DINEPS[ epnum ].INT = USB_DIEP_INT_TXFEMP;
|
||||
|
||||
if ( ep->state != D_EP_IDLE )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'f' );
|
||||
USBDHAL_FillFifo( ep );
|
||||
}
|
||||
}
|
||||
#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 ( status & USB_DOEP_INT_XFERCOMPL )
|
||||
{
|
||||
USB_DOUTEPS[ epnum ].INT = USB_DOEP_INT_XFERCOMPL;
|
||||
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
|
||||
|
||||
if ( epnum == 0 )
|
||||
{
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
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
|
||||
{
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
ep->xferred = ep->hwXferSize -
|
||||
( ( USB_DOUTEPS[ epnum ].TSIZ & _USB_DOEP_TSIZ_XFERSIZE_MASK ) >>
|
||||
_USB_DOEP_TSIZ_XFERSIZE_SHIFT );
|
||||
ep->remaining -= ep->xferred;
|
||||
#endif
|
||||
USBDEP_EpHandler( ep->addr );
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup Phase Done */
|
||||
if ( status & USB_DOEP_INT_SETUP )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTS( "\nSP" );
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
if ( USB->DOEP0INT & USB_DOEP_INT_BACK2BACKSETUP )
|
||||
{ /* Back to back setup packets received */
|
||||
USB->DOEP0INT = USB_DOEP_INT_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 ];
|
||||
}
|
||||
#endif
|
||||
USB->DOEP0TSIZ |= 3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT;
|
||||
USB->DOEP0DMAADDR = (uint32_t)dev->setupPkt;
|
||||
USB->DOEP0INT = USB_DOEP_INT_SETUP;
|
||||
USBDEP_Ep0Handler( dev ); /* Call the SETUP process for the EP0 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle USB reset detectet interrupt in suspend mode.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_RESETDET ( void )
|
||||
{
|
||||
USB->GINTSTS = USB_GINTSTS_RESETDET;
|
||||
|
||||
#if ( USB_PWRSAVE_MODE )
|
||||
UsbPowerUp();
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
USBD_SetUsbState( USBD_STATE_DEFAULT );
|
||||
DEBUG_USB_INT_LO_PUTS( "RsuP\n" );
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/*
|
||||
* Handle receive FIFO full interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_RXFLVL( void )
|
||||
{
|
||||
USBD_Ep_TypeDef *ep;
|
||||
uint32_t status, byteCount, count, residue;
|
||||
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'q' );
|
||||
|
||||
status = USB->GRXSTSP; /* Get status from top of FIFO */
|
||||
|
||||
ep = USBD_GetEpFromAddr( status & _USB_GRXSTSP_CHEPNUM_MASK );
|
||||
|
||||
switch ( status & _USB_GRXSTSP_PKTSTS_MASK )
|
||||
{
|
||||
case GRXSTSP_PKTSTS_DEVICE_DATAOUTRECEIVED:
|
||||
byteCount = (status & _USB_GRXSTSP_BCNT_MASK) >> _USB_GRXSTSP_BCNT_SHIFT;
|
||||
if ( byteCount )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'e' );
|
||||
if ( ep->state != D_EP_IDLE )
|
||||
{
|
||||
/* Check for possible buffer overflow */
|
||||
if ( byteCount > ep->remaining )
|
||||
{
|
||||
residue = byteCount - ep->remaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
residue = 0;
|
||||
}
|
||||
|
||||
count = EFM32_MIN( byteCount, ep->remaining );
|
||||
USBHAL_ReadFifo( ep->buf, count );
|
||||
ep->xferred += count;
|
||||
ep->remaining -= count;
|
||||
ep->buf += count;
|
||||
|
||||
if ( residue )
|
||||
{
|
||||
USBHAL_FlushFifo( residue );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRXSTSP_PKTSTS_DEVICE_SETUPRECEIVED:
|
||||
USBHAL_ReadFifo( (uint8_t*)dev->setup, USB_SETUP_PKT_SIZE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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;
|
||||
USB->DOEPMSK = USB_DOEPMSK_SETUPMSK | USB_DOEPMSK_XFERCOMPLMSK;
|
||||
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" );
|
||||
|
||||
state = USBD_GetUsbState();
|
||||
if ( ( state == USBD_STATE_POWERED ) ||
|
||||
( state == USBD_STATE_DEFAULT ) ||
|
||||
( state == USBD_STATE_ADDRESSED ) ||
|
||||
( state == USBD_STATE_CONFIGURED ) )
|
||||
{
|
||||
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONSUSPEND )
|
||||
UsbPowerDown();
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
USBD_SetUsbState( USBD_STATE_SUSPENDED );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle USB port wakeup interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_WKUPINT( void )
|
||||
{
|
||||
USB->GINTSTS = USB_GINTSTS_WKUPINT;
|
||||
|
||||
#if ( USB_PWRSAVE_MODE )
|
||||
if ( UsbPowerUp() )
|
||||
{
|
||||
USBDHAL_StartEp0Setup( dev );
|
||||
USBDHAL_Ep0Activate();
|
||||
}
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
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;
|
||||
|
||||
/* Backup USB core registers. */
|
||||
x_USB_GINTMSK = USB->GINTMSK;
|
||||
x_USB_GOTGCTL = USB->GOTGCTL;
|
||||
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;
|
||||
|
||||
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
|
||||
/* Enter EM2 on interrupt exit. */
|
||||
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk;
|
||||
#endif
|
||||
|
||||
/* Switch USBC clock to 32 kHz. */
|
||||
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
|
||||
CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;
|
||||
#else
|
||||
CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;
|
||||
#endif
|
||||
while ( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ){}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
#if ( USB_PWRSAVE_MODE )
|
||||
/*
|
||||
* Exit USB core partial powerdown mode, restore essential USB core registers.
|
||||
* Optionally prevent re-entry back to EM2.
|
||||
*/
|
||||
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 ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
|
||||
if ( USBD_poweredDown && ( USB->STATUS & USB_STATUS_VREGOS ) )
|
||||
#else
|
||||
if ( USBD_poweredDown )
|
||||
#endif
|
||||
{
|
||||
USBD_poweredDown = false;
|
||||
|
||||
/* Switch CPU core clock to 48MHz */
|
||||
CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
|
||||
|
||||
/* Switch USBC clock to HFCLK */
|
||||
CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );
|
||||
|
||||
/* Exit partial powerdown mode. */
|
||||
USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK;
|
||||
USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE);
|
||||
|
||||
/* 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;
|
||||
if ( ep->in )
|
||||
{
|
||||
tmp = ( ep->packetSize << _USB_DIEP_CTL_MPS_SHIFT ) |
|
||||
( ep->type << _USB_DIEP_CTL_EPTYPE_SHIFT ) |
|
||||
( ep->txFifoNum << _USB_DIEP_CTL_TXFNUM_SHIFT ) |
|
||||
USB_DIEP_CTL_USBACTEP |
|
||||
USB_DIEP_CTL_SNAK;
|
||||
|
||||
if ( x_USB_EP_CTL[ i ] & USB_DIEP_CTL_DPIDEOF )
|
||||
tmp |= USB_DIEP_CTL_SETD1PIDOF;
|
||||
else
|
||||
tmp |= USB_DIEP_CTL_SETD0PIDEF;
|
||||
|
||||
USB_DINEPS[ epNum ].CTL = tmp;
|
||||
USB_DINEPS[ epNum ].TSIZ = x_USB_EP_TSIZ[ i ];
|
||||
USB_DINEPS[ epNum ].DMAADDR = x_USB_EP_DMAADDR[ i ];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( x_USB_EP_CTL[ i ] & USB_DOEP_CTL_DPIDEOF )
|
||||
USB_DOUTEPS[ epNum ].CTL = x_USB_EP_CTL[ i ] | USB_DOEP_CTL_SETD1PIDOF;
|
||||
else
|
||||
USB_DOUTEPS[ epNum ].CTL = x_USB_EP_CTL[ i ] | USB_DOEP_CTL_SETD0PIDEF;
|
||||
|
||||
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;
|
||||
USB->GOTGCTL = x_USB_GOTGCTL;
|
||||
USB->GINTMSK = x_USB_GINTMSK;
|
||||
|
||||
USB->DCTL |= USB_DCTL_PWRONPRGDONE;
|
||||
|
||||
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ENTEREM2 )
|
||||
/* Do not reenter EM2 on interrupt exit. */
|
||||
SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif /* if ( USB_PWRSAVE_MODE ) */
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif /* defined( USB_DEVICE ) */
|
||||
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,814 @@
|
|||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, low level USB peripheral access.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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 */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Wait for AHB master IDLE state. */
|
||||
while ( !( USB->GRSTCTL & USB_GRSTCTL_AHBIDLE ) ) {}
|
||||
|
||||
/* Core Soft Reset */
|
||||
USB->GRSTCTL |= USB_GRSTCTL_CSFTRST;
|
||||
while ( USB->GRSTCTL & USB_GRSTCTL_CSFTRST ) {}
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
CMU_ClockEnable( cmuClock_GPIO, true );
|
||||
GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */
|
||||
USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Init PHY */
|
||||
|
||||
USBHAL_CoreReset(); /* Reset USB core */
|
||||
|
||||
/* Force Device Mode */
|
||||
USB->GUSBCFG = ( USB->GUSBCFG &
|
||||
~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEHSTMODE ) ) |
|
||||
USB_GUSBCFG_FORCEDEVMODE;
|
||||
|
||||
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;
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) |
|
||||
USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR;
|
||||
#endif
|
||||
|
||||
/* Set Rx FIFO size */
|
||||
USB->GRXFSIZ = ( totalRxFifoSize << _USB_GRXFSIZ_RXFDEP_SHIFT ) &
|
||||
_USB_GRXFSIZ_RXFDEP_MASK;
|
||||
|
||||
start = totalRxFifoSize; /* Set Tx EP0 FIFO size */
|
||||
depth = dev->ep[ 0 ].fifoSize;
|
||||
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 = ep->fifoSize;
|
||||
USB_DIEPTXFS[ ep->txFifoNum - 1 ] =
|
||||
( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) |
|
||||
( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( totalRxFifoSize + totalTxFifoSize > MAX_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_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
|
||||
/* 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;
|
||||
#endif
|
||||
|
||||
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 )
|
||||
{
|
||||
/* 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 */
|
||||
while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) )
|
||||
{
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/* Check if Rx FIFO filled with global OUT NAK status */
|
||||
if ( USB->GINTSTS & USB_GINTSTS_RXFLVL )
|
||||
{
|
||||
USB->GRXSTSP; /* Pop status from top of FIFO */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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 */
|
||||
while ( !( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD ) ) {}
|
||||
|
||||
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;
|
||||
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 */
|
||||
while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) )
|
||||
{
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/* Check if Rx FIFO filled with global OUT NAK status */
|
||||
if ( USB->GINTSTS & USB_GINTSTS_RXFLVL )
|
||||
{
|
||||
USB->GRXSTSP; /* Pop status from top of FIFO */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ( im );
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ( im || om );
|
||||
|
||||
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;
|
||||
|
||||
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; /* Init PHY */
|
||||
|
||||
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 );
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) |
|
||||
USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR;
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
{
|
||||
#if defined( USB_SLAVEMODE )
|
||||
USB->GRXSTSP;
|
||||
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
|
||||
#endif
|
||||
__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, uint32_t eptype )
|
||||
{
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
(void)eptype;
|
||||
|
||||
#else
|
||||
USB->HC[ hcnum ].INTMSK |= USB_HC_INT_CHHLTD;
|
||||
#endif
|
||||
|
||||
hcchar |= USB_HC_CHAR_CHENA | USB_HC_CHAR_CHDIS;
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/* Check for space in the request queue to issue the halt. */
|
||||
if ( eptype == HCCHAR_EPTYPE_CTRL || eptype == HCCHAR_EPTYPE_BULK )
|
||||
{
|
||||
if ( ( USB->GNPTXSTS & _USB_GNPTXSTS_NPTXQSPCAVAIL_MASK ) == 0 )
|
||||
{
|
||||
hcchar &= ~USB_HC_CHAR_CHENA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( USB->HPTXSTS & _USB_HPTXSTS_PTXQSPCAVAIL_MASK ) == 0)
|
||||
{
|
||||
hcchar &= ~USB_HC_CHAR_CHENA;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
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:
|
||||
USB->HC[ hcnum ].INTMSK =
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB_HC_INT_CHHLTD;
|
||||
#else
|
||||
USB_HC_INT_XFERCOMPL |
|
||||
USB_HC_INT_STALL |
|
||||
USB_HC_INT_XACTERR |
|
||||
USB_HC_INT_NAK |
|
||||
( ep->in ? 0 : USB_HC_INT_ACK ) |
|
||||
( ep->in ? USB_HC_INT_DATATGLERR : 0 ) |
|
||||
( ep->in ? USB_HC_INT_BBLERR : 0 );
|
||||
#endif
|
||||
break;
|
||||
|
||||
case USB_EPTYPE_INTR:
|
||||
USB->HC[ hcnum ].INTMSK =
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
USB_HC_INT_CHHLTD;
|
||||
#else
|
||||
USB_HC_INT_XFERCOMPL |
|
||||
USB_HC_INT_STALL |
|
||||
USB_HC_INT_XACTERR |
|
||||
USB_HC_INT_DATATGLERR |
|
||||
USB_HC_INT_NAK |
|
||||
( ep->in ? 0 : USB_HC_INT_ACK ) |
|
||||
USB_HC_INT_FRMOVRUN |
|
||||
( ep->in ? USB_HC_INT_BBLERR : 0 );
|
||||
#endif
|
||||
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 defined( USB_SLAVEMODE )
|
||||
hc->pending = 0;
|
||||
#endif
|
||||
|
||||
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 */
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
hc->hwXferSize = len;
|
||||
#endif
|
||||
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 );
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
if ( !hc->ep->in )
|
||||
{
|
||||
if ( hc->ep->type == USB_EPTYPE_INTR )
|
||||
{
|
||||
USBHHAL_FillFifo( hcnum, USB->HPTXSTS, hc );
|
||||
}
|
||||
else
|
||||
{
|
||||
USBHHAL_FillFifo( hcnum, USB->GNPTXSTS, hc );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif /* defined( USB_HOST ) */
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
|
||||
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
|
|
@ -0,0 +1,212 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, USB host endpoint handlers.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#include "em_device.h"
|
||||
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
|
||||
#include "em_usb.h"
|
||||
#if defined( USB_HOST )
|
||||
|
||||
#include "em_usbtypes.h"
|
||||
#include "em_usbhal.h"
|
||||
#include "em_usbh.h"
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
/*
|
||||
* USBHEP_CtrlEpHandler() is called each time a packet has been transmitted
|
||||
* or recieved on host channels serving a device default endpoint (EP0).
|
||||
* A state machine navigate us through the phases of a control transfer
|
||||
* according to "chapter 9" in the USB spec.
|
||||
*/
|
||||
void USBHEP_CtrlEpHandler( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result )
|
||||
{
|
||||
uint8_t direction;
|
||||
|
||||
switch ( ep->state )
|
||||
{
|
||||
/* ------- Setup stage ------------------------------------------------ */
|
||||
case H_EP_SETUP: /* SETUP packet sent successfully */
|
||||
if ( result == USB_STATUS_OK )
|
||||
{
|
||||
direction = ep->setup.bmRequestType & USB_SETUP_DIR_MASK;
|
||||
|
||||
/* Check if there is a data stage */
|
||||
if ( ep->setup.wLength != 0 )
|
||||
{
|
||||
if ( direction == USB_SETUP_DIR_D2H ) /* Data direction is IN */
|
||||
{
|
||||
USBH_CtlReceiveData( ep, ep->setup.wLength );
|
||||
ep->state = H_EP_DATA_IN;
|
||||
break;
|
||||
}
|
||||
else /* Data direction is OUT */
|
||||
{
|
||||
USBH_CtlSendData( ep, ep->setup.wLength );
|
||||
ep->state = H_EP_DATA_OUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
USBH_CtlReceiveData( ep, 0 ); /* No data stage */
|
||||
ep->state = H_EP_STATUS_IN; /* Get zero length in status packet */
|
||||
break;
|
||||
}
|
||||
|
||||
ep->setupErrCnt++;
|
||||
|
||||
/*
|
||||
* After a halt condition is encountered or an error is detected by the
|
||||
* host, a control endpoint is allowed to recover by accepting the next
|
||||
* SETUP package. If the next Setup package is not accepted, a device
|
||||
* reset will ultimately be needed.
|
||||
*/
|
||||
|
||||
if ( ( ep->setupErrCnt == 1 ) && ( ep->timeout != 0 ) )
|
||||
{
|
||||
USBH_CtlSendSetup( ep ); /* Retry */
|
||||
break;
|
||||
}
|
||||
USBHEP_TransferDone( ep, result );
|
||||
break;
|
||||
|
||||
|
||||
/* ------- Data IN stage ---------------------------------------------- */
|
||||
case H_EP_DATA_IN: /* Data received */
|
||||
if ( result == USB_STATUS_OK )
|
||||
{
|
||||
USBH_CtlSendData( ep, 0 ); /* Send zero length out status packet */
|
||||
ep->state = H_EP_STATUS_OUT;
|
||||
break;
|
||||
}
|
||||
USBHEP_TransferDone( ep, result );
|
||||
break;
|
||||
|
||||
|
||||
/* ------- Data OUT stage --------------------------------------------- */
|
||||
case H_EP_DATA_OUT: /* Data sent */
|
||||
if ( result == USB_STATUS_OK )
|
||||
{
|
||||
USBH_CtlReceiveData( ep, 0 ); /* Get zero length in status packet */
|
||||
ep->state = H_EP_STATUS_IN;
|
||||
break;
|
||||
}
|
||||
USBHEP_TransferDone( ep, result );
|
||||
break;
|
||||
|
||||
|
||||
/* ------- Status IN/OUT stage ---------------------------------------- */
|
||||
case H_EP_STATUS_IN: /* Status packet received */
|
||||
case H_EP_STATUS_OUT : /* Status packet sent */
|
||||
USBHEP_TransferDone( ep, result );
|
||||
break;
|
||||
|
||||
|
||||
case H_EP_IDLE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* USBHEP_EpHandler() is called each time a packet has been transmitted
|
||||
* or recieved on a host channel serving a non-control device endpoint.
|
||||
*/
|
||||
void USBHEP_EpHandler( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result )
|
||||
{
|
||||
switch ( ep->state )
|
||||
{
|
||||
case H_EP_DATA_IN:
|
||||
case H_EP_DATA_OUT:
|
||||
USBHEP_TransferDone( ep, result );
|
||||
break;
|
||||
|
||||
default:
|
||||
case H_EP_IDLE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* USBHEP_TransferDone() is called on transfer completion on all types of
|
||||
* device endpoints.
|
||||
*/
|
||||
void USBHEP_TransferDone( USBH_Ep_TypeDef *ep, USB_Status_TypeDef result )
|
||||
{
|
||||
int hcnum;
|
||||
USB_XferCompleteCb_TypeDef callback;
|
||||
|
||||
ep->xferCompleted = true;
|
||||
ep->xferStatus = result;
|
||||
ep->state = H_EP_IDLE;
|
||||
|
||||
if ( ep->type == USB_EPTYPE_CTRL )
|
||||
{
|
||||
hcnum = ep->setup.Direction == USB_SETUP_DIR_IN ? ep->hcIn : ep->hcOut;
|
||||
|
||||
if ( ep->timeout )
|
||||
USBTIMER_Stop( ep->hcOut + HOSTCH_TIMER_INDEX );
|
||||
|
||||
ep->xferred = hcs[ hcnum ].xferred;
|
||||
ep->remaining = hcs[ hcnum ].remaining;
|
||||
|
||||
hcs[ ep->hcIn ].idle = true;
|
||||
hcs[ ep->hcOut ].idle = true;
|
||||
|
||||
if ( ep->setup.wLength == 0 )
|
||||
{
|
||||
ep->xferred = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hcnum = ep->in ? ep->hcIn : ep->hcOut;
|
||||
|
||||
if ( ep->timeout || ep->type == USB_EPTYPE_INTR )
|
||||
USBTIMER_Stop( hcnum + HOSTCH_TIMER_INDEX );
|
||||
|
||||
hcs[ hcnum ].idle = true;
|
||||
ep->xferred = hcs[ hcnum ].xferred;
|
||||
ep->remaining = hcs[ hcnum ].remaining;
|
||||
}
|
||||
|
||||
if ( ep->xferCompleteCb )
|
||||
{
|
||||
callback = ep->xferCompleteCb;
|
||||
ep->xferCompleteCb = NULL;
|
||||
(callback)( result, ep->xferred, ep->remaining );
|
||||
}
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif /* defined( USB_HOST ) */
|
||||
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
|
|
@ -0,0 +1,899 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, USB host peripheral interrupt handlers.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#include "em_device.h"
|
||||
#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
|
||||
#include "em_usb.h"
|
||||
#if defined( USB_HOST )
|
||||
|
||||
#include "em_usbtypes.h"
|
||||
#include "em_usbhal.h"
|
||||
#include "em_usbh.h"
|
||||
#if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE )
|
||||
#include "em_gpio.h"
|
||||
#endif
|
||||
|
||||
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
|
||||
|
||||
#define HANDLE_INT( x ) if ( status & x ) { Handle_##x(); status &= ~x; }
|
||||
|
||||
#define FIFO_TXSTS_HCNUM_MASK 0x78000000
|
||||
#define FIFO_TXSTS_HCNUM_SHIFT 27
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
#define TOGGLE_DATA_PID() \
|
||||
if ( eptype != HCCHAR_EPTYPE_ISOC ) \
|
||||
{ \
|
||||
if ( hc->ep->toggle == USB_PID_DATA0 ) \
|
||||
{ \
|
||||
hc->ep->toggle = USB_PID_DATA1; \
|
||||
} \
|
||||
else if ( hc->ep->toggle == USB_PID_DATA1 ) \
|
||||
{ \
|
||||
hc->ep->toggle = USB_PID_DATA0; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
static void Handle_HcInInt( uint8_t hcnum );
|
||||
static void Handle_HcOutInt( uint8_t hcnum );
|
||||
static void Handle_USB_GINTSTS_DISCONNINT ( void );
|
||||
static void Handle_USB_GINTSTS_HCHINT ( void );
|
||||
static void Handle_USB_GINTSTS_PRTINT ( void );
|
||||
#if defined( USB_SLAVEMODE )
|
||||
static void Handle_USB_GINTSTS_NPTXFEMP ( void );
|
||||
static void Handle_USB_GINTSTS_PTXFEMP ( void );
|
||||
static void Handle_USB_GINTSTS_RXFLVL ( void );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
|
||||
*/
|
||||
void USB_IRQHandler( void )
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
INT_Disable();
|
||||
|
||||
status = USBHAL_GetCoreInts();
|
||||
if ( status == 0 )
|
||||
{
|
||||
INT_Enable();
|
||||
DEBUG_USB_INT_LO_PUTS( "\nSinT" );
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
HANDLE_INT( USB_GINTSTS_RXFLVL )
|
||||
HANDLE_INT( USB_GINTSTS_NPTXFEMP )
|
||||
HANDLE_INT( USB_GINTSTS_PTXFEMP )
|
||||
#endif
|
||||
HANDLE_INT( USB_GINTSTS_HCHINT )
|
||||
HANDLE_INT( USB_GINTSTS_PRTINT )
|
||||
HANDLE_INT( USB_GINTSTS_DISCONNINT )
|
||||
|
||||
INT_Enable();
|
||||
|
||||
if ( status != 0 )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTS( "\nUinT" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle host channel IN transfer interrupt.
|
||||
*/
|
||||
static void Handle_HcInInt( uint8_t hcnum )
|
||||
{
|
||||
USBH_Hc_TypeDef *hc;
|
||||
USB_Status_TypeDef result;
|
||||
uint32_t status, hcchar, eptype;
|
||||
#ifdef DEBUG_USB_INT_HI
|
||||
uint32_t status2;
|
||||
#endif
|
||||
|
||||
hc = &hcs[ hcnum ];
|
||||
status = USBHHAL_GetHcInts( hcnum );
|
||||
hcchar = USB->HC[ hcnum ].CHAR;
|
||||
eptype = hcchar & _USB_HC_CHAR_EPTYPE_MASK;
|
||||
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'i' );
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
if ( status & USB_HC_INT_CHHLTD )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = 0xFFFFFFFF;
|
||||
|
||||
#ifdef DEBUG_USB_INT_HI
|
||||
status2 = status;
|
||||
#endif
|
||||
status &= USB_HC_INT_XFERCOMPL | USB_HC_INT_STALL | USB_HC_INT_XACTERR |
|
||||
USB_HC_INT_ACK | USB_HC_INT_NAK | USB_HC_INT_DATATGLERR |
|
||||
USB_HC_INT_BBLERR;
|
||||
|
||||
if ( ( status & ( USB_HC_INT_ACK | USB_HC_INT_XFERCOMPL ) ) ==
|
||||
( USB_HC_INT_ACK | USB_HC_INT_XFERCOMPL ) )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
|
||||
|
||||
hc->xferred = hc->hwXferSize -
|
||||
( ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_XFERSIZE_MASK ) >>
|
||||
_USB_HC_TSIZ_XFERSIZE_SHIFT );
|
||||
|
||||
hc->remaining -= hc->xferred;
|
||||
hc->ep->toggle = ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_PID_MASK ) ==
|
||||
USB_HC_TSIZ_PID_DATA0 ? USB_PID_DATA0 : USB_PID_DATA1;
|
||||
|
||||
result = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_STALL )
|
||||
{
|
||||
result = USB_STATUS_EP_STALLED;
|
||||
DEBUG_USB_INT_LO_PUTS( "StaL" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_BBLERR )
|
||||
{
|
||||
result = USB_STATUS_EP_ERROR;
|
||||
DEBUG_USB_INT_LO_PUTS( "BabL" );
|
||||
}
|
||||
|
||||
else if ( ( ( status &
|
||||
( USB_HC_INT_DATATGLERR | USB_HC_INT_NAK ) )
|
||||
== USB_HC_INT_DATATGLERR ) &&
|
||||
( !( hc->status & HCS_TIMEOUT ) ) )
|
||||
{
|
||||
/* Toggle error but not nak or timeout */
|
||||
result = USB_STATUS_EP_ERROR;
|
||||
DEBUG_USB_INT_LO_PUTS( "TglE" );
|
||||
|
||||
hc->errorCnt++;
|
||||
if ( hc->errorCnt < 3 )
|
||||
{
|
||||
USBHHAL_HCStart( hcnum );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( ( ( status &
|
||||
( USB_HC_INT_DATATGLERR | USB_HC_INT_NAK |
|
||||
USB_HC_INT_XACTERR ) )
|
||||
== USB_HC_INT_XACTERR ) &&
|
||||
( !( hc->status & HCS_TIMEOUT ) ) )
|
||||
{
|
||||
/* Exact error but not toggle err or nak or timeout */
|
||||
result = USB_STATUS_EP_ERROR;
|
||||
DEBUG_USB_INT_LO_PUTS( "XacT" );
|
||||
|
||||
hc->errorCnt++;
|
||||
if ( hc->errorCnt < 3 )
|
||||
{
|
||||
USBHHAL_HCStart( hcnum );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( hc->status & HCS_TIMEOUT )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 't' );
|
||||
result = USB_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_USB_INT_HI
|
||||
if ( !( ( eptype == HCCHAR_EPTYPE_INTR ) &&
|
||||
( ( status & USB_HC_INT_NAK ) == USB_HC_INT_NAK ) ) )
|
||||
{
|
||||
USB_PRINTF( "0x%08lX", status2 );
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if ( eptype == HCCHAR_EPTYPE_CTRL )
|
||||
USBHEP_CtrlEpHandler( hc->ep, result );
|
||||
else
|
||||
USBHEP_EpHandler( hc->ep, result );
|
||||
}
|
||||
#else /* !defined( USB_SLAVEMODE ) */
|
||||
|
||||
if ( status & USB_HC_INT_XFERCOMPL )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_XFERCOMPL;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_COMPLETED;
|
||||
|
||||
TOGGLE_DATA_PID() /* Update data toggle */
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_XACTERR )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_XACTERR;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_XACT;
|
||||
DEBUG_USB_INT_LO_PUTS( "XacT" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_BBLERR )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_BBLERR;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_BABBLE;
|
||||
DEBUG_USB_INT_LO_PUTS( "BabL" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_STALL )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_STALL;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_STALL;
|
||||
DEBUG_USB_INT_LO_PUTS( "StaL" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_NAK )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'n' );
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_NAK;
|
||||
|
||||
if ( ( eptype != HCCHAR_EPTYPE_INTR ) &&
|
||||
( hc->status == 0 ) )
|
||||
{
|
||||
/* Re-activate the channel */
|
||||
USBHHAL_HCActivate( hcnum, hcchar, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
hc->status |= HCS_NAK;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_DATATGLERR )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_DATATGLERR;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_TGLERR;
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_CHHLTD )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'h' );
|
||||
USB->HC[ hcnum ].INT = 0xFFFFFFFF;
|
||||
USB->HC[ hcnum ].INTMSK &= ~USB_HC_INT_CHHLTD;
|
||||
|
||||
result = USB_STATUS_EP_ERROR;
|
||||
|
||||
if ( hc->status & HCS_STALL )
|
||||
{
|
||||
result = USB_STATUS_EP_STALLED;
|
||||
}
|
||||
|
||||
else if ( ( hc->status &
|
||||
( HCS_NAK | HCS_STALL | HCS_TGLERR |
|
||||
HCS_BABBLE | HCS_TIMEOUT ) ) == HCS_TGLERR )
|
||||
{
|
||||
hc->errorCnt++;
|
||||
if ( hc->errorCnt < 3 )
|
||||
{
|
||||
hc->status |= HCS_RETRY;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( ( hc->status &
|
||||
( HCS_TGLERR | HCS_TIMEOUT |
|
||||
HCS_XACT | HCS_BABBLE ) ) == HCS_XACT )
|
||||
{
|
||||
hc->errorCnt++;
|
||||
if ( hc->errorCnt < 3 )
|
||||
{
|
||||
hc->status |= HCS_RETRY;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( ( hc->status & ( HCS_NAK | HCS_TIMEOUT ) ) == HCS_NAK )
|
||||
{
|
||||
if ( eptype == HCCHAR_EPTYPE_INTR )
|
||||
return;
|
||||
|
||||
result = USB_STATUS_EP_NAK;
|
||||
}
|
||||
|
||||
else if ( hc->status & ( HCS_TIMEOUT | HCS_NAK ) )
|
||||
{
|
||||
result = USB_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
else if ( hc->status == HCS_COMPLETED )
|
||||
{
|
||||
result = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
if ( hc->status & HCS_RETRY )
|
||||
{
|
||||
USBHHAL_HCStart( hcnum );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( eptype == HCCHAR_EPTYPE_CTRL )
|
||||
USBHEP_CtrlEpHandler( hc->ep, result );
|
||||
else
|
||||
USBHEP_EpHandler( hc->ep, result );
|
||||
}
|
||||
}
|
||||
#endif /* !defined( USB_SLAVEMODE ) */
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle host channel OUT transfer interrupt.
|
||||
*/
|
||||
static void Handle_HcOutInt( uint8_t hcnum )
|
||||
{
|
||||
USBH_Hc_TypeDef *hc;
|
||||
USB_Status_TypeDef result;
|
||||
uint32_t status, hcchar, eptype;
|
||||
#ifdef DEBUG_USB_INT_HI
|
||||
uint32_t status2;
|
||||
#endif
|
||||
|
||||
hc = &hcs[ hcnum ];
|
||||
status = USBHHAL_GetHcInts( hcnum );
|
||||
hcchar = USB->HC[ hcnum ].CHAR;
|
||||
eptype = hcchar & _USB_HC_CHAR_EPTYPE_MASK;
|
||||
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'o' );
|
||||
|
||||
#if !defined( USB_SLAVEMODE )
|
||||
if ( status & USB_HC_INT_CHHLTD )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = 0xFFFFFFFF;
|
||||
|
||||
#ifdef DEBUG_USB_INT_HI
|
||||
status2 = status;
|
||||
#endif
|
||||
status &= USB_HC_INT_XFERCOMPL | USB_HC_INT_STALL | USB_HC_INT_XACTERR |
|
||||
USB_HC_INT_ACK | USB_HC_INT_NAK;
|
||||
|
||||
if ( ( status & ( USB_HC_INT_ACK | USB_HC_INT_XFERCOMPL ) ) ==
|
||||
( USB_HC_INT_ACK | USB_HC_INT_XFERCOMPL ) )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
|
||||
|
||||
hc->xferred = hc->remaining;
|
||||
hc->remaining = 0;
|
||||
hc->ep->toggle = ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_PID_MASK ) ==
|
||||
USB_HC_TSIZ_PID_DATA0 ? USB_PID_DATA0 : USB_PID_DATA1;
|
||||
|
||||
result = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_STALL )
|
||||
{
|
||||
result = USB_STATUS_EP_STALLED;
|
||||
DEBUG_USB_INT_LO_PUTS( "StaL" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_XACTERR )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTS( "XacT" );
|
||||
if ( status & ( USB_HC_INT_ACK | USB_HC_INT_NAK ) )
|
||||
{
|
||||
hc->errorCnt = 0;
|
||||
USBHHAL_HCStart( hcnum );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
hc->errorCnt++;
|
||||
if ( hc->errorCnt < 3 )
|
||||
{
|
||||
USBHHAL_HCStart( hcnum );
|
||||
return;
|
||||
}
|
||||
}
|
||||
result = USB_STATUS_EP_ERROR;
|
||||
}
|
||||
|
||||
else if ( hc->status & HCS_TIMEOUT )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 't' );
|
||||
result = USB_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_USB_INT_HI
|
||||
if ( !( ( eptype == HCCHAR_EPTYPE_INTR ) &&
|
||||
( ( status & USB_HC_INT_NAK ) == USB_HC_INT_NAK ) ) )
|
||||
{
|
||||
USB_PRINTF( "0x%08lX", status2 );
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if ( eptype == HCCHAR_EPTYPE_CTRL )
|
||||
USBHEP_CtrlEpHandler( hc->ep, result );
|
||||
else
|
||||
USBHEP_EpHandler( hc->ep, result );
|
||||
}
|
||||
#else /* #if !defined( USB_SLAVEMODE ) */
|
||||
|
||||
if ( status & USB_HC_INT_XFERCOMPL )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'c' );
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_XFERCOMPL;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_COMPLETED;
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_STALL )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_STALL;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_STALL;
|
||||
DEBUG_USB_INT_LO_PUTS( "StaL" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_ACK )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'a' );
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_ACK;
|
||||
|
||||
if ( hc->pending )
|
||||
{
|
||||
hc->buf += hc->pending;
|
||||
hc->xferred += hc->pending;
|
||||
hc->remaining -= hc->pending;
|
||||
hc->pending = 0;
|
||||
|
||||
TOGGLE_DATA_PID() /* Update data toggle */
|
||||
|
||||
if ( eptype == HCCHAR_EPTYPE_INTR )
|
||||
{
|
||||
USBHHAL_FillFifo( hcnum, USB->HPTXSTS, hc ); /* There may be more data*/
|
||||
}
|
||||
else
|
||||
{
|
||||
USBHHAL_FillFifo( hcnum, USB->GNPTXSTS, hc );/* There may be more data*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_NAK )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'n' );
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_NAK;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_NAK;
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_XACTERR )
|
||||
{
|
||||
USB->HC[ hcnum ].INT = USB_HC_INT_XACTERR;
|
||||
USBHHAL_HCHalt( hcnum, hcchar, eptype );
|
||||
|
||||
hc->status |= HCS_XACT;
|
||||
DEBUG_USB_INT_LO_PUTS( "XacT" );
|
||||
}
|
||||
|
||||
else if ( status & USB_HC_INT_CHHLTD )
|
||||
{
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'h' );
|
||||
USB->HC[ hcnum ].INT = 0xFFFFFFFF;
|
||||
USB->HC[ hcnum ].INTMSK &= ~USB_HC_INT_CHHLTD;
|
||||
|
||||
result = USB_STATUS_EP_ERROR;
|
||||
|
||||
if ( hc->status & HCS_STALL )
|
||||
{
|
||||
result = USB_STATUS_EP_STALLED;
|
||||
}
|
||||
|
||||
else if ( hc->status == HCS_XACT )
|
||||
{
|
||||
hc->errorCnt++;
|
||||
if ( hc->errorCnt < 3 )
|
||||
{
|
||||
hc->status |= HCS_RETRY;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( ( hc->status & ( HCS_NAK | HCS_TIMEOUT ) ) == HCS_NAK )
|
||||
{
|
||||
if ( eptype == HCCHAR_EPTYPE_INTR )
|
||||
return;
|
||||
|
||||
hc->status |= HCS_RETRY;
|
||||
}
|
||||
|
||||
else if ( hc->status & HCS_TIMEOUT )
|
||||
{
|
||||
result = USB_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
else if ( hc->status == HCS_COMPLETED )
|
||||
{
|
||||
result = USB_STATUS_OK;
|
||||
}
|
||||
|
||||
if ( hc->status & HCS_RETRY )
|
||||
{
|
||||
USBHHAL_HCStart( hcnum );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( eptype == HCCHAR_EPTYPE_CTRL )
|
||||
USBHEP_CtrlEpHandler( hc->ep, result );
|
||||
else
|
||||
USBHEP_EpHandler( hc->ep, result );
|
||||
}
|
||||
}
|
||||
#endif /* #if !defined( USB_SLAVEMODE ) */
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle port disconnect interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_DISCONNINT( void )
|
||||
{
|
||||
int i;
|
||||
uint32_t hcchar;
|
||||
|
||||
USB->GINTSTS = USB_GINTSTS_DISCONNINT;
|
||||
USB->HAINTMSK = 0;
|
||||
|
||||
USBH_portStatus = H_PORT_DISCONNECTED;
|
||||
USBTIMER_Stop( HOSTPORT_TIMER_INDEX );
|
||||
USBHHAL_PortReset( false );
|
||||
|
||||
for ( i=0; i< NUM_HC_USED + 2; i++ )
|
||||
{
|
||||
hcchar = USB->HC[ i ].CHAR; /* Halt channel */
|
||||
USBHHAL_HCHalt( i, hcchar, hcchar & _USB_HC_CHAR_EPTYPE_MASK );
|
||||
USB->HC[ i ].INT = 0xFFFFFFFF; /* Clear pending interrupts */
|
||||
|
||||
if ( !hcs[ i ].idle )
|
||||
{
|
||||
USBHEP_TransferDone( hcs[ i ].ep, USB_STATUS_DEVICE_REMOVED );
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_USB_INT_LO_PUTS( "\nDisC" );
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle host channel interrupt. Call IN and OUT transfer handlers as needed.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_HCHINT( void )
|
||||
{
|
||||
uint8_t hcnum;
|
||||
uint32_t hcints, hcmask;
|
||||
|
||||
hcints = USBHHAL_GetHostChannelInts();
|
||||
|
||||
for ( hcnum = 0, hcmask = 1;
|
||||
hcnum < NUM_HC_USED + 2;
|
||||
hcnum++, hcmask <<= 1 )
|
||||
{
|
||||
if ( hcints & hcmask )
|
||||
{
|
||||
if ( USB->HC[ hcnum ].CHAR & USB_HC_CHAR_EPDIR )
|
||||
{
|
||||
Handle_HcInInt( hcnum );
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_HcOutInt( hcnum );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/*
|
||||
* Handle non periodic transmit FIFO empty interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_NPTXFEMP( void )
|
||||
{
|
||||
int i;
|
||||
uint8_t hcnum;
|
||||
uint32_t fifoStatus;
|
||||
USBH_Hc_TypeDef *hc;
|
||||
|
||||
fifoStatus = USB->GNPTXSTS;
|
||||
hcnum = ( fifoStatus & FIFO_TXSTS_HCNUM_MASK ) >> FIFO_TXSTS_HCNUM_SHIFT;
|
||||
hc = &hcs[ hcnum ];
|
||||
|
||||
USBHHAL_FillFifo( hcnum, fifoStatus, hc );
|
||||
|
||||
DEBUG_USB_INT_LO_PUTS( "NpE" );
|
||||
|
||||
for ( i = 0; i < NUM_HC_USED + 2; i++ )
|
||||
{
|
||||
if ( hcs[ i ].txNpFempIntOn == true )
|
||||
return; /* TxFemp int must remain on */
|
||||
}
|
||||
|
||||
USB->GINTMSK &= ~USB_GINTSTS_NPTXFEMP; /* Turn off TxFemp interrupt */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Callback function for port interrupt state machine.
|
||||
* Called on timeout of the port timer when a port reset is completed.
|
||||
*/
|
||||
static void PortResetComplete( void )
|
||||
{
|
||||
if ( USB->HPRT & USB_HPRT_PRTCONNSTS ) /* Is device still connected ? */
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '5' );
|
||||
}
|
||||
else
|
||||
{
|
||||
USBH_portStatus = H_PORT_DISCONNECTED;
|
||||
}
|
||||
USBHHAL_PortReset( false );
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for port interrupt state machine.
|
||||
* Called on timeout of the port timer connection debounce time has expired.
|
||||
*/
|
||||
static void PortDebounceComplete( void )
|
||||
{
|
||||
uint32_t hprt;
|
||||
|
||||
hprt = USB->HPRT; /* Get port status */
|
||||
|
||||
if ( hprt & USB_HPRT_PRTCONNSTS ) /* Is device still connected ? */
|
||||
{
|
||||
if ( ( hprt & _USB_HPRT_PRTSPD_MASK ) == HPRT_L_SPEED )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '3' );
|
||||
USB->HFIR = 6000;
|
||||
/* Set 6 MHz PHY clock */
|
||||
USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) |
|
||||
( 2 << _USB_HCFG_FSLSPCLKSEL_SHIFT );
|
||||
}
|
||||
else if ( ( hprt & _USB_HPRT_PRTSPD_MASK ) == HPRT_F_SPEED )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '4' );
|
||||
USB->HFIR = 48000;
|
||||
/* Set 48 MHz PHY clock */
|
||||
USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) |
|
||||
( 1 << _USB_HCFG_FSLSPCLKSEL_SHIFT );
|
||||
}
|
||||
|
||||
USBH_portStatus = H_PORT_CONNECTED_RESETTING;
|
||||
USBTIMER_Start( HOSTPORT_TIMER_INDEX,
|
||||
USBH_attachTiming[ USBH_attachRetryCount ].resetTime,
|
||||
PortResetComplete );
|
||||
USBHHAL_PortReset( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
USBH_portStatus = H_PORT_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle port interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_PRTINT( void )
|
||||
{
|
||||
uint32_t hprt;
|
||||
|
||||
hprt = USB->HPRT; /* Get port status */
|
||||
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '^' );
|
||||
|
||||
switch ( USBH_portStatus )
|
||||
{
|
||||
case H_PORT_DISCONNECTED:
|
||||
/***********************/
|
||||
if ( ( hprt & USB_HPRT_PRTCONNDET ) &&
|
||||
( hprt & USB_HPRT_PRTCONNSTS ) ) /* Any device connected ? */
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '2' );
|
||||
USBH_portStatus = H_PORT_CONNECTED_DEBOUNCING;
|
||||
USBTIMER_Start( HOSTPORT_TIMER_INDEX,
|
||||
USBH_attachTiming[ USBH_attachRetryCount ].debounceTime,
|
||||
PortDebounceComplete );
|
||||
}
|
||||
break;
|
||||
|
||||
case H_PORT_CONNECTED_DEBOUNCING:
|
||||
/***********************/
|
||||
DEBUG_USB_INT_LO_PUTCHAR( 'Y' );
|
||||
break;
|
||||
|
||||
case H_PORT_CONNECTED_RESETTING:
|
||||
/***********************/
|
||||
if ( ( hprt & USB_HPRT_PRTENCHNG ) && /* Port enable changed ? */
|
||||
( hprt & USB_HPRT_PRTENA ) && /* Port enabled ? */
|
||||
( hprt & USB_HPRT_PRTCONNSTS ) ) /* Device still connected ? */
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '6' );
|
||||
USBH_portStatus = H_PORT_CONNECTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case H_PORT_CONNECTED:
|
||||
/***********************/
|
||||
if ( ( hprt & USB_HPRT_PRTENCHNG ) &&
|
||||
( !( hprt & USB_HPRT_PRTENA ) ) )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( 'X' );
|
||||
#if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE )
|
||||
if ( GPIO_PinInGet( USB_VBUSOVRCUR_PORT, USB_VBUSOVRCUR_PIN ) ==
|
||||
USB_VBUSOVRCUR_POLARITY )
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '~' );
|
||||
USBHHAL_PortReset( false );
|
||||
USBHHAL_VbusOn( false );
|
||||
USBTIMER_Stop( HOSTPORT_TIMER_INDEX );
|
||||
USBH_portStatus = H_PORT_OVERCURRENT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case H_PORT_OVERCURRENT:
|
||||
/***********************/
|
||||
break;
|
||||
}
|
||||
|
||||
if ( hprt & USB_HPRT_PRTOVRCURRCHNG ) /* Overcurrent change interrupt ? */
|
||||
{
|
||||
DEBUG_USB_INT_LO_PUTCHAR( '9' );
|
||||
}
|
||||
|
||||
hprt &= ~HPRT_WC_MASK; /* Mask off all write clear bits */
|
||||
hprt |= USB_HPRT_PRTCONNDET | USB_HPRT_PRTENCHNG | USB_HPRT_PRTOVRCURRCHNG;
|
||||
USB->HPRT = hprt; /* Clear all port interrupt flags */
|
||||
}
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/*
|
||||
* Handle periodic transmit FIFO empty interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_PTXFEMP( void )
|
||||
{
|
||||
int i;
|
||||
uint8_t hcnum;
|
||||
uint32_t fifoStatus;
|
||||
USBH_Hc_TypeDef *hc;
|
||||
|
||||
fifoStatus = USB->HPTXSTS;
|
||||
hcnum = ( fifoStatus & FIFO_TXSTS_HCNUM_MASK ) >> FIFO_TXSTS_HCNUM_SHIFT;
|
||||
hc = &hcs[ hcnum ];
|
||||
|
||||
USBHHAL_FillFifo( hcnum, fifoStatus, hc );
|
||||
|
||||
DEBUG_USB_INT_LO_PUTS( "PE" );
|
||||
|
||||
for ( i = 0; i < NUM_HC_USED + 2; i++ )
|
||||
{
|
||||
if ( hcs[ i ].txPFempIntOn == true )
|
||||
return; /* TxFemp int must remain on */
|
||||
}
|
||||
|
||||
USB->GINTMSK &= ~USB_GINTSTS_PTXFEMP ; /* Turn off TxFemp interrupt */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined( USB_SLAVEMODE )
|
||||
/*
|
||||
* Handle receive FIFO full interrupt.
|
||||
*/
|
||||
static void Handle_USB_GINTSTS_RXFLVL( void )
|
||||
{
|
||||
uint8_t hcnum;
|
||||
USBH_Hc_TypeDef *hc;
|
||||
uint32_t grxstsp, hcchar;
|
||||
int bytecnt, pid, packetcnt;
|
||||
|
||||
/* Disable the Rx Status Queue Level interrupt */
|
||||
USB->GINTMSK &= ~USB_GINTMSK_RXFLVLMSK;
|
||||
|
||||
grxstsp = USB->GRXSTSP;
|
||||
hcnum = ( grxstsp & _USB_GRXSTSP_CHEPNUM_MASK ) >> _USB_GRXSTSP_CHEPNUM_SHIFT;
|
||||
hc = &hcs[ hcnum ];
|
||||
bytecnt = ( grxstsp & _USB_GRXSTSP_BCNT_MASK ) >> _USB_GRXSTSP_BCNT_SHIFT;
|
||||
pid = ( grxstsp & _USB_GRXSTSP_DPID_MASK ) >> _USB_GRXSTSP_DPID_SHIFT;
|
||||
packetcnt = ( USB->HC[ hcnum ].TSIZ & _USB_HC_TSIZ_PKTCNT_MASK ) >>
|
||||
_USB_HC_TSIZ_PKTCNT_SHIFT;
|
||||
hcchar = USB->HC[ hcnum ].CHAR;
|
||||
|
||||
DEBUG_USB_INT_HI_PUTCHAR( 'q' );
|
||||
|
||||
switch ( grxstsp & _USB_GRXSTSP_PKTSTS_MASK )
|
||||
{
|
||||
case GRXSTSP_PKTSTS_HOST_DATAINRECEIVED:
|
||||
/* Read the data into the host buffer. */
|
||||
if ( ( bytecnt > 0 ) && ( hc->buf != NULL ) )
|
||||
{
|
||||
USBHAL_ReadFifo( hc->buf, bytecnt );
|
||||
|
||||
hc->remaining -= bytecnt;
|
||||
hc->buf += bytecnt;
|
||||
hc->xferred += bytecnt;
|
||||
|
||||
if ( packetcnt )
|
||||
{
|
||||
/* re-activate the channel when more packets are expected */
|
||||
hcchar |= USB_HC_CHAR_CHENA;
|
||||
hcchar &= ~USB_HC_CHAR_CHDIS;
|
||||
USB->HC[ hcnum ].CHAR = hcchar;
|
||||
}
|
||||
|
||||
hc->ep->toggle = pid;
|
||||
}
|
||||
DEBUG_USB_INT_HI_PUTS( "IR" );
|
||||
break;
|
||||
|
||||
case GRXSTSP_PKTSTS_HOST_DATAINCOMPLETE:
|
||||
if ( packetcnt )
|
||||
{
|
||||
hc->ep->toggle = pid;
|
||||
}
|
||||
DEBUG_USB_INT_HI_PUTS( "IC" );
|
||||
break;
|
||||
|
||||
case GRXSTSP_PKTSTS_HOST_CHANNELHALTED:
|
||||
case GRXSTSP_PKTSTS_HOST_DATATOGGLEERROR:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable the Rx Status Queue Level interrupt */
|
||||
USB->GINTMSK |= USB_GINTMSK_RXFLVLMSK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif /* defined( USB_HOST ) */
|
||||
#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
|
|
@ -0,0 +1,384 @@
|
|||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief USB protocol stack library, timer API.
|
||||
* @author Energy Micro AS
|
||||
* @version 3.20.0
|
||||
*******************************************************************************
|
||||
* @section License
|
||||
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
|
||||
* microcontrollers and "EFR4" radios.
|
||||
*
|
||||
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
|
||||
* obligation to support this Software. Energy Micro AS is providing the
|
||||
* Software "AS IS", with no express or implied warranties of any kind,
|
||||
* including, but not limited to, any implied warranties of merchantability
|
||||
* or fitness for any particular purpose or warranties against infringement
|
||||
* of any proprietary rights of a third party.
|
||||
*
|
||||
* Energy Micro AS will not be liable for any consequential, incidental, or
|
||||
* special damages, or any other relief, or for any claim by any third party,
|
||||
* arising from your use of this Software.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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"
|
||||
|
||||
/*
|
||||
* 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
|
||||
#define USB_TIMER USB_TIMER0
|
||||
#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 );
|
||||
}
|
||||
|
||||
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 ) */
|
Loading…
Reference in New Issue