⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb-cdc.c

📁 新版的FreeRTOS操作系统源代码4.0.0版
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
	FreeRTOS V4.0.0 - copyright (C) 2003-2006 Richard Barry.

	This file is part of the FreeRTOS distribution.

	FreeRTOS 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 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; 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, 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 + -