?? usb-cdc.c
字號:
/*
FreeRTOS.org V4.1.1 - copyright (C) 2003-2006 Richard Barry.
This file is part of the FreeRTOS.org distribution.
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
/*
USB Communications Device Class driver.
Implements task vUSBCDCTask and provides an Abstract Control Model serial
interface. Control is through endpoint 0, device-to-host notification is
provided by interrupt-in endpoint 3, and raw data is transferred through
bulk endpoints 1 and 2.
- developed from original FreeRTOS HID example by Scott Miller
- modified to support 3.2 GCC by najay
*/
/* Standard includes. */
#include <string.h>
#include <stdio.h>
/* Demo board includes. */
#include "Board.h"
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* Demo app includes. */
#include "USB-CDC.h"
#include "descriptors.h"
#define usbNO_BLOCK ( ( portTickType ) 0 )
/* Reset all endpoints */
static void prvResetEndPoints( void );
/* Clear pull up resistor to detach device from host */
static void vDetachUSBInterface( void );
/* Set up interface and initialize variables */
static void vInitUSBInterface( void );
/* Handle control endpoint events. */
static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
/* Handle standard device requests. */
static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
/* Handle standard interface requests. */
static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
/* Handle endpoint requests. */
static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
/* Handle class interface requests. */
static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
/* Prepare control data transfer. prvSendNextSegment starts transfer. */
static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthLeftToSend, portLONG lSendingDescriptor );
/* Send next segment of data for the control transfer */
static void prvSendNextSegment( void );
/* Send stall - used to respond to unsupported requests */
static void prvSendStall( void );
/* Send a zero-length (null) packet */
static void prvSendZLP( void );
/* Handle requests for standard interface descriptors */
static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
/*------------------------------------------------------------*/
/* File scope static variables */
static unsigned portCHAR ucUSBConfig = ( unsigned portCHAR ) 0;
static unsigned portLONG ulReceivedAddress = ( unsigned portLONG ) 0;
static eDRIVER_STATE eDriverState = eNOTHING;
/* Incoming and outgoing control data structures */
static xCONTROL_MESSAGE pxControlTx;
static xCONTROL_MESSAGE pxControlRx;
/* Queue holding pointers to pending messages */
xQueueHandle xUSBInterruptQueue;
/* Queues used to hold received characters, and characters waiting to be
transmitted. Rx queue must be larger than FIFO size. */
static xQueueHandle xRxCDC;
static xQueueHandle xTxCDC;
/* Line coding - 115,200 baud, N-8-1 */
static const unsigned portCHAR pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
/* Status variables. */
static unsigned portCHAR ucControlState;
static unsigned int uiCurrentBank;
/*------------------------------------------------------------*/
void vUSBCDCTask( void *pvParameters )
{
xISRStatus *pxMessage;
unsigned portLONG ulStatus;
unsigned portLONG ulRxBytes;
unsigned portCHAR ucByte;
portBASE_TYPE xByte;
( void ) pvParameters;
/* Disconnect USB device from hub. For debugging - causes host to register reset */
portENTER_CRITICAL();
vDetachUSBInterface();
portEXIT_CRITICAL();
vTaskDelay( portTICK_RATE_MS * 60 );
/* Init USB interface */
portENTER_CRITICAL();
vInitUSBInterface();
portEXIT_CRITICAL();
/* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
for( ;; )
{
/* Look for data coming from the ISR. */
if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
{
if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
{
/* All endpoint 0 interrupts are handled here. */
prvProcessEndPoint0Interrupt( pxMessage );
}
if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
{
/* End of bus reset - reset the endpoints and de-configure. */
prvResetEndPoints();
}
}
/* See if we're ready to send and receive data. */
if( eDriverState == eREADY_TO_SEND && ucControlState )
{
if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
{
for( xByte = 0; xByte < 64; xByte++ )
{
if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
{
/* No data buffered to transmit. */
break;
}
/* Got a byte to transmit. */
AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
}
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
}
/* Check for incoming data (host-to-device) on endpoint 1. */
while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
{
ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
/* Only process FIFO if there's room to store it in the queue */
if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
{
while( ulRxBytes-- )
{
ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
xQueueSend( xRxCDC, &ucByte, 0 );
}
/* Release the FIFO */
portENTER_CRITICAL();
{
ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
}
portEXIT_CRITICAL();
/* Re-enable endpoint 1's interrupts */
AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
/* Update the current bank in use */
if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
{
uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
}
else
{
uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
}
}
else
{
break;
}
}
}
}
}
/*------------------------------------------------------------*/
void vUSBSendByte( portCHAR cByte )
{
/* Queue the byte to be sent. The USB task will send it. */
xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
}
/*------------------------------------------------------------*/
static void prvSendZLP( void )
{
unsigned portLONG ulStatus;
/* Wait until the FIFO is free - even though we are not going to use it.
THERE IS NO TIMEOUT HERE! */
while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
{
vTaskDelay( usbSHORTEST_DELAY );
}
portENTER_CRITICAL();
{
/* Cancel any further pending data */
pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
/* Set the TXPKTRDY bit to cause a transmission with no data. */
ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
}
portEXIT_CRITICAL();
}
/*------------------------------------------------------------*/
static void prvSendStall( void )
{
unsigned portLONG ulStatus;
portENTER_CRITICAL();
{
/* Force a stall by simply setting the FORCESTALL bit in the CSR. */
ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
}
portEXIT_CRITICAL();
}
/*------------------------------------------------------------*/
static void prvResetEndPoints( void )
{
unsigned portLONG ulTemp;
eDriverState = eJUST_RESET;
ucControlState = 0;
/* Reset all the end points. */
AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
AT91C_BASE_UDP->UDP_RSTEP = ( unsigned portLONG ) 0x00;
/* Enable data to be sent and received. */
AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
/* Repair the configuration end point. */
portENTER_CRITICAL();
{
ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
usbCSR_SET_BIT( &ulTemp, ( ( unsigned portLONG ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
}
portEXIT_CRITICAL();
uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
}
/*------------------------------------------------------------*/
static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
{
static xUSB_REQUEST xRequest;
unsigned portLONG ulRxBytes;
/* Get number of bytes received, if any */
ulRxBytes = pxMessage->ulCSR0 >> 16;
ulRxBytes &= usbRX_COUNT_MASK;
if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
{
/* We received a TX complete interrupt. What we do depends on
what we sent to get this interrupt. */
if( eDriverState == eJUST_GOT_CONFIG )
{
/* We sent an acknowledgement of a SET_CONFIG request. We
are now at the end of the enumeration.
TODO: Config 0 sets unconfigured state, should enter Address state.
Request for unsupported config should stall. */
AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
/* Set up endpoints */
portENTER_CRITICAL();
{
unsigned portLONG ulTemp;
/* Set endpoint 1 to bulk-out */
ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
/* Set endpoint 2 to bulk-in */
ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
/* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
/*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
}
portEXIT_CRITICAL();
eDriverState = eREADY_TO_SEND;
}
else if( eDriverState == eJUST_GOT_ADDRESS )
{
/* We sent an acknowledgement of a SET_ADDRESS request. Move
to the addressed state. */
if( ulReceivedAddress != ( unsigned portLONG ) 0 )
{
AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
}
else
{
AT91C_BASE_UDP->UDP_GLBSTATE = 0;
}
AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
eDriverState = eNOTHING;
}
else
{
/* The TXCOMP was not for any special type of transmission. See
if there is any more data to send. */
prvSendNextSegment();
}
}
if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
{
/* Received a control data packet. May be a 0-length ACK or a data stage. */
unsigned portCHAR ucBytesToGet;
/* Got data. Cancel any outgoing data. */
pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
/* Determine how many bytes we need to receive. */
ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
if( ucBytesToGet > ulRxBytes )
{
ucBytesToGet = ulRxBytes;
}
/* If we're not expecting any data, it's an ack - just quit now. */
if( !ucBytesToGet )
{
return;
}
/* Get the required data and update the index. */
memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
pxControlRx.ulNextCharIndex += ucBytesToGet;
}
if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
{
/* Received a SETUP packet. May be followed by data packets. */
if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
{
/* Create an xUSB_REQUEST variable from the raw bytes array. */
xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
xRequest.usValue <<= 8;
xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
xRequest.usIndex <<= 8;
xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
xRequest.usLength <<= 8;
xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -