📄 udp.c
字号:
unsigned int dLength,
Callback_f fCallback,
void *pArgument)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
//! Return if the endpoint is not in IDLE state
// if (pEndpoint->dState != endpointStateIdle) {
// return USB_STATUS_LOCKED;
// }
// Endpoint enters Read state
pEndpoint->dState = endpointStateRead;
// Set the transfer descriptor
pEndpoint->pData = (char *) pData;
pEndpoint->dBytesRemaining = dLength;
pEndpoint->dBytesBuffered = 0;
pEndpoint->dBytesTransferred = 0;
pEndpoint->fCallback = fCallback;
pEndpoint->pArgument = pArgument;
// Enable interrupt on endpoint
SET(pInterface->UDP_IER, 1 << bEndpoint);
return USB_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
// \brief Clears, sets or returns the Halt state on specified endpoint
//
// When in Halt state, an endpoint acknowledges every received packet
// with a STALL handshake. This continues until the endpoint is
// manually put out of the Halt state by calling this function.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param bRequest Request to perform
// -> USB_SET_FEATURE, USB_CLEAR_FEATURE, USB_GET_STATUS
// \return true if the endpoint is currently Halted, false otherwise
// \see S_usb
//------------------------------------------------------------------------------
bool UDP_Halt(const S_usb *pUsb,
unsigned char bEndpoint,
unsigned char bRequest)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
// Clear the Halt feature of the endpoint if it is enabled
if (bRequest == USB_CLEAR_FEATURE) {
// Return endpoint to Idle state
pEndpoint->dState = endpointStateIdle;
// Clear FORCESTALL flag
UDP_CLEAREPFLAGS(pUsb, bEndpoint, AT91C_UDP_FORCESTALL);
// Reset Endpoint Fifos, beware this is a 2 steps operation
SET(pInterface->UDP_RSTEP, 1 << bEndpoint);
CLEAR(pInterface->UDP_RSTEP, 1 << bEndpoint);
}
// Set the Halt feature on the endpoint if it is not already enabled
// and the endpoint is not disabled
else if ((bRequest == USB_SET_FEATURE)
&& (pEndpoint->dState != endpointStateHalted)
&& (pEndpoint->dState != endpointStateDisabled)) {
// Abort the current transfer if necessary
UDP_EndOfTransfer(pEndpoint, USB_STATUS_ABORTED);
// Put endpoint into Halt state
UDP_SETEPFLAGS(pUsb, bEndpoint, AT91C_UDP_FORCESTALL);
pEndpoint->dState = endpointStateHalted;
// Enable the endpoint interrupt
SET(pInterface->UDP_IER, 1 << bEndpoint);
}
// Return the endpoint halt status
if (pEndpoint->dState == endpointStateHalted) {
return true;
}
else {
return false;
}
}
//------------------------------------------------------------------------------
// \brief Causes the endpoint to acknowledge the next received packet with
// a STALL handshake.
//
// Further packets are then handled normally.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \return Operation result code
// \see S_usb
//------------------------------------------------------------------------------
char UDP_Stall(const S_usb *pUsb,
unsigned char bEndpoint)
{
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
// Check that endpoint is in Idle state
if (pEndpoint->dState != endpointStateIdle) {
return USB_STATUS_LOCKED;
}
UDP_SETEPFLAGS(pUsb, bEndpoint, AT91C_UDP_FORCESTALL);
return USB_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
// \brief Activates a remote wakeup procedure
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
void UDP_RemoteWakeUp(const S_usb *pUsb)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
UDP_EnableMCK(pUsb);
UDP_EnableUDPCK(pUsb);
UDP_EnableTransceiver(pUsb);
// Activates a remote wakeup (edge on ESR)
SET(pInterface->UDP_GLBSTATE, AT91C_UDP_ESR);
// Then clear ESR
CLEAR(pInterface->UDP_GLBSTATE, AT91C_UDP_ESR);
}
//------------------------------------------------------------------------------
// \brief Handles attachment or detachment from the USB when the VBus power
// line status changes.
// \param pUsb Pointer to a S_usb instance
// \return true if VBus is present, false otherwise
// \see S_usb
//------------------------------------------------------------------------------
bool UDP_Attach(const S_usb *pUsb)
{
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
// Check if VBus is present
if (!ISSET(USB_GetState(pUsb), USB_STATE_POWERED))
// && BRD_IsVBusConnected(pInterface))
{
// Powered state:
// MCK + UDPCK must be on
// Pull-Up must be connected
// Transceiver must be disabled
// Invoke the Resume callback
USB_ResumeCallback(pUsb);
UDP_EnableMCK(pUsb);
UDP_EnableUDPCK(pUsb);
// Reconnect the pull-up if needed
if (ISSET(*(pUsb->pState), UDP_STATE_SHOULD_RECONNECT)) {
USB_Connect(pUsb);
CLEAR(*(pUsb->pState), UDP_STATE_SHOULD_RECONNECT);
}
// Clear the Suspend and Resume interrupts
SET(pInterface->UDP_ICR,
AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM | AT91C_UDP_RXSUSP);
SET(pInterface->UDP_IER, AT91C_UDP_RXSUSP);
// The device is in Powered state
SET(*(pUsb->pState), USB_STATE_POWERED);
}
else //if (ISSET(USB_GetState(pUsb), USB_STATE_POWERED)
// && !BRD_IsVBusConnected(pInterface))
{
// Attached state:
// MCK + UDPCK off
// Pull-Up must be disconnected
// Transceiver must be disabled
// Warning: MCK must be enabled to be able to write in UDP registers
// It may have been disabled by the Suspend interrupt, so re-enable it
UDP_EnableMCK(pUsb);
// Disable interrupts
SET(pInterface->UDP_IDR, AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM
| AT91C_UDP_RXSUSP | AT91C_UDP_SOFINT);
UDP_DisableEndpoints(pUsb);
UDP_DisableTransceiver(pUsb);
// Disconnect the pull-up if needed
if (ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
USB_Disconnect(pUsb);
SET(*(pUsb->pState), UDP_STATE_SHOULD_RECONNECT);
}
UDP_DisableMCK(pUsb);
UDP_DisableUDPCK(pUsb);
// The device leaves the all states except Attached
CLEAR(*(pUsb->pState), USB_STATE_POWERED | USB_STATE_DEFAULT
| USB_STATE_ADDRESS | USB_STATE_CONFIGURED | USB_STATE_SUSPENDED);
// Invoke the Suspend callback
USB_SuspendCallback(pUsb);
}
return ISSET(USB_GetState(pUsb), USB_STATE_POWERED);
}
//------------------------------------------------------------------------------
// \brief Sets or unsets the device address
//
// This function directly accesses the S_usb_request instance located
// in the S_usb structure to extract its new address.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
void UDP_SetAddress(S_usb const *pUsb)
{
unsigned short wAddress = USB_GetSetup(pUsb)->wValue;
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
// Set address
SET(pInterface->UDP_FADDR, AT91C_UDP_FEN | wAddress);
if (wAddress == 0) {
SET(pInterface->UDP_GLBSTATE, 0);
// Device enters the Default state
CLEAR(*(pUsb->pState), USB_STATE_ADDRESS);
}
else {
SET(pInterface->UDP_GLBSTATE, AT91C_UDP_FADDEN);
// The device enters the Address state
SET(*(pUsb->pState), USB_STATE_ADDRESS);
}
}
//------------------------------------------------------------------------------
// \brief Changes the device state from Address to Configured, or from
// Configured to Address.
//
// This method directly access the last received SETUP packet to
// decide on what to do.
// \see S_usb
//------------------------------------------------------------------------------
void UDP_SetConfiguration(S_usb const *pUsb)
{
unsigned short wValue = USB_GetSetup(pUsb)->wValue;
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
// Check the request
if (wValue != 0) {
// Enter Configured state
SET(*(pUsb->pState), USB_STATE_CONFIGURED);
SET(pInterface->UDP_GLBSTATE, AT91C_UDP_CONFG);
}
else {
// Go back to Address state
CLEAR(*(pUsb->pState), USB_STATE_CONFIGURED);
SET(pInterface->UDP_GLBSTATE, AT91C_UDP_FADDEN);
// Abort all transfers
UDP_DisableEndpoints(pUsb);
}
}
//------------------------------------------------------------------------------
// \brief Enables the pull-up on the D+ line to connect the device to the USB.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
void UDP_Connect(const S_usb *pUsb)
{
#if defined(UDP_INTERNAL_PULLUP)
SET(UDP_GetDriverInterface(pUsb)->UDP_TXVC, AT91C_UDP_PUON);
#elif defined(UDP_INTERNAL_PULLUP_BY_MATRIX)
AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON;
#else
BRD_ConnectPullUp(UDP_GetDriverInterface(pUsb));
#endif
}
//------------------------------------------------------------------------------
// \brief Disables the pull-up on the D+ line to disconnect the device from
// the bus.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
void UDP_Disconnect(const S_usb *pUsb)
{
#if defined(UDP_INTERNAL_PULLUP)
CLEAR(UDP_GetDriverInterface(pUsb)->UDP_TXVC, AT91C_UDP_PUON);
#elif defined(UDP_INTERNAL_PULLUP_BY_MATRIX)
AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
#else
BRD_DisconnectPullUp(UDP_GetDriverInterface(pUsb));
#endif
// Device leaves the Default state
CLEAR(*(pUsb->pState), USB_STATE_DEFAULT);
}
//------------------------------------------------------------------------------
// \brief Initializes the specified USB driver
//
// This function initializes the current FIFO bank of endpoints,
// configures the pull-up and VBus lines, disconnects the pull-up and
// then trigger the Init callback.
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
void UDP_Init(const S_usb *pUsb)
{
unsigned int dIndex;
AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb);
// Init data banks
for (dIndex = 0; dIndex < pUsb->dNumEndpoints; dIndex++) {
pUsb->pEndpoints[dIndex].dFlag = AT91C_UDP_RX_DATA_BK0;
}
// External pull-up on D+
// Configure
BRD_ConfigurePullUp(pInterface);
// Disable
UDP_Disconnect(pUsb);
// Device is in the Attached state
*(pUsb->pState) = USB_STATE_ATTACHED;
// Disable the UDP transceiver and interrupts
UDP_EnableMCK(pUsb);
SET(pInterface->UDP_IDR, AT91C_UDP_RXRSM);
UDP_Connect(pUsb);
UDP_DisableTransceiver(pUsb);
UDP_DisableMCK(pUsb);
UDP_Disconnect(pUsb);
// Configure interrupts
USB_InitCallback(pUsb);
}
//------------------------------------------------------------------------------
// Global variables
//------------------------------------------------------------------------------
// \brief Low-level driver methods to use with the UDP USB controller
// \see S_driver_methods
const S_driver_methods sUDPMethods = {
UDP_Init,
UDP_Write,
UDP_Read,
UDP_Stall,
UDP_Halt,
UDP_RemoteWakeUp,
UDP_ConfigureEndpoint,
UDP_Attach,
UDP_SetAddress,
UDP_SetConfiguration,
UDP_Handler,
UDP_Connect,
UDP_Disconnect
};
// \brief Default driver when an UDP controller is present on a chip
const S_usb_driver sDefaultDriver = {
AT91C_BASE_UDP,
0,
0,
AT91C_ID_UDP,
AT91C_PMC_UDP,
&sUDPMethods
};
#endif // UDP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -