?? usbd_otghs.c
字號:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/*!
Functions for OTGHS peripheral usage.
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <board.h>
#ifdef CHIP_OTGHS
#include "common.h"
#include "trace.h"
#include "usb.h"
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
#define NUM_IT_MAX (AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_EPT_NBR_MAX)
#define NUM_IT_MAX_DMA ((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4)
#define SHIFT_DMA 24
#define SHIFT_INTERUPT 12
#define DMA
//------------------------------------------------------------------------------
// Structures
//------------------------------------------------------------------------------
// \brief Endpoint states
typedef enum {
endpointStateDisabled,
endpointStateIdle,
endpointStateWrite,
endpointStateRead,
endpointStateHalted
} EndpointState_t;
//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Internal Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// \brief Returns a pointer to the OTGHS controller interface used by an USB
// driver
//
// The pointer is cast to the correct type (AT91PS_OTGHS).
// \param pUsb Pointer to a S_usb instance
// \return Pointer to the USB controller interface
// \see S_usb
//------------------------------------------------------------------------------
static AT91PS_OTGHS OTGHS_GetDriverInterface(const S_usb *pUsb)
{
return (AT91PS_OTGHS) pUsb->pDriver->pInterface;
}
//------------------------------------------------------------------------------
// \fn OTGHS_GetInterfaceEPT
// \brief Returns OTGHS endpoint FIFO interface from S_usb structure
//------------------------------------------------------------------------------
static AT91PS_OTGHS_EPTFIFO OTGHS_GetInterfaceEPT(const S_usb *pUsb)
{
return (AT91PS_OTGHS_EPTFIFO) pUsb->pDriver->pEndpointFIFO;
}
//------------------------------------------------------------------------------
// \brief Enables the peripheral clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_EnableMCK(const S_usb *pUsb)
{
}
//------------------------------------------------------------------------------
// \brief Disables the peripheral clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_DisableMCK(const S_usb *pUsb)
{
}
//------------------------------------------------------------------------------
// \brief Enables the 48MHz clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_EnableOTGHSCK(const S_usb *pUsb)
{
}
//------------------------------------------------------------------------------
// \brief Disables the 48MHz clock of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_DisableOTGHSCK(const S_usb *pUsb)
{
}
//------------------------------------------------------------------------------
// \brief Enables the transceiver of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_EnableTransceiver(const S_usb *pUsb)
{
SET(OTGHS_GetDriverInterface(pUsb)->OTGHS_CTRL, AT91C_OTGHS_OTGPADE);
}
//------------------------------------------------------------------------------
// \brief Disables the transceiver of the USB controller associated with
// the specified USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_DisableTransceiver(const S_usb *pUsb)
{
CLEAR(OTGHS_GetDriverInterface(pUsb)->OTGHS_CTRL, AT91C_OTGHS_OTGPADE);
}
//------------------------------------------------------------------------------
// \brief Invokes the callback associated with a finished transfer on an
// endpoint
// \param pEndpoint Pointer to a S_usb_endpoint instance
// \param bStatus Status code returned by the transfer operation
// \see Status codes
// \see S_usb_endpoint
//------------------------------------------------------------------------------
static void OTGHS_EndOfTransfer(S_usb_endpoint *pEndpoint,
char bStatus)
{
if ((pEndpoint->dState == endpointStateWrite)
|| (pEndpoint->dState == endpointStateRead)) {
TRACE_DEBUG_WP("E");
// Endpoint returns in Idle state
pEndpoint->dState = endpointStateIdle;
// Invoke callback is present
if (pEndpoint->fCallback != 0) {
pEndpoint->fCallback((unsigned int) pEndpoint->pArgument,
(unsigned int) bStatus,
pEndpoint->dBytesTransferred,
pEndpoint->dBytesRemaining
+ pEndpoint->dBytesBuffered);
}
}
}
//------------------------------------------------------------------------------
// \brief Transfers a data payload from the current tranfer buffer to the
// endpoint FIFO.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \return Number of bytes transferred
// \see S_usb
//------------------------------------------------------------------------------
static unsigned int OTGHS_WritePayload(const S_usb *pUsb,
unsigned char bEndpoint)
{
AT91PS_OTGHS_EPTFIFO pInterfaceEPT = OTGHS_GetInterfaceEPT(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
char *pfifo;
unsigned int dBytes;
unsigned int dCtr;
pfifo = (char*)&(pInterfaceEPT->OTGHS_READEPT0[bEndpoint*16384]);
// Get the number of bytes to send
dBytes = min(pEndpoint->wMaxPacketSize, pEndpoint->dBytesRemaining);
// Transfer one packet in the FIFO buffer
for (dCtr = 0; dCtr < dBytes; dCtr++) {
pfifo[dCtr] = *(pEndpoint->pData);
pEndpoint->pData++;
}
pEndpoint->dBytesBuffered += dBytes;
pEndpoint->dBytesRemaining -= dBytes;
return dBytes;
}
//----------------------------------------------------------------------------
// \brief Transfers a data payload from an endpoint FIFO to the current
// transfer buffer.
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \param wPacketSize Size of received data packet
// \return Number of bytes transferred
// \see S_usb
//------------------------------------------------------------------------------
static unsigned int OTGHS_GetPayload(const S_usb *pUsb,
unsigned char bEndpoint,
unsigned short wPacketSize)
{
AT91PS_OTGHS_EPTFIFO pInterfaceEPT = OTGHS_GetInterfaceEPT(pUsb);
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
char *pfifo;
unsigned int dBytes;
unsigned int dCtr;
pfifo = (char*)&(pInterfaceEPT->OTGHS_READEPT0[bEndpoint*16384]);
// Get number of bytes to retrieve
dBytes = min(pEndpoint->dBytesRemaining, wPacketSize);
// Retrieve packet
for (dCtr = 0; dCtr < dBytes; dCtr++) {
*(pEndpoint->pData) = pfifo[dCtr];
pEndpoint->pData++;
}
pEndpoint->dBytesRemaining -= dBytes;
pEndpoint->dBytesTransferred += dBytes;
pEndpoint->dBytesBuffered += wPacketSize - dBytes;
return dBytes;
}
//------------------------------------------------------------------------------
// \brief Transfers a received SETUP packet from endpoint 0 FIFO to the
// S_usb_request structure of an USB driver
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_GetSetup(const S_usb *pUsb)
{
unsigned int *pData = (unsigned int *) USB_GetSetup(pUsb);
AT91PS_OTGHS_EPTFIFO pInterfaceEPT = OTGHS_GetInterfaceEPT(pUsb);
pData[0] = pInterfaceEPT->OTGHS_READEPT0[0];
pData[1] = pInterfaceEPT->OTGHS_READEPT0[0];
}
//------------------------------------------------------------------------------
// \brief This function reset all endpoint transfer descriptors
// \param pUsb Pointer to a S_usb instance
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_ResetEndpoints(const S_usb *pUsb)
{
S_usb_endpoint *pEndpoint;
unsigned char bEndpoint;
// Reset the transfer descriptor of every endpoint
for (bEndpoint = 0; bEndpoint < pUsb->dNumEndpoints; bEndpoint++) {
pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
// Reset endpoint transfer descriptor
pEndpoint->pData = 0;
pEndpoint->dBytesRemaining = 0;
pEndpoint->dBytesTransferred = 0;
pEndpoint->dBytesBuffered = 0;
pEndpoint->fCallback = 0;
pEndpoint->pArgument = 0;
// Configure endpoint characteristics
pEndpoint->dState = endpointStateDisabled;
}
}
//------------------------------------------------------------------------------
// \brief Disable all endpoints (except control endpoint 0), aborting current
// transfers if necessary.
// \param pUsb Pointer to a S_usb instance
//------------------------------------------------------------------------------
static void OTGHS_DisableEndpoints(const S_usb *pUsb)
{
S_usb_endpoint *pEndpoint;
unsigned char bEndpoint;
// Foreach endpoint, if it is enabled, disable it and invoke the callback
// Control endpoint 0 is not disabled
for (bEndpoint = 1; bEndpoint < pUsb->dNumEndpoints; bEndpoint++) {
pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_RESET);
pEndpoint->dState = endpointStateDisabled;
}
}
//------------------------------------------------------------------------------
// \brief Endpoint interrupt handler.
//
// Handle IN/OUT transfers, received SETUP packets and STALLing
// \param pUsb Pointer to a S_usb instance
// \param bEndpoint Index of endpoint
// \see S_usb
//------------------------------------------------------------------------------
static void OTGHS_EndpointHandler(const S_usb *pUsb, unsigned char bEndpoint)
{
S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint);
AT91PS_OTGHS pInterface = OTGHS_GetDriverInterface(pUsb);
unsigned int dStatus = pInterface->OTGHS_DEVEPTCSR[bEndpoint];
unsigned short wPacketSize;
TRACE_DEBUG_WP("Ept%d, 0x%X ", bEndpoint, dStatus);
// Handle interrupts
// IN packet sent
if((ISSET(pInterface->OTGHS_DEVEPTCMR[bEndpoint], AT91C_OTGHS_TXINI))
&& (ISSET(dStatus, AT91C_OTGHS_TXINI ))) {
TRACE_DEBUG_WP("Wr ");
if (pEndpoint->dBytesBuffered > 0) {
TRACE_DEBUG_WP("%d ", pEndpoint->dBytesBuffered);
pEndpoint->dBytesTransferred += pEndpoint->dBytesBuffered;
pEndpoint->dBytesBuffered = 0;
}
if ((!pEndpoint->isDataSent) || (pEndpoint->dBytesRemaining > 0)) {
OTGHS_WritePayload(pUsb, bEndpoint);
pEndpoint->isDataSent = true;
pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_TXINI;
// For a non-control endpoint, the FIFOCON bit must be cleared
// to start the transfer
if ((AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])
!= AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_FIFOCON;
}
}
else {
pInterface->OTGHS_DEVEPTCDR[bEndpoint] = AT91C_OTGHS_TXINI;
// Disable interrupt if this is not a control endpoint
if ((AT91C_OTGHS_EPT_TYPE & pInterface->OTGHS_DEVEPTCFG[bEndpoint])
!= AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
pInterface->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
}
OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
}
}
// OUT packet received
if(ISSET(dStatus, AT91C_OTGHS_RXOUT)) {
TRACE_DEBUG_WP("Rd ");
// Check that the endpoint is in Read state
if (pEndpoint->dState != endpointStateRead) {
// Endpoint is NOT in Read state
if (ISCLEARED(pInterface->OTGHS_DEVEPTCFG[bEndpoint], AT91C_OTGHS_EPT_TYPE)
&& ISCLEARED(dStatus, (0x7FF<<20))) { // byte count
// Control endpoint, 0 bytes received
// Acknowledge the data and finish the current transfer
TRACE_DEBUG_WP("Ack ");
pInterface->OTGHS_DEVEPTCCR[bEndpoint] = AT91C_OTGHS_RXOUT;
OTGHS_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS);
}
else if (ISSET(dStatus, AT91C_OTGHS_STALL)) {
// Non-control endpoint
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -