📄 usbd_otghs.c
字号:
// Enable wakeup
SET(pInterface->OTGHS_DEVIER, AT91C_OTGHS_EORST | AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM);
// Acknowledge interrupt
pInterface->OTGHS_DEVICR = AT91C_OTGHS_SUSP;
SET(*(pUsb->pState), USB_STATE_SUSPENDED);
OTGHS_DisableTransceiver(pUsb);
OTGHS_DisableMCK(pUsb);
OTGHS_DisableOTGHSCK(pUsb);
// Invoke the Suspend callback
USB_SuspendCallback(pUsb);
}
}
// Resume
else if (ISSET(dStatus, AT91C_OTGHS_WAKEUP)
|| ISSET(dStatus, AT91C_OTGHS_EORSM)) {
// Invoke the Resume callback
USB_ResumeCallback(pUsb);
TRACE_DEBUG_M("R ");
// 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
OTGHS_EnableMCK(pUsb);
OTGHS_EnableOTGHSCK(pUsb);
// Default state
if (ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
OTGHS_EnableTransceiver(pUsb);
}
CLEAR(*(pUsb->pState), USB_STATE_SUSPENDED);
}
pInterface->OTGHS_DEVICR =
(AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM | AT91C_OTGHS_SUSP);
pInterface->OTGHS_DEVIER = (AT91C_OTGHS_EORST | AT91C_OTGHS_SUSP);
pInterface->OTGHS_DEVICR = (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM);
pInterface->OTGHS_DEVIDR = AT91C_OTGHS_WAKEUP;
}
// End of bus reset
else if (dStatus & AT91C_OTGHS_EORST) {
TRACE_DEBUG_M("EoB ");
// 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);
OTGHS_EnableTransceiver(pUsb);
// The device leaves the Address & Configured states
CLEAR(*(pUsb->pState), USB_STATE_ADDRESS | USB_STATE_CONFIGURED);
OTGHS_ResetEndpoints(pUsb);
OTGHS_DisableEndpoints(pUsb);
OTGHS_ConfigureEndpoint(pUsb, 0);
// Flush and enable the Suspend interrupt
SET(pInterface->OTGHS_DEVICR, AT91C_OTGHS_WAKEUP | AT91C_OTGHS_SUSP);
// Enable the Start Of Frame (SOF) interrupt if needed
if (pUsb->pCallbacks->startOfFrame != 0) {
SET(pInterface->OTGHS_DEVIER, AT91C_OTGHS_SOF);
}
// Invoke the Reset callback
USB_ResetCallback(pUsb);
// Acknowledge end of bus reset interrupt
pInterface->OTGHS_DEVICR = AT91C_OTGHS_EORST;
}
// Handle upstream resume interrupt
else if (dStatus & AT91C_OTGHS_UPRSM) {
TRACE_DEBUG_L(" External resume interrupt\n\r");
// - Acknowledge the IT
pInterface->OTGHS_DEVICR = AT91C_OTGHS_UPRSM;
}
// Endpoint interrupts
else {
#ifndef DMA
// Handle endpoint interrupts
for (numIT = 0; numIT < NUM_IT_MAX; numIT++) {
if( dStatus & (1<<SHIFT_INTERUPT<<numIT) ) {
OTGHS_EndpointHandler(pUsb, numIT);
}
}
#else
// Handle endpoint control interrupt
if( dStatus & (1<<SHIFT_INTERUPT<<0) ) {
OTGHS_EndpointHandler(pUsb, 0);
}
// Handle DMA interrupts
for(numIT = 1; numIT <= NUM_IT_MAX_DMA; numIT++) {
if( dStatus & (1<<SHIFT_DMA<<numIT) ) {
OTGHS_DmaHandler(pUsb, numIT);
}
}
#endif
}
// Retrieve new interrupt status
dStatus = (pInterface->OTGHS_DEVISR) & (pInterface->OTGHS_DEVIMR);
// Mask unneeded interrupts
if (!ISSET(USB_GetState(pUsb), USB_STATE_DEFAULT)) {
dStatus &= AT91C_OTGHS_EORST | AT91C_OTGHS_SOF;
}
TRACE_DEBUG_H("\n\r");
if (dStatus != 0) {
TRACE_DEBUG_L(" - ");
}
}
if ( (!ISSET(USB_GetState(pUsb), USB_STATE_SUSPENDED))
&& (ISSET(USB_GetState(pUsb), USB_STATE_POWERED))){
LED_TOGGLE(LED_USB);
}
}
//------------------------------------------------------------------------------
// \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
//------------------------------------------------------------------------------
static char OTGHS_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_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
// Check that the endpoint is in Idle state
if (pEndpoint->dState != endpointStateIdle) {
return USB_STATUS_LOCKED;
}
TRACE_DEBUG_L("Write%d(%d) ", bEndpoint, dLength);
// Setup the transfer descriptor
pEndpoint->pData = (char *) pData;
pEndpoint->dBytesRemaining = dLength;
pEndpoint->dBytesBuffered = 0;
pEndpoint->dBytesTransferred = 0;
pEndpoint->fCallback = fCallback;
pEndpoint->pArgument = pArgument;
pEndpoint->isDataSent = false;
// Send one packet
pEndpoint->dState = endpointStateWrite;
#ifdef DMA
// Test if endpoint type control
if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])) {
#endif
// Enable endpoint IT
pInterface->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_TXINI;
#ifdef DMA
}
else {
// others endoint (not control)
pEndpoint->dBytesBuffered = pEndpoint->dBytesRemaining;
pEndpoint->dBytesRemaining = 0;
pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int) pEndpoint->pData;
// Enable IT DMA
pInterface->OTGHS_DEVIER = (1<<SHIFT_DMA<<bEndpoint);
pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL =
(((pEndpoint->dBytesBuffered<<16)&AT91C_OTGHS_BUFF_LENGTH)
| AT91C_OTGHS_END_B_EN
| AT91C_OTGHS_END_BUFFIT
| AT91C_OTGHS_CHANN_ENB);
}
#endif
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
//------------------------------------------------------------------------------
static char OTGHS_Read(const S_usb *pUsb,
unsigned char bEndpoint,
void *pData,
unsigned int dLength,
Callback_f fCallback,
void *pArgument)
{
AT91PS_OTGHS pInterface = OTGHS_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;
}
TRACE_DEBUG_M("Read%d(%d) ", bEndpoint, dLength);
// 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;
#ifdef DMA
// Test if endpoint type control
if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])) {
#endif
// Control endpoint
// Enable endpoint IT
pInterface->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_RXOUT;
#ifdef DMA
}
else {
// others endoint (not control)
pEndpoint->dBytesBuffered = pEndpoint->dBytesRemaining;
pEndpoint->dBytesRemaining = 0;
// Enable IT DMA
pInterface->OTGHS_DEVIER = (1<<SHIFT_DMA<<bEndpoint);
pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int) pEndpoint->pData;
pInterface->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = \
( (pEndpoint->dBytesBuffered<<16)
| AT91C_OTGHS_END_TR_EN
| AT91C_OTGHS_END_TR_IT
| AT91C_OTGHS_END_B_EN
| AT91C_OTGHS_END_BUFFIT
| AT91C_OTGHS_CHANN_ENB);
}
#endif
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
//------------------------------------------------------------------------------
static bool OTGHS_Halt(const S_usb *pUsb,
unsigned char bEndpoint,
unsigned char bRequest)
{
AT91PS_OTGHS pInterface = OTGHS_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) {
TRACE_DEBUG_L("Unhalt%d ", bEndpoint);
// Return endpoint to Idle state
pEndpoint->dState = endpointStateIdle;
// Clear FORCESTALL flag
// Disable stall on endpoint
pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_STALLRQ;
pEndpoint->dState = endpointStateIdle;
// Reset data-toggle
pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_RSTDT;
}
// 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)) {
TRACE_DEBUG_L("Halt%d ", bEndpoint);
// Abort the current transfer if necessary
OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_ABORTED);
// Put endpoint into Halt state
pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_STALLRQ;
pEndpoint->dState = endpointStateHalted;
// Enable the endpoint interrupt
pInterface->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<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
//------------------------------------------------------------------------------
static char OTGHS_Stall(const S_usb *pUsb,
unsigned char bEndpoint)
{
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
// Check that endpoint is in Idle state
if (pEndpoint->dState != endpointStateIdle) {
TRACE_WARNING("W: UDP_Stall: Endpoint%d locked\n\r", bEndpoint);
return USB_STATUS_LOCKED;
}
TRACE_DEBUG_L("Stall%d ", bEndpoint);
pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_STALL;
pInterface->OTGHS_DEVEPTCER[bEndpoint] = AT91C_OTGHS_STALLRQ;
return USB_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
// \brief Activates a remote wakeup procedure
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_RemoteWakeUp(const S_usb *pUsb)
{
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
OTGHS_EnableMCK(pUsb);
OTGHS_EnableOTGHSCK(pUsb);
OTGHS_EnableTransceiver(pUsb);
TRACE_DEBUG_L("Remote WakeUp ");
//! Enable wakeup interrupt
//pInterface->OTGHS_DEVIER = AT91C_OTGHS_UPRSM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -