📄 usbd_udp.c
字号:
static void UDP_DisableEndpoints( void )
{
unsigned char bEndpoint;
// Disable each endpoint, terminating any pending transfer
// Control endpoint 0 is not disabled
for (bEndpoint = 1; bEndpoint < BOARD_USB_NUMENDPOINTS; bEndpoint++) {
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED;
}
}
//------------------------------------------------------------------------------
/// 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 unsigned char UDP_IsTransferFinished(unsigned char bEndpoint)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = &(pEndpoint->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[bEndpoint] & AT91C_UDP_EPTYPE)
== AT91C_UDP_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(unsigned char bEndpoint)
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]);
Transfer *pTransfer = &(pEndpoint->transfer);
unsigned int status = AT91C_BASE_UDP->UDP_CSR[bEndpoint];
unsigned short wPacketSize;
USBGenericRequest request;
TRACE_DEBUG_WP("E%d ", bEndpoint);
TRACE_DEBUG_WP("st:0x%X ", status);
// Handle interrupts
// IN packet sent
if ((status & AT91C_UDP_TXCOMP) != 0) {
TRACE_DEBUG_WP("Wr ");
// Check that endpoint was in Sending state
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 & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {
AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
}
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
}
else {
// Transfer remaining data
TRACE_DEBUG_WP(" %d ", pEndpoint->size);
pTransfer->transferred += pEndpoint->size;
pTransfer->buffered -= pEndpoint->size;
// Send next packet
if (BOARD_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
// No double buffering
UDP_WritePayload(bEndpoint);
SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
}
else {
// Double buffering
SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
UDP_WritePayload(bEndpoint);
}
}
}
else {
// Acknowledge interrupt
TRACE_ERROR("Error Wr");
CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
}
}
// OUT packet received
if ((status & UDP_RXDATA) != 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 & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL)
&& ((status & AT91C_UDP_RXBYTECNT) == 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 & AT91C_UDP_FORCESTALL) != 0) {
// Discard STALLed data
TRACE_DEBUG_WP("Discard ");
UDP_ClearRxFlag(bEndpoint);
}
// NAK the data
else {
TRACE_DEBUG_WP("Nak ");
AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
}
}
// Endpoint is in Read state
else {
// Retrieve data and store it into the current transfer buffer
wPacketSize = (unsigned short) (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 & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {
AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
}
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
}
}
}
// STALL sent
if ((status & AT91C_UDP_STALLSENT) != 0) {
TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint);
// If the endpoint is not halted, clear the STALL condition
CLEAR_CSR(bEndpoint, AT91C_UDP_STALLSENT);
if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
TRACE_WARNING( "_ " );
CLEAR_CSR(bEndpoint, AT91C_UDP_FORCESTALL);
}
}
// SETUP packet received
if ((status & AT91C_UDP_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, AT91C_UDP_DIR);
}
// Acknowledge setup packet
CLEAR_CSR(bEndpoint, AT91C_UDP_RXSETUP);
// Forward the request to the upper layer
USBDCallbacks_RequestReceived(&request);
}
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// USB interrupt handler
/// Manages device resume, suspend, end of bus reset.
/// Forwards endpoint interrupts to the appropriate handler.
//------------------------------------------------------------------------------
void USBD_InterruptHandler(void)
{
unsigned int status;
int eptnum = 0;
// Get interrupt status
// Some interrupts may get masked depending on the device state
status = AT91C_BASE_UDP->UDP_ISR;
status &= 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
if (deviceState >= USBD_STATE_POWERED) {
LED_Set(USBD_LEDUSB);
}
// Service interrupts
//// Start Of Frame (SOF)
//if (ISSET(dStatus, AT91C_UDP_SOFINT)) {
//
// 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_INFO_WP("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;
// Invoke the Suspended callback
USBDCallbacks_Suspended();
UDP_DisableTransceiver();
UDP_DisablePeripheralClock();
UDP_DisableUsbClock();
}
}
// Resume
else if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) {
TRACE_INFO_WP("Res ");
// 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();
// Invoke the Resume callback
USBDCallbacks_Resumed();
}
}
// 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_INFO_WP("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 {
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_INFO_WP("\n\r - ");
}
}
eptnum++;
}
}
// Toggle LED back to its previous state
TRACE_INFO_WP("\n\r");
if (deviceState >= USBD_STATE_POWERED) {
LED_Clear(USBD_LEDUSB);
}
}
//------------------------------------------------------------------------------
/// Configures an endpoint according to its Endpoint Descriptor.
/// \param pDescriptor Pointer to an Endpoint descriptor.
//------------------------------------------------------------------------------
void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)
{
Endpoint *pEndpoint;
unsigned char bEndpoint;
unsigned char bType;
unsigned char bEndpointDir;
// NULL descriptor -> Control endpoint 0
if (pDescriptor == 0) {
bEndpoint = 0;
pEndpoint = &(endpoints[bEndpoint]);
bType= USBEndpointDescriptor_CONTROL;
bEndpointDir = 0;
pEndpoint->size = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0);
}
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)) {
UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -