mirror of https://gerrit.osmocom.org/simtrace2
1719 lines
53 KiB
C
1719 lines
53 KiB
C
/* ----------------------------------------------------------------------------
|
|
* ATMEL Microcontroller Software Support
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2008, Atmel Corporation
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the disclaimer below.
|
|
*
|
|
* Atmel's name may not be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
|
|
\file
|
|
|
|
\section Purpose
|
|
|
|
Implementation of USB device functions on a UDP controller.
|
|
|
|
See \ref usbd_api_method USBD API Methods.
|
|
*/
|
|
|
|
/** \addtogroup usbd_hal
|
|
*@{*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Headers
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include "chip.h"
|
|
#include "USBD_HAL.h"
|
|
#include <usb/device/dfu/dfu.h>
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Definitions
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
/** Indicates chip has an UDP Full Speed. */
|
|
#define CHIP_USB_UDP
|
|
|
|
/** Indicates chip has an internal pull-up. */
|
|
#define CHIP_USB_PULLUP_INTERNAL
|
|
|
|
/** Number of USB endpoints */
|
|
#define CHIP_USB_NUMENDPOINTS 8
|
|
|
|
/** Endpoints max paxcket size */
|
|
#define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \
|
|
((i == 0) ? 64 : \
|
|
((i == 1) ? 64 : \
|
|
((i == 2) ? 64 : \
|
|
((i == 3) ? 64 : \
|
|
((i == 4) ? 512 : \
|
|
((i == 5) ? 512 : \
|
|
((i == 6) ? 64 : \
|
|
((i == 7) ? 64 : 0 ))))))))
|
|
|
|
/** Endpoints Number of Bank */
|
|
#define CHIP_USB_ENDPOINTS_BANKS(i) \
|
|
((i == 0) ? 1 : \
|
|
((i == 1) ? 2 : \
|
|
((i == 2) ? 2 : \
|
|
((i == 3) ? 1 : \
|
|
((i == 4) ? 2 : \
|
|
((i == 5) ? 2 : \
|
|
((i == 6) ? 2 : \
|
|
((i == 7) ? 2 : 0 ))))))))
|
|
|
|
/**
|
|
* \section UDP_registers_sec "UDP Register field values"
|
|
*
|
|
* This section lists the initialize values of UDP registers.
|
|
*
|
|
* \subsection Values
|
|
* - UDP_RXDATA
|
|
*/
|
|
/** Bit mask for both banks of the UDP_CSR register. */
|
|
#define UDP_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1)
|
|
|
|
/**
|
|
* \section endpoint_states_sec "UDP Endpoint states"
|
|
*
|
|
* This page lists the endpoint states.
|
|
*
|
|
* \subsection States
|
|
* - UDP_ENDPOINT_DISABLED
|
|
* - UDP_ENDPOINT_HALTED
|
|
* - UDP_ENDPOINT_IDLE
|
|
* - UDP_ENDPOINT_SENDING
|
|
* - UDP_ENDPOINT_RECEIVING
|
|
* - UDP_ENDPOINT_SENDINGM
|
|
* - UDP_ENDPOINT_RECEIVINGM
|
|
*/
|
|
|
|
/** Endpoint states: Endpoint is disabled */
|
|
#define UDP_ENDPOINT_DISABLED 0
|
|
/** Endpoint states: Endpoint is halted (i.e. STALLs every request) */
|
|
#define UDP_ENDPOINT_HALTED 1
|
|
/** Endpoint states: Endpoint is idle (i.e. ready for transmission) */
|
|
#define UDP_ENDPOINT_IDLE 2
|
|
/** Endpoint states: Endpoint is sending data */
|
|
#define UDP_ENDPOINT_SENDING 3
|
|
/** Endpoint states: Endpoint is receiving data */
|
|
#define UDP_ENDPOINT_RECEIVING 4
|
|
/** Endpoint states: Endpoint is sending MBL */
|
|
#define UDP_ENDPOINT_SENDINGM 5
|
|
/** Endpoint states: Endpoint is receiving MBL */
|
|
#define UDP_ENDPOINT_RECEIVINGM 6
|
|
|
|
/**
|
|
* \section udp_csr_register_access_sec "UDP CSR register access"
|
|
*
|
|
* This page lists the macros to access UDP CSR register.
|
|
*
|
|
* \comment
|
|
* In a preemptive environment, set or clear the flag and wait for a time of
|
|
* 1 UDPCK clock cycle and 1 peripheral clock cycle. However, RX_DATA_BK0,
|
|
* TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and
|
|
* 5 peripheral clock cycles before accessing DPR.
|
|
* See datasheet
|
|
*
|
|
* !Macros
|
|
* - CLEAR_CSR
|
|
* - SET_CSR
|
|
*/
|
|
|
|
#if defined ( __CC_ARM )
|
|
#define nop() {volatile int h; for(h=0;h<10;h++){}}
|
|
#elif defined ( __ICCARM__ )
|
|
#include <intrinsics.h>
|
|
#define nop() (__no_operation())
|
|
#elif defined ( __GNUC__ )
|
|
#define nop() __asm__ __volatile__ ( "nop" )
|
|
#endif
|
|
|
|
|
|
/** Bitmap for all status bits in CSR. */
|
|
#define REG_NO_EFFECT_1_ALL UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \
|
|
|UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \
|
|
|UDP_CSR_TXCOMP
|
|
|
|
/**
|
|
* Sets the specified bit(s) in the UDP_CSR register.
|
|
*
|
|
* \param endpoint The endpoint number of the CSR to process.
|
|
* \param flags The bitmap to set to 1.
|
|
*/
|
|
#define SET_CSR(endpoint, flags) \
|
|
{ \
|
|
volatile uint32_t reg; \
|
|
int32_t nop_count ; \
|
|
reg = UDP->UDP_CSR[endpoint] ; \
|
|
reg |= REG_NO_EFFECT_1_ALL; \
|
|
reg |= (flags); \
|
|
UDP->UDP_CSR[endpoint] = reg; \
|
|
for( nop_count=0; nop_count<15; nop_count++ ) {\
|
|
nop();\
|
|
}\
|
|
}
|
|
|
|
/**
|
|
* Clears the specified bit(s) in the UDP_CSR register.
|
|
*
|
|
* \param endpoint The endpoint number of the CSR to process.
|
|
* \param flags The bitmap to clear to 0.
|
|
*/
|
|
#define CLEAR_CSR(endpoint, flags) \
|
|
{ \
|
|
volatile uint32_t reg; \
|
|
int32_t nop_count ; \
|
|
reg = UDP->UDP_CSR[endpoint]; \
|
|
reg |= REG_NO_EFFECT_1_ALL; \
|
|
reg &= ~((uint32_t)(flags)); \
|
|
UDP->UDP_CSR[endpoint] = reg; \
|
|
for( nop_count=0; nop_count<15; nop_count++ ) {\
|
|
nop();\
|
|
}\
|
|
}
|
|
|
|
|
|
/** Get Number of buffer in Multi-Buffer-List
|
|
* \param i input index
|
|
* \param o output index
|
|
* \param size list size
|
|
*/
|
|
#define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o)))
|
|
|
|
/** Buffer list is full */
|
|
#define MBL_FULL 1
|
|
/** Buffer list is null */
|
|
#define MBL_NULL 2
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Types
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
/** Describes header for UDP endpoint transfer. */
|
|
typedef struct {
|
|
/** Optional callback to invoke when the transfer completes. */
|
|
void* fCallback;
|
|
/** Optional argument to the callback function. */
|
|
void* pArgument;
|
|
/** Transfer type */
|
|
uint8_t transType;
|
|
} TransferHeader;
|
|
|
|
/** Describes a transfer on a UDP endpoint. */
|
|
typedef struct {
|
|
|
|
/** Optional callback to invoke when the transfer completes. */
|
|
TransferCallback fCallback;
|
|
/** Optional argument to the callback function. */
|
|
void *pArgument;
|
|
/** Transfer type */
|
|
uint16_t transType;
|
|
/** Number of bytes which have been written into the UDP internal FIFO
|
|
* buffers. */
|
|
int16_t buffered;
|
|
/** Pointer to a data buffer used for emission/reception. */
|
|
uint8_t *pData;
|
|
/** Number of bytes which have been sent/received. */
|
|
int32_t transferred;
|
|
/** Number of bytes which have not been buffered/transferred yet. */
|
|
int32_t remaining;
|
|
} Transfer;
|
|
|
|
/** Describes Multi Buffer List transfer on a UDP endpoint. */
|
|
typedef struct {
|
|
/** Optional callback to invoke when the transfer completes. */
|
|
MblTransferCallback fCallback;
|
|
/** Optional argument to the callback function. */
|
|
void *pArgument;
|
|
/** Transfer type */
|
|
volatile uint8_t transType;
|
|
/** List state (OK, FULL, NULL) (run time) */
|
|
uint8_t listState;
|
|
/** Multi-Buffer List size */
|
|
uint16_t listSize;
|
|
/** Pointer to multi-buffer list */
|
|
USBDTransferBuffer *pMbl;
|
|
/** Offset number of buffers to start transfer */
|
|
uint16_t offsetSize;
|
|
/** Current processing buffer index (run time) */
|
|
uint16_t outCurr;
|
|
/** Loast loaded buffer index (run time) */
|
|
uint16_t outLast;
|
|
/** Current buffer for input (run time) */
|
|
uint16_t inCurr;
|
|
} MblTransfer;
|
|
|
|
/**
|
|
* Describes the state of an endpoint of the UDP controller.
|
|
*/
|
|
typedef struct {
|
|
|
|
/* CSR */
|
|
//uint32_t CSR;
|
|
/** Current endpoint state. */
|
|
volatile uint8_t state;
|
|
/** Current reception bank (0 or 1). */
|
|
volatile uint8_t bank;
|
|
/** Maximum packet size for the endpoint. */
|
|
volatile uint16_t size;
|
|
/** Describes an ongoing transfer (if current state is either
|
|
* UDP_ENDPOINT_SENDING or UDP_ENDPOINT_RECEIVING) */
|
|
union {
|
|
TransferHeader transHdr;
|
|
Transfer singleTransfer;
|
|
MblTransfer mblTransfer;
|
|
} transfer;
|
|
} Endpoint;
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Internal variables
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
/** Holds the internal state for each endpoint of the UDP. */
|
|
static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Internal Functions
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Enables the clock of the UDP peripheral.
|
|
* \return 1 if peripheral status changed.
|
|
*/
|
|
static uint8_t UDP_EnablePeripheralClock(void)
|
|
{
|
|
if (!PMC_IsPeriphEnabled(ID_UDP)) {
|
|
PMC_EnablePeripheral(ID_UDP);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Disables the UDP peripheral clock.
|
|
*/
|
|
static inline void UDP_DisablePeripheralClock(void)
|
|
{
|
|
PMC_DisablePeripheral(ID_UDP);
|
|
}
|
|
|
|
/**
|
|
* Enables the 48MHz USB clock.
|
|
*/
|
|
static inline void UDP_EnableUsbClock(void)
|
|
{
|
|
REG_PMC_SCER = PMC_SCER_UDP;
|
|
}
|
|
|
|
/**
|
|
* Disables the 48MHz USB clock.
|
|
*/
|
|
static inline void UDP_DisableUsbClock(void)
|
|
{
|
|
REG_PMC_SCDR = PMC_SCER_UDP;
|
|
}
|
|
|
|
/**
|
|
* Enables the UDP transceiver.
|
|
*/
|
|
static inline void UDP_EnableTransceiver(void)
|
|
{
|
|
UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_TXVDIS;
|
|
}
|
|
|
|
/**
|
|
* Disables the UDP transceiver.
|
|
*/
|
|
static inline void UDP_DisableTransceiver(void)
|
|
{
|
|
UDP->UDP_TXVC |= UDP_TXVC_TXVDIS;
|
|
}
|
|
|
|
/**
|
|
* Handles a completed transfer on the given endpoint, invoking the
|
|
* configured callback if any.
|
|
* \param bEndpoint Number of the endpoint for which the transfer has completed.
|
|
* \param bStatus Status code returned by the transfer operation
|
|
*/
|
|
static void UDP_EndOfTransfer(uint8_t bEndpoint, uint8_t bStatus)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
|
|
// Check that endpoint was sending or receiving data
|
|
if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
|
|
|| (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
|
|
|
|
Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer);
|
|
uint32_t transferred = pTransfer->transferred;
|
|
uint32_t remaining = pTransfer->remaining + pTransfer->buffered;
|
|
|
|
TRACE_DEBUG_WP("EoT ");
|
|
|
|
/* Endpoint returns in Idle state */
|
|
pEndpoint->state = UDP_ENDPOINT_IDLE;
|
|
/* Reset descriptor values */
|
|
pTransfer->pData = 0;
|
|
pTransfer->transferred = -1;
|
|
pTransfer->buffered = -1;
|
|
pTransfer->remaining = -1;
|
|
|
|
// Invoke callback is present
|
|
if (pTransfer->fCallback != 0) {
|
|
|
|
((TransferCallback) pTransfer->fCallback)
|
|
(pTransfer->pArgument,
|
|
bStatus,
|
|
transferred,
|
|
remaining);
|
|
}
|
|
else {
|
|
TRACE_DEBUG_WP("NoCB ");
|
|
}
|
|
}
|
|
else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
|
|
|| (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) {
|
|
|
|
MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
|
|
|
|
TRACE_DEBUG_WP("EoMT ");
|
|
|
|
/* Endpoint returns in Idle state */
|
|
pEndpoint->state = UDP_ENDPOINT_IDLE;
|
|
/* Reset transfer descriptor */
|
|
if (pTransfer->transType) {
|
|
MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
|
|
pMblt->listState = 0;
|
|
pMblt->outCurr = pMblt->inCurr = pMblt->outLast = 0;
|
|
}
|
|
/* Invoke callback */
|
|
if (pTransfer->fCallback != 0) {
|
|
|
|
((MblTransferCallback) pTransfer->fCallback)
|
|
(pTransfer->pArgument,
|
|
bStatus);
|
|
}
|
|
else {
|
|
TRACE_DEBUG_WP("NoCB ");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clears the correct reception flag (bank 0 or bank 1) of an endpoint
|
|
* \param bEndpoint Index of endpoint
|
|
*/
|
|
static void UDP_ClearRxFlag(uint8_t bEndpoint)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
|
|
// Clear flag and change banks
|
|
if (pEndpoint->bank == 0) {
|
|
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK0);
|
|
// Swap bank if in dual-fifo mode
|
|
if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) {
|
|
|
|
pEndpoint->bank = 1;
|
|
}
|
|
}
|
|
else {
|
|
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK1);
|
|
pEndpoint->bank = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update multi-buffer-transfer descriptors.
|
|
* \param pTransfer Pointer to instance MblTransfer.
|
|
* \param size Size of bytes that processed.
|
|
* \param forceEnd Force the buffer END.
|
|
* \return 1 if current buffer ended.
|
|
*/
|
|
static uint8_t UDP_MblUpdate(MblTransfer *pTransfer,
|
|
USBDTransferBuffer * pBi,
|
|
uint16_t size,
|
|
uint8_t forceEnd)
|
|
{
|
|
/* Update transfer descriptor */
|
|
pBi->remaining -= size;
|
|
/* Check if list NULL */
|
|
if (pTransfer->listState == MBL_NULL) {
|
|
return 1;
|
|
}
|
|
/* Check if current buffer ended */
|
|
if (pBi->remaining == 0 || forceEnd || size == 0) {
|
|
|
|
/* Process to next buffer */
|
|
if ((++ pTransfer->outCurr) == pTransfer->listSize)
|
|
pTransfer->outCurr = 0;
|
|
/* Check buffer NULL case */
|
|
if (pTransfer->outCurr == pTransfer->inCurr)
|
|
pTransfer->listState = MBL_NULL;
|
|
else {
|
|
pTransfer->listState = 0;
|
|
/* Continue transfer, prepare for next operation */
|
|
pBi = &pTransfer->pMbl[pTransfer->outCurr];
|
|
pBi->buffered = 0;
|
|
pBi->transferred = 0;
|
|
pBi->remaining = pBi->size;
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Transfers a data payload from the current tranfer buffer to the endpoint
|
|
* FIFO
|
|
* \param bEndpoint Number of the endpoint which is sending data.
|
|
*/
|
|
static uint8_t UDP_MblWriteFifo(uint8_t bEndpoint)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
|
|
USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]);
|
|
int32_t size;
|
|
|
|
volatile uint8_t * pBytes;
|
|
volatile uint8_t bufferEnd = 1;
|
|
|
|
/* Get the number of bytes to send */
|
|
size = pEndpoint->size;
|
|
if (size > pBi->remaining) size = pBi->remaining;
|
|
|
|
TRACE_DEBUG_WP("w%d.%" PRId32 " ", pTransfer->outCurr, size);
|
|
|
|
/* Record last accessed buffer */
|
|
pTransfer->outLast = pTransfer->outCurr;
|
|
|
|
pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
|
|
pBi->buffered += size;
|
|
bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0);
|
|
|
|
/* Write packet in the FIFO buffer */
|
|
if (size) {
|
|
int32_t c8 = size >> 3;
|
|
int32_t c1 = size & 0x7;
|
|
for (; c8; c8 --) {
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
}
|
|
for (; c1; c1 --) {
|
|
UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
|
|
}
|
|
}
|
|
return bufferEnd;
|
|
}
|
|
|
|
/**
|
|
* Transfers a data payload from the current tranfer buffer to the endpoint
|
|
* FIFO
|
|
* \param bEndpoint Number of the endpoint which is sending data.
|
|
*/
|
|
static void UDP_WritePayload(uint8_t bEndpoint)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
|
int32_t size;
|
|
|
|
// Get the number of bytes to send
|
|
size = pEndpoint->size;
|
|
if (size > pTransfer->remaining) {
|
|
|
|
size = pTransfer->remaining;
|
|
}
|
|
|
|
// Update transfer descriptor information
|
|
pTransfer->buffered += size;
|
|
pTransfer->remaining -= size;
|
|
|
|
// Write packet in the FIFO buffer
|
|
while (size > 0) {
|
|
|
|
UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData);
|
|
pTransfer->pData++;
|
|
size--;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Transfers a data payload from an endpoint FIFO to the current transfer buffer
|
|
* \param bEndpoint Endpoint number.
|
|
* \param wPacketSize Size of received data packet
|
|
*/
|
|
static void UDP_ReadPayload(uint8_t bEndpoint, int32_t wPacketSize)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
|
|
|
// Check that the requested size is not bigger than the remaining transfer
|
|
if (wPacketSize > pTransfer->remaining) {
|
|
|
|
pTransfer->buffered += wPacketSize - pTransfer->remaining;
|
|
wPacketSize = pTransfer->remaining;
|
|
}
|
|
|
|
// Update transfer descriptor information
|
|
pTransfer->remaining -= wPacketSize;
|
|
pTransfer->transferred += wPacketSize;
|
|
|
|
// Retrieve packet
|
|
while (wPacketSize > 0) {
|
|
|
|
*(pTransfer->pData) = (uint8_t) UDP->UDP_FDR[bEndpoint];
|
|
pTransfer->pData++;
|
|
wPacketSize--;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Received SETUP packet from endpoint 0 FIFO
|
|
* \param pRequest Generic USB SETUP request sent over Control endpoints
|
|
*/
|
|
static void UDP_ReadRequest(USBGenericRequest *pRequest)
|
|
{
|
|
uint8_t *pData = (uint8_t *)pRequest;
|
|
uint32_t i;
|
|
|
|
// Copy packet
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
*pData = (uint8_t) UDP->UDP_FDR[0];
|
|
pData++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if an ongoing transfer on an endpoint has been completed.
|
|
* \param bEndpoint Endpoint number.
|
|
* \return 1 if the current transfer on the given endpoint is complete;
|
|
* otherwise 0.
|
|
*/
|
|
static uint8_t UDP_IsTransferFinished(uint8_t bEndpoint)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
|
|
|
// Check if it is a Control endpoint
|
|
// -> Control endpoint must always finish their transfer with a zero-length
|
|
// packet
|
|
if ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) {
|
|
|
|
return (pTransfer->buffered < pEndpoint->size);
|
|
}
|
|
// Other endpoints only need to transfer all the data
|
|
else {
|
|
|
|
return (pTransfer->buffered <= pEndpoint->size)
|
|
&& (pTransfer->remaining == 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Endpoint interrupt handler.
|
|
* Handle IN/OUT transfers, received SETUP packets and STALLing
|
|
* \param bEndpoint Index of endpoint
|
|
*/
|
|
static void UDP_EndpointHandler(uint8_t bEndpoint)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
|
MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
|
|
uint32_t status = UDP->UDP_CSR[bEndpoint];
|
|
uint16_t wPacketSize;
|
|
USBGenericRequest request;
|
|
|
|
TRACE_DEBUG_WP("E%d ", bEndpoint);
|
|
TRACE_DEBUG_WP("st:0x%" PRIX32 " ", status);
|
|
|
|
// Handle interrupts
|
|
// IN packet sent
|
|
if ((status & UDP_CSR_TXCOMP) != 0) {
|
|
|
|
TRACE_DEBUG_WP("Wr ");
|
|
|
|
// Check that endpoint was in MBL Sending state
|
|
if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) {
|
|
|
|
USBDTransferBuffer * pMbli = &(pMblt->pMbl[pMblt->outLast]);
|
|
uint8_t bufferEnd = 0;
|
|
|
|
TRACE_DEBUG_WP("TxM%d.%d ", pMblt->listState, pMbli->buffered);
|
|
|
|
// End of transfer ?
|
|
if (pMblt->listState == MBL_NULL && pMbli->buffered == 0) {
|
|
|
|
pMbli->transferred += pMbli->buffered;
|
|
pMbli->buffered = 0;
|
|
|
|
// Disable interrupt
|
|
UDP->UDP_IDR = 1 << bEndpoint;
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
}
|
|
else {
|
|
|
|
// Transfer remaining data
|
|
TRACE_DEBUG_WP("%d ", pEndpoint->size);
|
|
|
|
if (pMbli->buffered > pEndpoint->size) {
|
|
pMbli->transferred += pEndpoint->size;
|
|
pMbli->buffered -= pEndpoint->size;
|
|
}
|
|
else {
|
|
pMbli->transferred += pMbli->buffered;
|
|
pMbli->buffered = 0;
|
|
}
|
|
|
|
// Send next packet
|
|
if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
|
|
|
|
// No double buffering
|
|
bufferEnd = UDP_MblWriteFifo(bEndpoint);
|
|
SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
}
|
|
else {
|
|
// Double buffering
|
|
SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
bufferEnd = UDP_MblWriteFifo(bEndpoint);
|
|
}
|
|
|
|
if (bufferEnd && pMblt->fCallback) {
|
|
((MblTransferCallback) pTransfer->fCallback)
|
|
(pTransfer->pArgument,
|
|
USBD_STATUS_PARTIAL_DONE);
|
|
}
|
|
}
|
|
}
|
|
// Check that endpoint was in Sending state
|
|
else if (pEndpoint->state == UDP_ENDPOINT_SENDING) {
|
|
|
|
// End of transfer ?
|
|
if (UDP_IsTransferFinished(bEndpoint)) {
|
|
|
|
pTransfer->transferred += pTransfer->buffered;
|
|
pTransfer->buffered = 0;
|
|
|
|
// Disable interrupt if this is not a control endpoint
|
|
if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) {
|
|
|
|
UDP->UDP_IDR = 1 << bEndpoint;
|
|
}
|
|
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
}
|
|
else {
|
|
|
|
// Transfer remaining data
|
|
TRACE_DEBUG_WP(" %d ", pEndpoint->size);
|
|
|
|
pTransfer->transferred += pEndpoint->size;
|
|
pTransfer->buffered -= pEndpoint->size;
|
|
|
|
// Send next packet
|
|
if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
|
|
|
|
// No double buffering
|
|
UDP_WritePayload(bEndpoint);
|
|
SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
}
|
|
else {
|
|
// Double buffering
|
|
SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
UDP_WritePayload(bEndpoint);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Acknowledge interrupt
|
|
TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state);
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP);
|
|
}
|
|
}
|
|
|
|
// OUT packet received
|
|
if ((status & UDP_CSR_RXDATA_BK) != 0) {
|
|
|
|
TRACE_DEBUG_WP("Rd ");
|
|
|
|
// Check that the endpoint is in Receiving state
|
|
if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
|
|
|
|
// Check if an ACK has been received on a Control endpoint
|
|
if (((status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL)
|
|
&& ((status & UDP_CSR_RXBYTECNT_Msk) == 0)) {
|
|
|
|
// Acknowledge the data and finish the current transfer
|
|
UDP_ClearRxFlag(bEndpoint);
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
|
}
|
|
// Check if the data has been STALLed
|
|
else if ((status & UDP_CSR_FORCESTALL) != 0) {
|
|
|
|
// Discard STALLed data
|
|
TRACE_DEBUG_WP("Discard ");
|
|
UDP_ClearRxFlag(bEndpoint);
|
|
}
|
|
// NAK the data
|
|
else {
|
|
|
|
TRACE_DEBUG_WP("Nak ");
|
|
UDP->UDP_IDR = 1 << bEndpoint;
|
|
}
|
|
}
|
|
// Endpoint is in Read state
|
|
else {
|
|
|
|
// Retrieve data and store it into the current transfer buffer
|
|
wPacketSize = (uint16_t) (status >> 16);
|
|
TRACE_DEBUG_WP("%d ", wPacketSize);
|
|
UDP_ReadPayload(bEndpoint, wPacketSize);
|
|
UDP_ClearRxFlag(bEndpoint);
|
|
|
|
// Check if the transfer is finished
|
|
if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) {
|
|
|
|
// Disable interrupt if this is not a control endpoint
|
|
if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) {
|
|
|
|
UDP->UDP_IDR = 1 << bEndpoint;
|
|
}
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
|
}
|
|
}
|
|
}
|
|
|
|
// STALL sent
|
|
if ((status & UDP_CSR_STALLSENTISOERROR) != 0) {
|
|
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR);
|
|
|
|
if ( (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_IN
|
|
|| (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_OUT ) {
|
|
|
|
TRACE_WARNING("Isoe [%d] ", bEndpoint);
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
|
|
}
|
|
else {
|
|
|
|
TRACE_WARNING("Sta 0x%X [%d] ", (int)status, bEndpoint);
|
|
|
|
if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
|
|
|
|
TRACE_WARNING( "_ " );
|
|
// If the endpoint is not halted, clear the STALL condition
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL);
|
|
}
|
|
}
|
|
}
|
|
|
|
// SETUP packet received
|
|
if ((status & UDP_CSR_RXSETUP) != 0) {
|
|
|
|
TRACE_DEBUG_WP("Stp ");
|
|
|
|
// If a transfer was pending, complete it
|
|
// Handles the case where during the status phase of a control write
|
|
// transfer, the host receives the device ZLP and ack it, but the ack
|
|
// is not received by the device
|
|
if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
|
|
|| (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
|
|
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
|
|
}
|
|
// Copy the setup packet
|
|
UDP_ReadRequest(&request);
|
|
|
|
// Set the DIR bit before clearing RXSETUP in Control IN sequence
|
|
if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) {
|
|
|
|
SET_CSR(bEndpoint, UDP_CSR_DIR);
|
|
}
|
|
// Acknowledge setup packet
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_RXSETUP);
|
|
|
|
// Forward the request to the upper layer
|
|
USBD_RequestHandler(0, &request);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Sends data through a USB endpoint. Sets up the transfer descriptor,
|
|
* writes one or two data payloads (depending on the number of FIFO bank
|
|
* for the endpoint) and then starts the actual transfer. The operation is
|
|
* complete when all the data has been sent.
|
|
*
|
|
* *If the size of the buffer is greater than the size of the endpoint
|
|
* (or twice the size if the endpoint has two FIFO banks), then the buffer
|
|
* must be kept allocated until the transfer is finished*. This means that
|
|
* it is not possible to declare it on the stack (i.e. as a local variable
|
|
* of a function which returns after starting a transfer).
|
|
*
|
|
* \param pEndpoint Pointer to Endpoint struct.
|
|
* \param pData Pointer to a buffer with the data to send.
|
|
* \param dLength Size of the data buffer.
|
|
* \return USBD_STATUS_SUCCESS if the transfer has been started;
|
|
* otherwise, the corresponding error status code.
|
|
*/
|
|
static inline uint8_t UDP_Write(uint8_t bEndpoint,
|
|
const void *pData,
|
|
uint32_t dLength)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
|
|
|
/* Check that the endpoint is in Idle state */
|
|
if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
|
|
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
TRACE_DEBUG_WP("Write%d(%" PRIu32 ") ", bEndpoint, dLength);
|
|
|
|
/* int i;
|
|
for (i = 0; i < dLength; i++) {
|
|
if (!(i%16)) {
|
|
printf("\n\r");
|
|
}
|
|
printf("0x%x ", ((uint8_t*)pData)[i]);
|
|
}
|
|
printf("\n\r");
|
|
*/
|
|
|
|
/* Setup the transfer descriptor */
|
|
pTransfer->pData = (void *) pData;
|
|
pTransfer->remaining = dLength;
|
|
pTransfer->buffered = 0;
|
|
pTransfer->transferred = 0;
|
|
|
|
/* Send the first packet */
|
|
pEndpoint->state = UDP_ENDPOINT_SENDING;
|
|
while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
|
|
UDP_WritePayload(bEndpoint);
|
|
SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
|
|
|
/* If double buffering is enabled and there is data remaining,
|
|
prepare another packet */
|
|
if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) {
|
|
|
|
UDP_WritePayload(bEndpoint);
|
|
}
|
|
|
|
/* Enable interrupt on endpoint */
|
|
UDP->UDP_IER = 1 << bEndpoint;
|
|
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Sends data through a USB endpoint. Sets up the transfer descriptor list,
|
|
* writes one or two data payloads (depending on the number of FIFO bank
|
|
* for the endpoint) and then starts the actual transfer. The operation is
|
|
* complete when all the transfer buffer in the list has been sent.
|
|
*
|
|
* *If the size of the buffer is greater than the size of the endpoint
|
|
* (or twice the size if the endpoint has two FIFO banks), then the buffer
|
|
* must be kept allocated until the transfer is finished*. This means that
|
|
* it is not possible to declare it on the stack (i.e. as a local variable
|
|
* of a function which returns after starting a transfer).
|
|
*
|
|
* \param pEndpoint Pointer to Endpoint struct.
|
|
* \param pData Pointer to a buffer with the data to send.
|
|
* \param dLength Size of the data buffer.
|
|
* \return USBD_STATUS_SUCCESS if the transfer has been started;
|
|
* otherwise, the corresponding error status code.
|
|
*/
|
|
static inline uint8_t UDP_AddWr(uint8_t bEndpoint,
|
|
const void *pData,
|
|
uint32_t dLength)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
MblTransfer *pMbl = (MblTransfer*)&(pEndpoint->transfer);
|
|
USBDTransferBuffer *pTx;
|
|
|
|
/* Check parameter */
|
|
if (dLength >= 0x10000)
|
|
return USBD_STATUS_INVALID_PARAMETER;
|
|
|
|
/* Data in progressing */
|
|
if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
|
|
/* If list full */
|
|
if (pMbl->listState == MBL_FULL) {
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
}
|
|
|
|
TRACE_DEBUG_WP("AddW%d(%" PRIu32 ") ", bEndpoint, dLength);
|
|
|
|
/* Add buffer to buffer list and update index */
|
|
pTx = &(pMbl->pMbl[pMbl->inCurr]);
|
|
pTx->pBuffer = (uint8_t*)pData;
|
|
pTx->size = pTx->remaining = dLength;
|
|
pTx->transferred = pTx->buffered = 0;
|
|
/* Update input index */
|
|
if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0;
|
|
else pMbl->inCurr ++;
|
|
if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL;
|
|
else pMbl->listState = 0;
|
|
/* Start sending when offset achieved */
|
|
if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize)
|
|
>= pMbl->offsetSize
|
|
&& pEndpoint->state == UDP_ENDPOINT_IDLE) {
|
|
TRACE_DEBUG_WP("StartT ");
|
|
/* Change state */
|
|
pEndpoint->state = UDP_ENDPOINT_SENDINGM;
|
|
while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
|
|
/* Send first packet */
|
|
UDP_MblWriteFifo(bEndpoint);
|
|
SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);
|
|
/* If double buffering is enabled and there is remaining, continue */
|
|
if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
|
|
&& pMbl->pMbl[pMbl->outCurr].remaining) {
|
|
UDP_MblWriteFifo(bEndpoint);
|
|
}
|
|
/* Enable interrupt on endpoint */
|
|
UDP->UDP_IER = 1 << bEndpoint;
|
|
}
|
|
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Reads incoming data on an USB endpoint This methods sets the transfer
|
|
* descriptor and activate the endpoint interrupt. The actual transfer is
|
|
* then carried out by the endpoint interrupt handler. The Read operation
|
|
* finishes either when the buffer is full, or a short packet (inferior to
|
|
* endpoint maximum size) is received.
|
|
*
|
|
* *The buffer must be kept allocated until the transfer is finished*.
|
|
* \param bEndpoint Endpoint number.
|
|
* \param pData Pointer to a data buffer.
|
|
* \param dLength Size of the data buffer in bytes.
|
|
* \return USBD_STATUS_SUCCESS if the read operation has been started;
|
|
* otherwise, the corresponding error code.
|
|
*/
|
|
static inline uint8_t UDP_Read(uint8_t bEndpoint,
|
|
void *pData,
|
|
uint32_t dLength)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
|
|
|
|
/* Return if the endpoint is not in IDLE state */
|
|
if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
|
|
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
|
|
/* Endpoint enters Receiving state */
|
|
pEndpoint->state = UDP_ENDPOINT_RECEIVING;
|
|
TRACE_DEBUG_WP("Read%d(%" PRIu32 ") ", bEndpoint, dLength);
|
|
|
|
/* int i;
|
|
for (i = 0; i < dLength; i++) {
|
|
if (!(i%16)) {
|
|
printf("\n\r");
|
|
}
|
|
printf("0x%x ", ((uint8_t*)pData)[i]);
|
|
}
|
|
printf("\n\r");
|
|
*/
|
|
|
|
/* Set the transfer descriptor */
|
|
pTransfer->pData = pData;
|
|
pTransfer->remaining = dLength;
|
|
pTransfer->buffered = 0;
|
|
pTransfer->transferred = 0;
|
|
|
|
/* Enable interrupt on endpoint */
|
|
UDP->UDP_IER = 1 << bEndpoint;
|
|
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Exported functions
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
|
|
uint16_t USBD_GetEndpointSize(uint8_t bEndpoint)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
|
|
return pEndpoint->size;
|
|
}
|
|
|
|
/**
|
|
* USBD (UDP) interrupt handler
|
|
* Manages device resume, suspend, end of bus reset.
|
|
* Forwards endpoint events to the appropriate handler.
|
|
*/
|
|
void USBD_IrqHandler(void)
|
|
{
|
|
uint32_t status;
|
|
int32_t eptnum = 0;
|
|
|
|
/* Enable peripheral ? */
|
|
//UDP_EnablePeripheralClock();
|
|
|
|
/* Get interrupt status
|
|
Some interrupts may get masked depending on the device state */
|
|
status = UDP->UDP_ISR;
|
|
status &= UDP->UDP_IMR;
|
|
|
|
TRACE_DEBUG("status; 0x%" PRIx32 , status);
|
|
|
|
if (USBD_GetState() < USBD_STATE_POWERED) {
|
|
|
|
status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM;
|
|
UDP->UDP_ICR = ~status;
|
|
}
|
|
|
|
/* Return immediately if there is no interrupt to service */
|
|
if (status == 0) {
|
|
|
|
TRACE_DEBUG_WP(".\n\r");
|
|
return;
|
|
}
|
|
|
|
/* Toggle USB LED if the device is active */
|
|
if (USBD_GetState() >= USBD_STATE_POWERED) {
|
|
|
|
//LED_Set(USBD_LEDUSB);
|
|
}
|
|
|
|
/* Service interrupts */
|
|
|
|
/** / Start Of Frame (SOF) */
|
|
//if (ISSET(dStatus, UDP_ISR_SOFINT)) {
|
|
//
|
|
// TRACE_DEBUG("SOF");
|
|
//
|
|
// // Invoke the SOF callback
|
|
// USB_StartOfFrameCallback(pUsb);
|
|
//
|
|
// // Acknowledge interrupt
|
|
// UDP->UDP_ICR = UDP_ICR_SOFINT;
|
|
// dStatus &= ~UDP_ISR_SOFINT;
|
|
//}
|
|
/* Resume (Wakeup) */
|
|
if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) {
|
|
|
|
TRACE_DEBUG_WP("Res ");
|
|
/* Clear and disable resume interrupts */
|
|
UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
|
|
UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM;
|
|
/* Do resome operations */
|
|
USBD_ResumeHandler();
|
|
}
|
|
|
|
/* Suspend
|
|
This interrupt is always treated last (hence the '==') */
|
|
if (status == UDP_ISR_RXSUSP) {
|
|
|
|
TRACE_DEBUG_WP("Susp ");
|
|
/* Enable wakeup */
|
|
UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM;
|
|
/* Acknowledge interrupt */
|
|
UDP->UDP_ICR = UDP_ICR_RXSUSP;
|
|
/* Do suspend operations */
|
|
USBD_SuspendHandler();
|
|
}
|
|
/* End of bus reset */
|
|
else if ((status & UDP_ISR_ENDBUSRES) != 0) {
|
|
|
|
TRACE_DEBUG_WP("EoBRes ");
|
|
|
|
#if defined(BOARD_USB_DFU)
|
|
#if defined(APPLICATION_dfu)
|
|
/* if we are currently in the DFU bootloader, and we are beyond
|
|
* the MANIFEST stage, we shall switch to the normal
|
|
* application */
|
|
if (g_dfu->past_manifest)
|
|
USBDFU_SwitchToApp();
|
|
#else
|
|
/* if we are currently in the main application, and we are in
|
|
* appDETACH state, switch into the DFU bootloader */
|
|
if (g_dfu->state == DFU_STATE_appDETACH)
|
|
DFURT_SwitchToDFU();
|
|
#endif /* APPLICATION_dfu */
|
|
#endif /* BOARD_USB_DFU */
|
|
|
|
/* Flush and enable the Suspend interrupt */
|
|
UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP;
|
|
UDP->UDP_IER = UDP_IER_RXSUSP;
|
|
|
|
/* Do RESET operations */
|
|
USBD_ResetHandler();
|
|
|
|
/* Acknowledge end of bus reset interrupt */
|
|
UDP->UDP_ICR = UDP_ICR_ENDBUSRES;
|
|
}
|
|
/* Endpoint interrupts */
|
|
else {
|
|
|
|
status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1);
|
|
while (status != 0) {
|
|
|
|
/* Check if endpoint has a pending interrupt */
|
|
if ((status & (1 << eptnum)) != 0) {
|
|
|
|
UDP_EndpointHandler(eptnum);
|
|
status &= ~(1 << eptnum);
|
|
|
|
if (status != 0) {
|
|
|
|
TRACE_DEBUG_WP("\n\r - ");
|
|
}
|
|
}
|
|
eptnum++;
|
|
}
|
|
}
|
|
|
|
/* Toggle LED back to its previous state */
|
|
TRACE_DEBUG_WP("!");
|
|
TRACE_DEBUG_WP("\n\r");
|
|
if (USBD_GetState() >= USBD_STATE_POWERED) {
|
|
|
|
//LED_Clear(USBD_LEDUSB);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Reset endpoints and disable them.
|
|
* -# Terminate transfer if there is any, with given status;
|
|
* -# Reset the endpoint & disable it.
|
|
* \param bmEPs Bitmap for endpoints to reset.
|
|
* \param bStatus Status passed to terminate transfer on endpoint.
|
|
* \param bKeepCfg 1 to keep old endpoint configuration.
|
|
* \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint
|
|
if not keeping old configuration.
|
|
* \sa USBD_HAL_ConfigureEP().
|
|
*/
|
|
void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg)
|
|
{
|
|
Endpoint *pEndpoint;
|
|
uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
|
|
uint8_t ep;
|
|
uint32_t epBit, epCfg;
|
|
for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++) {
|
|
if (tmp & epBit) {
|
|
|
|
/* Disable ISR */
|
|
UDP->UDP_IDR = epBit;
|
|
/* Kill pending TXPKTREADY */
|
|
CLEAR_CSR(ep, UDP_CSR_TXPKTRDY);
|
|
|
|
/* Reset transfer information */
|
|
pEndpoint = &(endpoints[ep]);
|
|
/* Reset endpoint state */
|
|
pEndpoint->bank = 0;
|
|
/* Endpoint configure */
|
|
epCfg = UDP->UDP_CSR[ep];
|
|
/* Reset endpoint */
|
|
UDP->UDP_RST_EP |= epBit;
|
|
UDP->UDP_RST_EP &= ~epBit;
|
|
/* Restore configure */
|
|
if (bKeepCfg) {
|
|
//SET_CSR(ep, pEndpoint->CSR);
|
|
SET_CSR(ep, epCfg);
|
|
}
|
|
else {
|
|
//pEndpoint->CSR = 0;
|
|
pEndpoint->state = UDP_ENDPOINT_DISABLED;
|
|
}
|
|
|
|
/* Terminate transfer on this EP */
|
|
UDP_EndOfTransfer(ep, bStatus);
|
|
}
|
|
epBit <<= 1;
|
|
}
|
|
/* Reset EPs */
|
|
// UDP->UDP_RST_EP |= bmEPs;
|
|
// UDP->UDP_RST_EP &= ~bmEPs;
|
|
}
|
|
|
|
/**
|
|
* Cancel pending READ/WRITE
|
|
* \param bmEPs Bitmap for endpoints to reset.
|
|
* \note EP callback is invoked with USBD_STATUS_CANCELED.
|
|
*/
|
|
void USBD_HAL_CancelIo(uint32_t bmEPs)
|
|
{
|
|
uint32_t tmp = bmEPs & ((1<<CHIP_USB_NUMENDPOINTS)-1);
|
|
uint8_t ep;
|
|
uint32_t epBit;
|
|
for (ep = 0, epBit = 1; ep < CHIP_USB_NUMENDPOINTS; ep ++) {
|
|
if (tmp & epBit) {
|
|
|
|
/* Disable ISR */
|
|
UDP->UDP_IDR = epBit;
|
|
/* Kill pending TXPKTREADY */
|
|
CLEAR_CSR(ep, UDP_CSR_TXPKTRDY);
|
|
|
|
/* Terminate transfer on this EP */
|
|
UDP_EndOfTransfer(ep, USBD_STATUS_CANCELED);
|
|
}
|
|
epBit <<= 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Configures an endpoint according to its endpoint Descriptor.
|
|
* \param pDescriptor Pointer to an endpoint descriptor.
|
|
*/
|
|
uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor)
|
|
{
|
|
Endpoint *pEndpoint;
|
|
uint8_t bEndpoint;
|
|
uint8_t bType;
|
|
uint8_t bEndpointDir;
|
|
|
|
/* NULL descriptor -> Control endpoint 0 in default */
|
|
if (pDescriptor == 0) {
|
|
bEndpoint = 0;
|
|
pEndpoint = &(endpoints[bEndpoint]);
|
|
bType= USBEndpointDescriptor_CONTROL;
|
|
bEndpointDir = 0;
|
|
pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
|
|
}
|
|
/* Device descriptor -> Specific Control EP */
|
|
else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE) {
|
|
bEndpoint = 0;
|
|
pEndpoint = &(endpoints[bEndpoint]);
|
|
bType = USBEndpointDescriptor_CONTROL;
|
|
bEndpointDir = 0;
|
|
pEndpoint->size = ((USBDeviceDescriptor *)pDescriptor)->bMaxPacketSize0;
|
|
}
|
|
/* Not endpoint descriptor, ERROR! */
|
|
else if (pDescriptor->bDescriptorType != USBGenericDescriptor_ENDPOINT) {
|
|
return 0xFF;
|
|
}
|
|
else {
|
|
bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
|
|
pEndpoint = &(endpoints[bEndpoint]);
|
|
bType = USBEndpointDescriptor_GetType(pDescriptor);
|
|
bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
|
|
pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
|
|
}
|
|
|
|
/* Abort the current transfer is the endpoint was configured and in
|
|
Write or Read state */
|
|
if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
|
|
|| (pEndpoint->state == UDP_ENDPOINT_SENDING)
|
|
|| (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
|
|
|| (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) {
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
|
|
}
|
|
pEndpoint->state = UDP_ENDPOINT_IDLE;
|
|
|
|
/* Reset Endpoint Fifos */
|
|
UDP->UDP_RST_EP |= (1 << bEndpoint);
|
|
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
|
|
|
/* Configure endpoint */
|
|
SET_CSR(bEndpoint, (uint32_t)UDP_CSR_EPEDS
|
|
| (bType << 8) | (bEndpointDir << 10));
|
|
if (bType != USBEndpointDescriptor_CONTROL) {
|
|
|
|
}
|
|
else {
|
|
|
|
UDP->UDP_IER = (1 << bEndpoint);
|
|
}
|
|
|
|
TRACE_DEBUG_WP("CfgEp%d ", bEndpoint);
|
|
return bEndpoint;
|
|
}
|
|
|
|
/**
|
|
* Set callback for a USB endpoint for transfer (read/write).
|
|
*
|
|
* \param bEP Endpoint number.
|
|
* \param fCallback Optional callback function to invoke when the transfer is
|
|
* complete.
|
|
* \param pCbData Optional pointer to data to the callback function.
|
|
* \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy.
|
|
*/
|
|
uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP,
|
|
TransferCallback fCallback,
|
|
void *pCbData)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEP]);
|
|
TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer);
|
|
/* Check that the endpoint is not transferring */
|
|
if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
TRACE_DEBUG_WP("sXfrCb ");
|
|
/* Setup the transfer callback and extension data */
|
|
pTransfer->fCallback = (void*)fCallback;
|
|
pTransfer->pArgument = pCbData;
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Configure an endpoint to use multi-buffer-list transfer mode.
|
|
* The buffers can be added by _Read/_Write function.
|
|
* \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL.
|
|
* \param mblSize Multi-buffer list size (number of buffers can be queued)
|
|
* \param startOffset When number of buffer achieve this offset transfer start
|
|
*/
|
|
uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint,
|
|
USBDTransferBuffer* pMbList,
|
|
uint16_t mblSize,
|
|
uint16_t startOffset)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer);
|
|
uint16_t i;
|
|
/* Check that the endpoint is not transferring */
|
|
if (pEndpoint->state > UDP_ENDPOINT_IDLE) {
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
TRACE_DEBUG_WP("sMblXfr ");
|
|
/* Enable Multi-Buffer Transfer List */
|
|
if (pMbList) {
|
|
/* Reset list items */
|
|
for (i = 0; i < mblSize; i --) {
|
|
pMbList[i].pBuffer = NULL;
|
|
pMbList[i].size = 0;
|
|
pMbList[i].transferred = 0;
|
|
pMbList[i].buffered = 0;
|
|
pMbList[i].remaining = 0;
|
|
}
|
|
/* Setup transfer */
|
|
pXfr->transType = 1;
|
|
pXfr->listState = 0; /* OK */
|
|
pXfr->listSize = mblSize;
|
|
pXfr->pMbl = pMbList;
|
|
pXfr->outCurr = pXfr->outLast = 0;
|
|
pXfr->inCurr = 0;
|
|
pXfr->offsetSize = startOffset;
|
|
}
|
|
/* Disable Multi-Buffer Transfer */
|
|
else {
|
|
pXfr->transType = 0;
|
|
pXfr->pMbl = NULL;
|
|
pXfr->listSize = 0;
|
|
pXfr->offsetSize = 1;
|
|
}
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Sends data through a USB endpoint. Sets up the transfer descriptor,
|
|
* writes one or two data payloads (depending on the number of FIFO bank
|
|
* for the endpoint) and then starts the actual transfer. The operation is
|
|
* complete when all the data has been sent.
|
|
*
|
|
* *If the size of the buffer is greater than the size of the endpoint
|
|
* (or twice the size if the endpoint has two FIFO banks), then the buffer
|
|
* must be kept allocated until the transfer is finished*. This means that
|
|
* it is not possible to declare it on the stack (i.e. as a local variable
|
|
* of a function which returns after starting a transfer).
|
|
*
|
|
* \param bEndpoint Endpoint number.
|
|
* \param pData Pointer to a buffer with the data to send.
|
|
* \param dLength Size of the data buffer.
|
|
* \return USBD_STATUS_SUCCESS if the transfer has been started;
|
|
* otherwise, the corresponding error status code.
|
|
*/
|
|
uint8_t USBD_HAL_Write( uint8_t bEndpoint,
|
|
const void *pData,
|
|
uint32_t dLength)
|
|
{
|
|
if (endpoints[bEndpoint].transfer.transHdr.transType)
|
|
return UDP_AddWr(bEndpoint, pData, dLength);
|
|
else
|
|
return UDP_Write(bEndpoint, pData, dLength);
|
|
}
|
|
|
|
/**
|
|
* Reads incoming data on an USB endpoint This methods sets the transfer
|
|
* descriptor and activate the endpoint interrupt. The actual transfer is
|
|
* then carried out by the endpoint interrupt handler. The Read operation
|
|
* finishes either when the buffer is full, or a short packet (inferior to
|
|
* endpoint maximum size) is received.
|
|
*
|
|
* *The buffer must be kept allocated until the transfer is finished*.
|
|
* \param bEndpoint Endpoint number.
|
|
* \param pData Pointer to a data buffer.
|
|
* \param dLength Size of the data buffer in bytes.
|
|
* \return USBD_STATUS_SUCCESS if the read operation has been started;
|
|
* otherwise, the corresponding error code.
|
|
*/
|
|
uint8_t USBD_HAL_Read(uint8_t bEndpoint,
|
|
void *pData,
|
|
uint32_t dLength)
|
|
{
|
|
if (endpoints[bEndpoint].transfer.transHdr.transType)
|
|
return USBD_STATUS_SW_NOT_SUPPORTED;
|
|
else
|
|
return UDP_Read(bEndpoint, pData, dLength);
|
|
}
|
|
|
|
/**
|
|
* \brief Enable Pull-up, connect.
|
|
*
|
|
* -# Enable HW access if needed
|
|
* -# Enable Pull-Up
|
|
* -# Disable HW access if needed
|
|
*/
|
|
void USBD_HAL_Connect(void)
|
|
{
|
|
uint8_t dis = UDP_EnablePeripheralClock();
|
|
UDP->UDP_TXVC |= UDP_TXVC_PUON;
|
|
if (dis) UDP_DisablePeripheralClock();
|
|
}
|
|
|
|
/**
|
|
* \brief Disable Pull-up, disconnect.
|
|
*
|
|
* -# Enable HW access if needed
|
|
* -# Disable PULL-Up
|
|
* -# Disable HW access if needed
|
|
*/
|
|
void USBD_HAL_Disconnect(void)
|
|
{
|
|
uint8_t dis = UDP_EnablePeripheralClock();
|
|
UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON;
|
|
if (dis) UDP_DisablePeripheralClock();
|
|
}
|
|
|
|
/**
|
|
* Starts a remote wake-up procedure.
|
|
*/
|
|
void USBD_HAL_RemoteWakeUp(void)
|
|
{
|
|
UDP_EnablePeripheralClock();
|
|
UDP_EnableUsbClock();
|
|
UDP_EnableTransceiver();
|
|
|
|
TRACE_DEBUG_WP("RWUp ");
|
|
|
|
// Activates a remote wakeup (edge on ESR), then clear ESR
|
|
UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR;
|
|
UDP->UDP_GLB_STAT &= ~(uint32_t)UDP_GLB_STAT_ESR;
|
|
}
|
|
|
|
/**
|
|
* Sets the device address to the given value.
|
|
* \param address New device address.
|
|
*/
|
|
void USBD_HAL_SetAddress(uint8_t address)
|
|
{
|
|
/* Set address */
|
|
UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk);
|
|
/* If the address is 0, the device returns to the Default state */
|
|
if (address == 0) UDP->UDP_GLB_STAT = 0;
|
|
/* If the address is non-zero, the device enters the Address state */
|
|
else UDP->UDP_GLB_STAT = UDP_GLB_STAT_FADDEN;
|
|
}
|
|
|
|
/**
|
|
* Sets the current device configuration.
|
|
* \param cfgnum - Configuration number to set.
|
|
*/
|
|
void USBD_HAL_SetConfiguration(uint8_t cfgnum)
|
|
{
|
|
/* If the configuration number if non-zero, the device enters the
|
|
Configured state */
|
|
if (cfgnum != 0) UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG;
|
|
/* If the configuration number is zero, the device goes back to the Address
|
|
state */
|
|
else {
|
|
UDP->UDP_GLB_STAT = UDP_FADDR_FEN;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializes the USB HW Access driver.
|
|
*/
|
|
void USBD_HAL_Init(void)
|
|
{
|
|
TRACE_DEBUG("%s\n\r", "USBD_HAL_Init");
|
|
|
|
/* Must before USB & TXVC access! */
|
|
UDP_EnablePeripheralClock();
|
|
|
|
/* Reset & disable endpoints */
|
|
USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);
|
|
|
|
/* Configure the pull-up on D+ and disconnect it */
|
|
UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON;
|
|
|
|
UDP_EnableUsbClock();
|
|
|
|
UDP->UDP_IDR = 0xFE;
|
|
UDP->UDP_IER = UDP_IER_WAKEUP;
|
|
}
|
|
|
|
/**
|
|
* Causes the given endpoint to acknowledge the next packet it receives
|
|
* with a STALL handshake except setup request.
|
|
* \param bEP Endpoint number.
|
|
* \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
|
|
*/
|
|
uint8_t USBD_HAL_Stall(uint8_t bEP)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEP]);
|
|
|
|
/* Check that endpoint is in Idle state */
|
|
if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
|
|
TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP);
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
/* STALL endpoint */
|
|
SET_CSR(bEP, UDP_CSR_FORCESTALL);
|
|
TRACE_DEBUG_WP("Stall%d ", bEP);
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Sets/Clear/Get the HALT state on the endpoint.
|
|
* In HALT state, the endpoint should keep stalling any packet.
|
|
* \param bEndpoint Endpoint number.
|
|
* \param ctl Control code CLR/HALT/READ.
|
|
* 0: Clear HALT state;
|
|
* 1: Set HALT state;
|
|
* .: Return HALT status.
|
|
* \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist,
|
|
* otherwise endpoint halt status.
|
|
*/
|
|
uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl)
|
|
{
|
|
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
|
|
uint8_t status = 0;
|
|
|
|
/* SET Halt */
|
|
if (ctl == 1) {
|
|
/* Check that endpoint is enabled and not already in Halt state */
|
|
if ((pEndpoint->state != UDP_ENDPOINT_DISABLED)
|
|
&& (pEndpoint->state != UDP_ENDPOINT_HALTED)) {
|
|
|
|
TRACE_DEBUG_WP("Halt%d ", bEndpoint);
|
|
|
|
/* Abort the current transfer if necessary */
|
|
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
|
|
|
|
/* Put endpoint into Halt state */
|
|
SET_CSR(bEndpoint, UDP_CSR_FORCESTALL);
|
|
pEndpoint->state = UDP_ENDPOINT_HALTED;
|
|
|
|
/* Enable the endpoint interrupt */
|
|
UDP->UDP_IER = 1 << bEndpoint;
|
|
}
|
|
}
|
|
/* CLEAR Halt */
|
|
else if (ctl == 0) {
|
|
/* Check if the endpoint is halted */
|
|
//if (pEndpoint->state != UDP_ENDPOINT_DISABLED) {
|
|
if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
|
|
|
|
TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
|
|
|
|
/* Return endpoint to Idle state */
|
|
pEndpoint->state = UDP_ENDPOINT_IDLE;
|
|
|
|
/* Clear FORCESTALL flag */
|
|
CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL);
|
|
|
|
/* Reset Endpoint Fifos, beware this is a 2 steps operation */
|
|
UDP->UDP_RST_EP |= 1 << bEndpoint;
|
|
UDP->UDP_RST_EP &= ~(1 << bEndpoint);
|
|
}
|
|
}
|
|
|
|
/* Return Halt status */
|
|
if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
|
|
status = 1;
|
|
}
|
|
return( status );
|
|
}
|
|
|
|
/**
|
|
* Indicates if the device is running in high or full-speed. Always returns 0
|
|
* since UDP does not support high-speed mode.
|
|
*/
|
|
uint8_t USBD_HAL_IsHighSpeed(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Suspend USB Device HW Interface
|
|
*
|
|
* -# Disable transceiver
|
|
* -# Disable USB Clock
|
|
* -# Disable USB Peripheral
|
|
*/
|
|
void USBD_HAL_Suspend(void)
|
|
{
|
|
/* The device enters the Suspended state */
|
|
UDP_DisableTransceiver();
|
|
UDP_DisableUsbClock();
|
|
/* Don't disable peripheral clock; this somehow breaks completion of any IN transfers
|
|
* that have already been written to the peripheral, and which we expect to complete
|
|
* after resume */
|
|
//UDP_DisablePeripheralClock();
|
|
}
|
|
|
|
/**
|
|
* Activate USB Device HW Interface
|
|
* -# Enable USB Peripheral
|
|
* -# Enable USB Clock
|
|
* -# Enable transceiver
|
|
*/
|
|
void USBD_HAL_Activate(void)
|
|
{
|
|
UDP_EnablePeripheralClock();
|
|
UDP_EnableUsbClock();
|
|
UDP_EnableTransceiver();
|
|
}
|
|
|
|
/**@}*/
|
|
|