📄 udp.c
字号:
if (pEndpoint->dState != endpointStateRead&&pEndpoint->dState!=endpointStateIdle)
{
// Endpoint is NOT in Read state
if (ISCLEARED(dStatus, AT91C_UDP_EPTYPE)
&& ISCLEARED(dStatus, 0xFFFF0000)) {
// Control endpoint, 0 bytes received
// Acknowledge the data and finish the current transfer
UDP_ClearRXFlag(pUsb, bEndpoint);
UDP_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
}
else if (ISSET(dStatus, AT91C_UDP_FORCESTALL)) {
// Non-control endpoint
// Discard stalled data
UDP_ClearRXFlag(pUsb, bEndpoint);
}
else {
// Non-control endpoint
// Nak data
SET(pInterface->UDP_IDR, 1 << bEndpoint);
}
}
else {
// Endpoint is in Read state
// Retrieve data and store it into the current transfer buffer
unsigned short wPacketSize = (unsigned short) (dStatus >> 16);
UDP_GetPayload(pUsb, bEndpoint, wPacketSize);
UDP_ClearRXFlag(pUsb, bEndpoint);
if ((pEndpoint->dBytesRemaining == 0)
|| (wPacketSize < pEndpoint->wMaxPacketSize)) {
// Disable interrupt if this is not a control endpoint
if (!ISCLEARED(dStatus, AT91C_UDP_EPTYPE)) {
SET(pInterface->UDP_IDR, 1 << bEndpoint);
}
UDP_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
}
}
}
// SETUP packet received
if (ISSET(dStatus, AT91C_UDP_RXSETUP)) {
// If a transfer was pending, complete it
// Handle 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->dState == endpointStateWrite)
|| (pEndpoint->dState == endpointStateRead)) {
UDP_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
}
// Copy the setup packet in S_usb
UDP_GetSetup(pUsb);
// Set the DIR bit before clearing RXSETUP in Control IN sequence
if (USB_GetSetup(pUsb)->bmRequestType & 0x80) {
UDP_SETEPFLAGS(pUsb, bEndpoint, AT91C_UDP_DIR);
}
UDP_CLEAREPFLAGS(pUsb, bEndpoint, AT91C_UDP_RXSETUP);
// Forward the request to the upper layer
USB_NewRequestCallback(pUsb);
}
// STALL sent
if (ISSET(dStatus, AT91C_UDP_STALLSENT)) {
// Acknowledge the stall flag
UDP_CLEAREPFLAGS(pUsb, bEndpoint, AT91C_UDP_STALLSENT);
// If the endpoint is not halted, clear the stall condition
if (pEndpoint->dState != endpointStateHalted) {
UDP_CLEAREPFLAGS(pUsb, bEndpoint, AT91C_UDP_FORCESTALL);
}
}
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// \brief Configure an endpoint with the provided endpoint descriptor
// \param pUsb Pointer to a S_usb instance
// \param pEpDesc Pointer to the endpoint descriptor
// \return true if the endpoint is now configured, false otherwise
// \see S_usb_endpoint_descriptor
// \see S_usb
//------------------------------------------------------------------------------
bool UDP_ConfigureEndpoint(const S_usb *pUsb,
const S_usb_endpoint_descriptor *pEpDesc)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
S_usb_endpoint *pEndpoint;
unsigned char bEndpoint;
unsigned char bType;
bool isINEndpoint;
unsigned int dFlags;
// NULL descriptor -> Control endpoint 0
if (pEpDesc == 0) {
bEndpoint = 0;
bType = ENDPOINT_TYPE_CONTROL;
isINEndpoint = false;
}
else {
bEndpoint = (unsigned char) (pEpDesc->bEndpointAddress & 0x7);
bType = (unsigned char) (pEpDesc->bmAttributes & 0x3);
if (ISSET(pEpDesc->bEndpointAddress, 1 << 7)) {
isINEndpoint = true;
}
else {
isINEndpoint = false;
}
}
// Get pointer on endpoint
pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
if (pEndpoint == 0) {
return false;
}
// Configure wMaxPacketSize
if (pEpDesc != 0) {
pEndpoint->wMaxPacketSize = pEpDesc->wMaxPacketSize;
}
else {
pEndpoint->wMaxPacketSize = USB_ENDPOINT0_MAXPACKETSIZE;
}
// Abort the current transfer is the endpoint was configured and in
// Write or Read state
if ((pEndpoint->dState == endpointStateRead)
|| (pEndpoint->dState == endpointStateWrite)) {
UDP_EndOfTransfer(pEndpoint, USB_STATUS_RESET);
}
// Enter IDLE state
pEndpoint->dState = endpointStateIdle;
// Reset Endpoint Fifos
SET(pInterface->UDP_RSTEP, 1 << bEndpoint);
CLEAR(pInterface->UDP_RSTEP, 1 << bEndpoint);
// Configure endpoint
dFlags = AT91C_UDP_EPEDS;
SET(dFlags, bType << UDP_EPTYPE_INDEX);
if (isINEndpoint) {
SET(dFlags, 1 << UDP_EPDIR_INDEX);
}
if (bType == ENDPOINT_TYPE_CONTROL)
{
SET(pInterface->UDP_IER, 1 << bEndpoint);
}
UDP_SETEPFLAGS(pUsb, bEndpoint, dFlags);
return true;
}
//------------------------------------------------------------------------------
// \brief UDP interrupt handler
//
// Manages device resume, suspend, end of bus reset. Forwards endpoint
// interrupts to the appropriate handler.
// \param pUsb Pointer to a S_usb instance
//------------------------------------------------------------------------------
void UDP_Handler(const S_usb *pUsb)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
unsigned int dStatus;
unsigned char bEndpoint;
// Get interrupts status
dStatus = pInterface->UDP_ISR & pInterface->UDP_IMR & ISR_MASK;
// Handle all UDP interrupts
while (dStatus != 0) {
// Start Of Frame (SOF)
if (ISSET(dStatus, AT91C_UDP_SOFINT)) {
// Acknowledge interrupt
SET(pInterface->UDP_ICR, AT91C_UDP_SOFINT);
CLEAR(dStatus, AT91C_UDP_SOFINT);
}
// Suspend
if (dStatus == AT91C_UDP_RXSUSP) {
if (!ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED)) {
// The device enters the Suspended state
// MCK + UDPCK must be off
// Pull-Up must be connected
// Transceiver must be disabled
// Enable wakeup
SET(pInterface->UDP_IER, AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM);
// Acknowledge interrupt
SET(pInterface->UDP_ICR, AT91C_UDP_RXSUSP);
SET(*(pUsb->pState), USB_STATE_SUSPENDED);
UDP_DisableTransceiver(pUsb);
UDP_DisableMCK(pUsb);
UDP_DisableUDPCK(pUsb);
// Invoke the Suspend callback
USB_SuspendCallback(pUsb);
}
}
// Resume
else if (ISSET(dStatus, AT91C_UDP_WAKEUP)
|| ISSET(dStatus, AT91C_UDP_RXRSM)) {
// Invoke the Resume callback
USB_ResumeCallback(pUsb);
// The device enters Configured state
// MCK + UDPCK must be on
// Pull-Up must be connected
// Transceiver must be enabled
if (ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED)) {
// Powered state
UDP_EnableMCK(pUsb);
UDP_EnableUDPCK(pUsb);
// Default state
if (ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
UDP_EnableTransceiver(pUsb);
}
CLEAR(*(pUsb->pState), USB_STATE_SUSPENDED);
}
SET(pInterface->UDP_ICR,
AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM | AT91C_UDP_RXSUSP);
SET(pInterface->UDP_IDR, AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM);
}
// End of bus reset
else if (ISSET(dStatus, AT91C_UDP_ENDBUSRES)) {
// The device enters the Default state
// MCK + UDPCK are already enabled
// Pull-Up is already connected
// Transceiver must be enabled
// Endpoint 0 must be enabled
SET(*(pUsb->pState), USB_STATE_DEFAULT);
UDP_EnableTransceiver(pUsb);
// The device leaves the Address & Configured states
CLEAR(*(pUsb->pState), USB_STATE_ADDRESS | USB_STATE_CONFIGURED);
UDP_ResetEndpoints(pUsb);
UDP_DisableEndpoints(pUsb);
UDP_ConfigureEndpoint(pUsb, 0);
// Flush and enable the Suspend interrupt
SET(pInterface->UDP_ICR,
AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM | AT91C_UDP_RXSUSP);
// Enable the Start Of Frame (SOF) interrupt if needed
if (pUsb->pCallbacks->startOfFrame != 0) {
SET(pInterface->UDP_IER, AT91C_UDP_SOFINT);
}
// Invoke the Reset callback
USB_ResetCallback(pUsb);
// Acknowledge end of bus reset interrupt
SET(pInterface->UDP_ICR, AT91C_UDP_ENDBUSRES);
}
// Endpoint interrupts
else {
while (dStatus != 0) {
// Get endpoint index
bEndpoint = lastSetBit(dStatus);
UDP_EndpointHandler(pUsb, bEndpoint);
/*CLEAR(pInterface->UDP_CSR[bEndpoint],
AT91C_UDP_TXCOMP | AT91C_UDP_RX_DATA_BK0
| AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RXSETUP
| AT91C_UDP_STALLSENT);*/
CLEAR(dStatus, 1 << bEndpoint);
}
}
// Retrieve new interrupt status
dStatus = pInterface->UDP_ISR & pInterface->UDP_IMR & ISR_MASK;
// Mask unneeded interrupts
if (!ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
dStatus &= AT91C_UDP_ENDBUSRES | AT91C_UDP_SOFINT;
}
}
}
//------------------------------------------------------------------------------
// \brief Sends data through an USB endpoint
//
// Sets up the transfer descriptor, write one or two data payloads
// (depending on the number of FIFO banks for the endpoint) and then
// starts the actual transfer. The operation is complete when all
// the data has been sent.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param pData Pointer to a buffer containing the data to send
// \param dLength Length of the data buffer
// \param fCallback Optional function to invoke when the transfer finishes
// \param pArgument Optional argument for the callback function
// \return Operation result code
// \see Operation result codes
// \see Callback_f
// \see S_usb
//------------------------------------------------------------------------------
char UDP_Write(const S_usb *pUsb,
unsigned char bEndpoint,
const void *pData,
unsigned int dLength,
Callback_f fCallback,
void *pArgument)
{
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
// Check that the endpoint is in Idle state
if (pEndpoint->dState != endpointStateIdle) {
return USB_STATUS_LOCKED;
}
// Setup the transfer descriptor
pEndpoint->pData = (char *) pData;
pEndpoint->dBytesRemaining = dLength;
pEndpoint->dBytesBuffered = 0;
pEndpoint->dBytesTransferred = 0;
pEndpoint->fCallback = fCallback;
pEndpoint->pArgument = pArgument;
// Send one packet
pEndpoint->dState = endpointStateWrite;
UDP_WritePayload(pUsb, bEndpoint);
UDP_SETEPFLAGS(pUsb, bEndpoint, AT91C_UDP_TXPKTRDY);
// If double buffering is enabled and there is data remaining,
// prepare another packet
if ((pEndpoint->dNumFIFO > 1) && (pEndpoint->dBytesRemaining > 0)) {
UDP_WritePayload(pUsb, bEndpoint);
}
// Enable interrupt on endpoint
SET(pInterface->UDP_IER, 1 << bEndpoint);
return USB_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
// \brief 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
// packet size) is received.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param pData Pointer to a buffer to store the received data
// \param dLength Length of the receive buffer
// \param fCallback Optional callback function
// \param pArgument Optional callback argument
// \return Operation result code
// \see Callback_f
// \see S_usb
//------------------------------------------------------------------------------
char UDP_Read(const S_usb *pUsb,
unsigned char bEndpoint,
void *pData,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -