📄 usbd_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.
* ----------------------------------------------------------------------------
*/
/*
Title: USBD implementation for a UDP controller
About: Purpose
Implementation of USB device functions on a UDP controller.
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "USBD.h"
#include "USBDCallbacks.h"
#include <board.h>
#include <pio/pio.h>
#include <utility/trace.h>
#include <utility/led.h>
#include <usb/common/core/USBEndpointDescriptor.h>
#include <usb/common/core/USBGenericRequest.h>
#if defined(BOARD_USB_UDP)
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
/*
Constants: UDP register field values
UDP_RXDATA - Bit mask for both banks of the UDP_CSR register.
*/
#define UDP_RXDATA (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)
/*
Constants: Endpoint states
UDP_ENDPOINT_DISABLED - Endpoint is disabled.
UDP_ENDPOINT_HALTED - Endpoint is halted (i.e. STALLs every request).
UDP_ENDPOINT_IDLE - Endpoint is idle (i.e. ready for transmission).
UDP_ENDPOINT_SENDING - Endpoint is sending data.
UDP_ENDPOINT_RECEIVING - Endpoint is receiving data.
*/
#define UDP_ENDPOINT_DISABLED 0
#define UDP_ENDPOINT_HALTED 1
#define UDP_ENDPOINT_IDLE 2
#define UDP_ENDPOINT_SENDING 3
#define UDP_ENDPOINT_RECEIVING 4
/*
Macros: UDP_CSR register access
CLEAR_CSR - Clears the specified bit(s) in the UDP_CSR register.
SET_CSR - Sets the specified bit(s) in the UDP_CSR register.
*/
//#define UDP_CLEAREPFLAGS(pUsb, bEndpoint, dFlags) {
// CLEAR(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags);
// while (!ISCLEARED(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags));
//}
#define CLEAR_CSR(endpoint, bits) AT91C_BASE_UDP->UDP_CSR[endpoint] &= ~bits;
//#define UDP_SETEPFLAGS(pUsb, bEndpoint, dFlags) {
// while (ISCLEARED(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags))
// SET(UDP_GetDriverInterface(pUsb)->UDP_CSR[bEndpoint], dFlags);
//}
#define SET_CSR(endpoint, bits) AT91C_BASE_UDP->UDP_CSR[endpoint] |= bits;
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
/*
Type: UDP transfer
Describes an ongoing transfer on a UDP endpoint.
Variables:
data - Pointer to a data buffer used for emission/reception.
buffered - Number of bytes which have been written into the UDP internal
FIFO buffers.
transferred - Number of bytes which have been sent/received.
remaining - Number of bytes which have not been buffered/transferred yet.
callback - Optional callback to invoke when the transfer completes.
argument - Optional argument to the callback function.
*/
typedef struct {
char *data;
int buffered;
int transferred;
int remaining;
TransferCallback callback;
void *argument;
} Transfer;
/*
Type: UDP endpoint
Describes the state of an endpoint of the UDP controller.
Variables:
state - Current endpoint state.
bank - Current reception bank (0 or 1).
size - Maximum packet size for the endpoint.
transfer - Describes an ongoing transfer (if current state is either
<UDP_ENDPOINT_SENDING> or <UDP_ENDPOINT_RECEIVING>).
*/
typedef struct {
unsigned char state;
unsigned char bank;
unsigned short size;
Transfer transfer;
} Endpoint;
//------------------------------------------------------------------------------
// Internal variables
//------------------------------------------------------------------------------
/*
Variables:
endpoints - Holds the internal state for each endpoint of the UDP.
deviceState - Device current state.
suspended - Indicates if device is currently suspended.
*/
static Endpoint endpoints[BOARD_USB_NUMENDPOINTS];
static unsigned char deviceState;
static unsigned char previousDeviceState;
//------------------------------------------------------------------------------
// Internal Functions
//------------------------------------------------------------------------------
/*
Functions: Peripheral clock
EnablePeripheralClock - Enables the clock of the UDP peripheral.
DisablePeripheralClock - Disables the UDP peripheral clock.
*/
static inline void UDP_EnablePeripheralClock()
{
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_UDP;
}
static inline void UDP_DisablePeripheralClock()
{
AT91C_BASE_PMC->PMC_PCDR = 1 << AT91C_ID_UDP;
}
/*
Functions: USB clock
EnableUsbClock - Enables the 48MHz USB clock.
DisableUsbClock - Disables the 48MHz USB clock.
*/
static inline void UDP_EnableUsbClock()
{
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
}
static inline void UDP_DisableUsbClock()
{
AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_UDP;
}
/*
Functions: Transceiver
UDP_EnableTransceiver - Enables the UDP transceiver.
UDP_DisableTransceiver - Disables the UDP transceiver.
*/
static inline void UDP_EnableTransceiver()
{
AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_TXVDIS;
}
static inline void UDP_DisableTransceiver()
{
AT91C_BASE_UDP->UDP_TXVC |= AT91C_UDP_TXVDIS;
}
/*
Function: UDP_EndOfTransfer
Handles a completed transfer on the given endpoint, invoking the
configured callback if any.
Parameters:
eptnum - Number of the endpoint for which the transfer has completed.
status - Result of the USB transfer.
*/
static void UDP_EndOfTransfer(unsigned char eptnum, char status)
{
Endpoint *endpoint = &(endpoints[eptnum]);
Transfer *transfer = &(endpoint->transfer);
// Check that endpoint was sending or receiving data
if ((endpoint->state == UDP_ENDPOINT_RECEIVING)
|| (endpoint->state == UDP_ENDPOINT_SENDING)) {
trace_LOG(trace_INFO, "EoT ");
// Endpoint returns in Idle state
endpoint->state = UDP_ENDPOINT_IDLE;
// Invoke callback is present
if (transfer->callback != 0) {
((TransferCallback) transfer->callback)
(transfer->argument,
status,
transfer->transferred,
transfer->remaining + transfer->buffered);
}
}
}
/*
Function: UDP_ClearRxFlag
Clears the correct reception flag (bank 0 or bank 1) of an endpoint.
Parameters:
eptnum - Number of an endpoint.
*/
static void UDP_ClearRxFlag(unsigned char eptnum)
{
Endpoint *endpoint = &(endpoints[eptnum]);
// Clear flag and change banks
if (endpoint->bank == 0) {
CLEAR_CSR(eptnum, AT91C_UDP_RX_DATA_BK0);
// Swap bank if in dual-fifo mode
if (BOARD_USB_ENDPOINTS_BANKS(eptnum) > 1) {
endpoint->bank = 1;
}
}
else {
CLEAR_CSR(eptnum, AT91C_UDP_RX_DATA_BK1);
endpoint->bank = 0;
}
}
/*
Function: UDP_WritePayload
Writes a data payload into the current FIFO buffer of the UDP.
Parameters:
eptnum - Number of the endpoint which is sending data.
*/
static void UDP_WritePayload(unsigned char eptnum)
{
Endpoint *endpoint = &(endpoints[eptnum]);
Transfer *transfer = &(endpoint->transfer);
signed int size;
// Get the number of bytes to send
size = endpoint->size;
if (size > transfer->remaining) {
size = transfer->remaining;
}
// Update transfer descriptor information
transfer->buffered += size;
transfer->remaining -= size;
// Write packet in the FIFO buffer
while (size > 0) {
AT91C_BASE_UDP->UDP_FDR[eptnum] = *(transfer->data);
transfer->data++;
size--;
}
}
/*
Function: UDP_ReadPayload
Reads a data payload from the current FIFO buffer of an endpoint.
Parameters:
eptnum - Endpoint number.
size - Size of the data to read.
*/
static void UDP_ReadPayload(unsigned char eptnum, int size)
{
Endpoint *endpoint = &(endpoints[eptnum]);
Transfer *transfer = &(endpoint->transfer);
// Check that the requested size is not bigger than the remaining transfer
if (size > transfer->remaining) {
transfer->buffered += size - transfer->remaining;
size = transfer->remaining;
}
// Update transfer descriptor information
transfer->remaining -= size;
transfer->transferred += size;
// Retrieve packet
while (size > 0) {
*(transfer->data) = (char) AT91C_BASE_UDP->UDP_FDR[eptnum];
transfer->data++;
size--;
}
}
/*
Function: UDP_ReadRequest
Reads a SETUP request from the FIFO buffer of Control endpoint 0 and
stores it into the global <request> variable.
*/
static void UDP_ReadRequest(USBGenericRequest *request)
{
unsigned char *data = (unsigned char *) request;
unsigned int i;
// Copy packet
for (i = 0; i < 8; i++) {
*data = (unsigned char) AT91C_BASE_UDP->UDP_FDR[0];
data++;
}
}
/*
Function: UDP_ResetEndpoints
Resets all the endpoints of the UDP peripheral.
*/
static void UDP_ResetEndpoints()
{
Endpoint *endpoint;
Transfer *transfer;
unsigned char eptnum;
// Reset the transfer descriptor of every endpoint
for (eptnum = 0; eptnum < BOARD_USB_NUMENDPOINTS; eptnum++) {
endpoint = &(endpoints[eptnum]);
transfer = &(endpoint->transfer);
// Reset endpoint transfer descriptor
transfer->data = 0;
transfer->transferred = -1;
transfer->buffered = -1;
transfer->remaining = -1;
transfer->callback = 0;
transfer->argument = 0;
// Reset endpoint state
endpoint->bank = 0;
endpoint->state = UDP_ENDPOINT_DISABLED;
}
}
/*
Function: UDP_DisableEndpoints
Disables all endpoints of the UDP peripheral except Control endpoint 0.
*/
static void UDP_DisableEndpoints()
{
unsigned char eptnum;
// Disable each endpoint, terminating any pending transfer
for (eptnum = 1; eptnum < BOARD_USB_NUMENDPOINTS; eptnum++) {
UDP_EndOfTransfer(eptnum, USBD_STATUS_ABORTED);
endpoints[eptnum].state = UDP_ENDPOINT_DISABLED;
}
}
/*
Function: UDP_IsTransferFinished
Checks if an ongoing transfer on an endpoint has been completed.
Parameters:
eptnum - Endpoint number.
Returns:
1 if the current transfer on the given endpoint is complete; otherwise
0.
*/
static unsigned char UDP_IsTransferFinished(unsigned char eptnum)
{
Endpoint *endpoint = &(endpoints[eptnum]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -