📄 udp.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support - ROUSSET -
* ----------------------------------------------------------------------------
* Copyright (c) 2006, 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 disclaiimer below.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* 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.
* ----------------------------------------------------------------------------
*/
/*
$Id: udp.c 196 2006-10-30 09:56:17Z jjoannic $
*/
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include "common.h"
#include "device.h"
#include "board.h"
#include "trace.h"
#include "usb.h"
#ifdef UDP
#define UDP_STATE_SHOULD_RECONNECT 0x10000000
#define UDP_EPTYPE_INDEX 8
#define UDP_EPDIR_INDEX 10
#define ISR_MASK 0x00003FFF
//------------------------------------------------------------------------------
// Structures
//------------------------------------------------------------------------------
// \brief Endpoint states
typedef enum {
endpointStateDisabled,
endpointStateIdle,
endpointStateWrite,
endpointStateRead,
endpointStateHalted
} EndpointState_t;
//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------
// \brief Clear flags in the UDP_CSR register and waits for synchronization
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param dFlags Flags to clear
#define UDP_CLEAREPFLAGS(pUsb, bEndpoint, dFlags) { \
while (!ISCLEARED(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags)) \
CLEAR(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags); \
}
// \brief Set flags in the UDP_CSR register and waits for synchronization
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param dFlags Flags to clear
#define UDP_SETEPFLAGS(pUsb, bEndpoint, dFlags) { \
while (ISCLEARED(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags)) \
SET(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags); \
}
//------------------------------------------------------------------------------
// Internal Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// \brief Returns a pointer to the UDP controller interface used by an USB
// driver
//
// The pointer is cast to the correct type (AT91PS_UDP).
// \param pUsb Pointer to a S_usb instance
// \return Pointer to the USB controller interface
// \see S_usb
//------------------------------------------------------------------------------
extern __inline AT91PS_UDP UDP_GetDriverInterface(const S_usb *pUsb)
{
return (AT91PS_UDP) pUsb->pDriver->pInterface;
}
//------------------------------------------------------------------------------
// \brief Enables the peripheral clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
extern __inline void UDP_EnableMCK(const S_usb *pUsb)
{
AT91C_BASE_PMC->PMC_PCER = 1 << USB_GetDriverID(pUsb);
}
//------------------------------------------------------------------------------
// \brief Disables the peripheral clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
extern __inline void UDP_DisableMCK(const S_usb *pUsb)
{
AT91C_BASE_PMC->PMC_PCDR = 1 << USB_GetDriverID(pUsb);
}
//------------------------------------------------------------------------------
// \brief Enables the 48MHz clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
extern __inline void UDP_EnableUDPCK(const S_usb *pUsb)
{
SET(AT91C_BASE_PMC->PMC_SCER, USB_GetDriverPMC(pUsb));
}
//------------------------------------------------------------------------------
// \brief Disables the 48MHz clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
extern __inline void UDP_DisableUDPCK(const S_usb *pUsb)
{
SET(AT91C_BASE_PMC->PMC_SCDR, USB_GetDriverPMC(pUsb));
}
//------------------------------------------------------------------------------
// \brief Enables the transceiver of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
extern __inline void UDP_EnableTransceiver(const S_usb *pUsb)
{
CLEAR(UDP_GetDriverInterface(pUsb)->UDP_TXVC, AT91C_UDP_TXVDIS);
}
//------------------------------------------------------------------------------
// \brief Disables the transceiver of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
extern __inline void UDP_DisableTransceiver(const S_usb *pUsb)
{
SET(UDP_GetDriverInterface(pUsb)->UDP_TXVC, AT91C_UDP_TXVDIS);
}
//------------------------------------------------------------------------------
// \brief Invokes the callback associated with a finished transfer on an
// endpoint
// \param pEndpoint Pointer to a S_usb_endpoint instance
// \param bStatus Status code returned by the transfer operation
// \see Status codes
// \see S_usb_endpoint
//------------------------------------------------------------------------------
extern __inline void UDP_EndOfTransfer(S_usb_endpoint *pEndpoint,
char bStatus)
{
if ((pEndpoint->dState == endpointStateWrite)
|| (pEndpoint->dState == endpointStateRead)) {
TRACE_DEBUG_L("EoT ");
// Endpoint returns in Idle state
pEndpoint->dState = endpointStateIdle;
// Invoke callback is present
if (pEndpoint->fCallback != 0) {
pEndpoint->fCallback((unsigned int) pEndpoint->pArgument,
(unsigned int) bStatus,
pEndpoint->dBytesTransferred,
pEndpoint->dBytesRemaining
+ pEndpoint->dBytesBuffered);
}
}
}
//------------------------------------------------------------------------------
// \brief Clears the correct RX flag in an endpoint status register
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \see S_usb_endpoint
// \see S_usb
//------------------------------------------------------------------------------
static void UDP_ClearRXFlag(const S_usb * pUsb,
unsigned char bEndpoint)
{
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
// Clear flag
UDP_CLEAREPFLAGS(pUsb, bEndpoint, pEndpoint->dFlag);
// Swap banks
if (pEndpoint->dFlag == AT91C_UDP_RX_DATA_BK0) {
if (pEndpoint->dNumFIFO > 1) {
// Swap bank if in dual-fifo mode
pEndpoint->dFlag = AT91C_UDP_RX_DATA_BK1;
}
}
else {
pEndpoint->dFlag = AT91C_UDP_RX_DATA_BK0;
}
}
//------------------------------------------------------------------------------
// \brief Transfers a data payload from the current tranfer buffer to the
// endpoint FIFO.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \return Number of bytes transferred
// \see S_usb
//------------------------------------------------------------------------------
static unsigned int UDP_WritePayload(const S_usb * pUsb,
unsigned char bEndpoint)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
unsigned int dBytes;
unsigned int dCtr;
// Get the number of bytes to send
dBytes = min(pEndpoint->wMaxPacketSize, pEndpoint->dBytesRemaining);
// Transfer one packet in the FIFO buffer
for (dCtr = 0; dCtr < dBytes; dCtr++) {
pInterface->UDP_FDR[bEndpoint] = *(pEndpoint->pData);
pEndpoint->pData++;
}
pEndpoint->dBytesBuffered += dBytes;
pEndpoint->dBytesRemaining -= dBytes;
return dBytes;
}
//------------------------------------------------------------------------------
// \brief Transfers a data payload from an endpoint FIFO to the current
// transfer buffer.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param wPacketSize Size of received data packet
// \return Number of bytes transferred
// \see S_usb
//------------------------------------------------------------------------------
static unsigned int UDP_GetPayload(const S_usb * pUsb,
unsigned char bEndpoint,
unsigned short wPacketSize)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
unsigned int dBytes;
unsigned int dCtr;
// Get number of bytes to retrieve
dBytes = min(pEndpoint->dBytesRemaining, wPacketSize);
// Retrieve packet
for (dCtr = 0; dCtr < dBytes; dCtr++) {
*pEndpoint->pData = (char) pInterface->UDP_FDR[bEndpoint];
pEndpoint->pData++;
}
pEndpoint->dBytesRemaining -= dBytes;
pEndpoint->dBytesTransferred += dBytes;
pEndpoint->dBytesBuffered += wPacketSize - dBytes;
return dBytes;
}
//------------------------------------------------------------------------------
// \brief Transfers a received SETUP packet from endpoint 0 FIFO to the
// S_usb_request structure of an USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void UDP_GetSetup(S_usb const *pUsb)
{
char *pData = (char *) USB_GetSetup(pUsb);
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
unsigned int dCtr;
// Copy packet
for (dCtr = 0; dCtr < 8; dCtr++) {
*pData = (char) pInterface->UDP_FDR[0];
pData++;
}
}
//------------------------------------------------------------------------------
// \brief This function reset all endpoint transfer descriptors
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void UDP_ResetEndpoints(const S_usb *pUsb)
{
S_usb_endpoint *pEndpoint;
unsigned char bEndpoint;
// Reset the transfer descriptor of every endpoint
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -