📄 usbd_udp.c
字号:
Transfer *transfer = &(endpoint->transfer);
// Check if it is a Control endpoint
// -> Control endpoint must always finish their transfer with a zero-length
// packet
if ((AT91C_BASE_UDP->UDP_CSR[eptnum] & AT91C_UDP_EPTYPE)
== AT91C_UDP_EPTYPE_CTRL) {
return (transfer->buffered < endpoint->size);
}
// Other endpoints only need to transfer all the data
else {
return (transfer->buffered <= endpoint->size)
&& (transfer->remaining == 0);
}
}
/*
Function: UDP_EndpointHandler
Endpoint interrupt handler. Manages IN, OUT & SETUP transaction, as well
as the STALL condition.
Parameters:
eptnum - Number of the endpoint to handle interrupt for.
*/
static void UDP_EndpointHandler(unsigned char eptnum)
{
Endpoint *endpoint = &(endpoints[eptnum]);
Transfer *transfer = &(endpoint->transfer);
unsigned int status = AT91C_BASE_UDP->UDP_CSR[eptnum];
trace_LOG(trace_INFO, "Ept%d ", eptnum);
// Handle interrupts
// IN packet sent
if ((status & AT91C_UDP_TXCOMP) != 0) {
trace_LOG(trace_INFO, "Wr ");
// Check that endpoint was in Sending state
if (endpoint->state == UDP_ENDPOINT_SENDING) {
// End of transfer ?
if (UDP_IsTransferFinished(eptnum)) {
trace_LOG(trace_INFO, "%d ", transfer->buffered);
transfer->transferred += transfer->buffered;
transfer->buffered = 0;
// Disable interrupt if this is not a control endpoint
if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {
AT91C_BASE_UDP->UDP_IDR |= 1 << eptnum;
}
UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
}
else {
// Transfer remaining data
trace_LOG(trace_INFO, "%d ", endpoint->size);
transfer->transferred += endpoint->size;
transfer->buffered -= endpoint->size;
// Send next packet
if (BOARD_USB_ENDPOINTS_BANKS(eptnum) == 1) {
// No double buffering
UDP_WritePayload(eptnum);
SET_CSR(eptnum, AT91C_UDP_TXPKTRDY);
}
else {
// Double buffering
SET_CSR(eptnum, AT91C_UDP_TXPKTRDY);
UDP_WritePayload(eptnum);
}
}
}
// Acknowledge interrupt
CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP);
}
// OUT packet received
if ((status & UDP_RXDATA) != 0) {
trace_LOG(trace_INFO, "Rd ");
// Check that the endpoint is in Receiving state
if (endpoint->state != UDP_ENDPOINT_RECEIVING) {
// Check if an ACK has been received on a Control endpoint
if (((status & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL)
&& ((status & AT91C_UDP_RXBYTECNT) == 0)) {
// Acknowledge the data and finish the current transfer
trace_LOG(trace_INFO, "Ack ");
UDP_ClearRxFlag(eptnum);
UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
}
// Check if the data has been STALLed
else if ((status & AT91C_UDP_FORCESTALL) != 0) {
// Discard STALLed data
trace_LOG(trace_INFO, "Disc ");
UDP_ClearRxFlag(eptnum);
}
// NAK the data
else {
trace_LOG(trace_INFO, "Nak ");
AT91C_BASE_UDP->UDP_IDR |= 1 << eptnum;
}
}
// Endpoint is in Read state
else {
// Retrieve data and store it into the current transfer buffer
unsigned short size = (unsigned short) (status >> 16);
trace_LOG(trace_INFO, "%d ", size);
UDP_ReadPayload(eptnum, size);
UDP_ClearRxFlag(eptnum);
// Check if the transfer is finished
if ((transfer->remaining == 0) || (size < endpoint->size)) {
// Disable interrupt if this is not a control endpoint
if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {
AT91C_BASE_UDP->UDP_IDR |= 1 << eptnum;
}
UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
}
}
}
// SETUP packet received
if ((status & AT91C_UDP_RXSETUP) != 0) {
trace_LOG(trace_INFO, "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 ((endpoint->state == UDP_ENDPOINT_RECEIVING)
|| (endpoint->state == UDP_ENDPOINT_SENDING)) {
UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
}
USBGenericRequest request;
UDP_ReadRequest(&request);
// Set the DIR bit before clearing RXSETUP in Control IN sequence
if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) {
SET_CSR(eptnum, AT91C_UDP_DIR);
}
CLEAR_CSR(eptnum, AT91C_UDP_RXSETUP);
// Forward the request to the upper layer
USBDCallbacks_RequestReceived(&request);
}
// STALL sent
if ((status & AT91C_UDP_STALLSENT) != 0) {
trace_LOG(trace_INFO, "Sta ");
// If the endpoint is not halted, clear the STALL condition
CLEAR_CSR(eptnum, AT91C_UDP_STALLSENT);
if (endpoint->state != UDP_ENDPOINT_HALTED) {
CLEAR_CSR(eptnum, AT91C_UDP_FORCESTALL);
}
}
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
/*
Function: USBD_ConfigureEndpoint
Configures an endpoint according to its Endpoint Descriptor.
Parameters:
descriptor - Pointer to an Endpoint descriptor.
*/
void USBD_ConfigureEndpoint(const USBEndpointDescriptor *descriptor)
{
Endpoint *endpoint;
unsigned char eptnum;
unsigned char type;
unsigned char direction;
// NULL descriptor -> Control endpoint 0
if (descriptor == 0) {
eptnum = 0;
endpoint = &(endpoints[eptnum]);
type = USBEndpointDescriptor_CONTROL;
direction = 0;
endpoint->size = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0);
}
else {
eptnum = USBEndpointDescriptor_GetNumber(descriptor);
endpoint = &(endpoints[eptnum]);
type = USBEndpointDescriptor_GetType(descriptor);
direction = USBEndpointDescriptor_GetDirection(descriptor);
endpoint->size = USBEndpointDescriptor_GetMaxPacketSize(descriptor);
}
// Abort the current transfer is the endpoint was configured and in
// Write or Read state
if ((endpoint->state == UDP_ENDPOINT_RECEIVING)
|| (endpoint->state == UDP_ENDPOINT_SENDING)) {
UDP_EndOfTransfer(eptnum, USBD_STATUS_RESET);
}
endpoint->state = UDP_ENDPOINT_IDLE;
// Reset Endpoint Fifos
AT91C_BASE_UDP->UDP_RSTEP |= (1 << eptnum);
AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << eptnum);
// Configure endpoint
SET_CSR(eptnum, AT91C_UDP_EPEDS | (type << 8) | (direction << 10));
if (type == USBEndpointDescriptor_CONTROL) {
AT91C_BASE_UDP->UDP_IER |= (1 << eptnum);
}
trace_LOG(trace_INFO, "CfgEpt%d ", eptnum);
}
/*
Function: USBD_InterruptHandler
UDP interrupt handler. Manages device status changes.
*/
void USBD_InterruptHandler()
{
// Get interrupt status
// Some interrupts may get masked depending on the device state
unsigned int status = AT91C_BASE_UDP->UDP_ISR & AT91C_BASE_UDP->UDP_IMR;
if (deviceState < USBD_STATE_POWERED) {
status &= AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
AT91C_BASE_UDP->UDP_ICR = ~status;
}
// Return immediately if there is no interrupt to service
if (status == 0) {
return;
}
// Toggle USB LED if the device is active
trace_LOG(trace_INFO, "Hlr ");
if (deviceState >= USBD_STATE_POWERED) {
LED_Set(USBD_LEDUSB);
}
// Service interrupts
//// Start Of Frame (SOF)
//if (ISSET(dStatus, AT91C_UDP_SOFINT)) {
//
// trace_LOG(trace_DEBUG, "SOF");
//
// // Invoke the SOF callback
// USB_StartOfFrameCallback(pUsb);
//
// // Acknowledge interrupt
// AT91C_BASE_UDP->UDP_ICR |= AT91C_UDP_SOFINT;
// dStatus &= ~AT91C_UDP_SOFINT;
//}
// Suspend
// This interrupt is always treated last (hence the '==')
if (status == AT91C_UDP_RXSUSP) {
trace_LOG(trace_INFO, "Susp ");
// Don't do anything if the device is already suspended
if (deviceState != USBD_STATE_SUSPENDED) {
// The device enters the Suspended state
// Enable wakeup
AT91C_BASE_UDP->UDP_IER |= AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
// Acknowledge interrupt
AT91C_BASE_UDP->UDP_ICR |= AT91C_UDP_RXSUSP;
// Switch to the Suspended state
previousDeviceState = deviceState;
deviceState = USBD_STATE_SUSPENDED;
UDP_DisableTransceiver();
UDP_DisablePeripheralClock();
UDP_DisableUsbClock();
// Invoke the Suspended callback
USBDCallbacks_Suspended();
}
}
// Resume
else if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) {
trace_LOG(trace_INFO, "Res ");
// Invoke the Resume callback
USBDCallbacks_Resumed();
// Don't do anything if the device was not suspended
if (deviceState == USBD_STATE_SUSPENDED) {
// The device enters its previous state
UDP_EnablePeripheralClock();
UDP_EnableUsbClock();
// Enable the transceiver if the device was past the Default
// state
deviceState = previousDeviceState;
if (deviceState >= USBD_STATE_DEFAULT) {
UDP_EnableTransceiver();
}
}
// Clear and disable resume interrupts
AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP
| AT91C_UDP_RXRSM
| AT91C_UDP_RXSUSP;
AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
}
// End of bus reset
else if ((status & AT91C_UDP_ENDBUSRES) != 0) {
trace_LOG(trace_INFO, "EoBRes ");
// The device enters the Default state
deviceState = USBD_STATE_DEFAULT;
UDP_EnableTransceiver();
UDP_ResetEndpoints();
UDP_DisableEndpoints();
USBD_ConfigureEndpoint(0);
// Flush and enable the Suspend interrupt
AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP
| AT91C_UDP_RXRSM
| AT91C_UDP_RXSUSP;
AT91C_BASE_UDP->UDP_IER = AT91C_UDP_RXSUSP;
//// Enable the Start Of Frame (SOF) interrupt if needed
//if (pUsb->pCallbacks->startOfFrame != 0) {
//
// AT91C_BASE_UDP->UDP_IER |= AT91C_UDP_SOFINT;
//}
// Invoke the Reset callback
USBDCallbacks_Reset();
// Acknowledge end of bus reset interrupt
AT91C_BASE_UDP->UDP_ICR |= AT91C_UDP_ENDBUSRES;
}
// Endpoint interrupts
else {
int eptnum = 0;
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_LOG(trace_INFO, "\n\r - ");
}
}
eptnum++;
}
}
// Toggle LED back to its previous state
trace_LOG(trace_INFO, "\n\r");
if (deviceState >= USBD_STATE_POWERED) {
LED_Clear(USBD_LEDUSB);
}
}
/*
Function: USBD_Write
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).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -