2 FreeRTOS V7.2.0 - Copyright (C) 2012 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 ***************************************************************************
\r
46 * Having a problem? Start by reading the FAQ "My application does *
\r
47 * not run, what could be wrong? *
\r
49 * http://www.FreeRTOS.org/FAQHelp.html *
\r
51 ***************************************************************************
\r
54 http://www.FreeRTOS.org - Documentation, training, latest information,
\r
55 license and contact details.
\r
57 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
58 including FreeRTOS+Trace - an indispensable productivity tool.
\r
60 Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell
\r
61 the code with commercial support, indemnification, and middleware, under
\r
62 the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also
\r
63 provide a safety engineered and independently SIL3 certified version under
\r
64 the SafeRTOS brand: http://www.SafeRTOS.com.
\r
68 USB Communications Device Class driver.
\r
69 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
70 interface. Control is through endpoint 0, device-to-host notification is
\r
71 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
72 bulk endpoints 1 and 2.
\r
74 - developed from original FreeRTOS HID example by Scott Miller
\r
75 - modified to support 3.2 GCC by najay
\r
78 /* Standard includes. */
\r
82 /* Demo board includes. */
\r
85 /* Scheduler includes. */
\r
86 #include "FreeRTOS.h"
\r
90 /* Demo app includes. */
\r
91 #include "USB-CDC.h"
\r
92 #include "descriptors.h"
\r
94 #define usbNO_BLOCK ( ( portTickType ) 0 )
\r
96 /* Reset all endpoints */
\r
97 static void prvResetEndPoints( void );
\r
99 /* Clear pull up resistor to detach device from host */
\r
100 static void vDetachUSBInterface( void );
\r
102 /* Set up interface and initialize variables */
\r
103 static void vInitUSBInterface( void );
\r
105 /* Handle control endpoint events. */
\r
106 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
108 /* Handle standard device requests. */
\r
109 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
111 /* Handle standard interface requests. */
\r
112 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
114 /* Handle endpoint requests. */
\r
115 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
117 /* Handle class interface requests. */
\r
118 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
120 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
121 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
123 /* Send next segment of data for the control transfer */
\r
124 static void prvSendNextSegment( void );
\r
126 /* Send stall - used to respond to unsupported requests */
\r
127 static void prvSendStall( void );
\r
129 /* Send a zero-length (null) packet */
\r
130 static void prvSendZLP( void );
\r
132 /* Handle requests for standard interface descriptors */
\r
133 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
135 /*------------------------------------------------------------*/
\r
137 /* File scope static variables */
\r
138 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
139 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
140 static eDRIVER_STATE eDriverState = eNOTHING;
\r
142 /* Incoming and outgoing control data structures */
\r
143 static xCONTROL_MESSAGE pxControlTx;
\r
144 static xCONTROL_MESSAGE pxControlRx;
\r
146 /* Queue holding pointers to pending messages */
\r
147 xQueueHandle xUSBInterruptQueue;
\r
149 /* Queues used to hold received characters, and characters waiting to be
\r
150 transmitted. Rx queue must be larger than FIFO size. */
\r
151 static xQueueHandle xRxCDC;
\r
152 static xQueueHandle xTxCDC;
\r
154 /* Line coding - 115,200 baud, N-8-1 */
\r
155 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
157 /* Status variables. */
\r
158 static unsigned char ucControlState;
\r
159 static unsigned int uiCurrentBank;
\r
162 /*------------------------------------------------------------*/
\r
165 void vUSBCDCTask( void *pvParameters )
\r
167 xISRStatus *pxMessage;
\r
168 unsigned long ulStatus;
\r
169 unsigned long ulRxBytes;
\r
170 unsigned char ucByte;
\r
171 portBASE_TYPE xByte;
\r
173 ( void ) pvParameters;
\r
175 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
176 portENTER_CRITICAL();
\r
177 vDetachUSBInterface();
\r
178 portEXIT_CRITICAL();
\r
180 vTaskDelay( portTICK_RATE_MS * 60 );
\r
182 /* Init USB interface */
\r
183 portENTER_CRITICAL();
\r
184 vInitUSBInterface();
\r
185 portEXIT_CRITICAL();
\r
187 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
191 /* Look for data coming from the ISR. */
\r
192 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
194 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
196 /* All endpoint 0 interrupts are handled here. */
\r
197 prvProcessEndPoint0Interrupt( pxMessage );
\r
200 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
202 /* End of bus reset - reset the endpoints and de-configure. */
\r
203 prvResetEndPoints();
\r
207 /* See if we're ready to send and receive data. */
\r
208 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
210 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
212 for( xByte = 0; xByte < 64; xByte++ )
\r
214 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
216 /* No data buffered to transmit. */
\r
220 /* Got a byte to transmit. */
\r
221 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
223 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
226 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
227 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
229 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
231 /* Only process FIFO if there's room to store it in the queue */
\r
232 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
234 while( ulRxBytes-- )
\r
236 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
237 xQueueSend( xRxCDC, &ucByte, 0 );
\r
240 /* Release the FIFO */
\r
241 portENTER_CRITICAL();
\r
243 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
244 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
245 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
247 portEXIT_CRITICAL();
\r
249 /* Re-enable endpoint 1's interrupts */
\r
250 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
252 /* Update the current bank in use */
\r
253 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
255 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
259 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
271 /*------------------------------------------------------------*/
\r
273 void vUSBSendByte( char cByte )
\r
275 /* Queue the byte to be sent. The USB task will send it. */
\r
276 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
278 /*------------------------------------------------------------*/
\r
280 static void prvSendZLP( void )
\r
282 unsigned long ulStatus;
\r
284 /* Wait until the FIFO is free - even though we are not going to use it.
\r
285 THERE IS NO TIMEOUT HERE! */
\r
286 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
288 vTaskDelay( usbSHORTEST_DELAY );
\r
291 portENTER_CRITICAL();
\r
293 /* Cancel any further pending data */
\r
294 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
296 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
297 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
298 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
299 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
301 portEXIT_CRITICAL();
\r
303 /*------------------------------------------------------------*/
\r
305 static void prvSendStall( void )
\r
307 unsigned long ulStatus;
\r
309 portENTER_CRITICAL();
\r
311 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
312 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
313 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
314 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
316 portEXIT_CRITICAL();
\r
318 /*------------------------------------------------------------*/
\r
320 static void prvResetEndPoints( void )
\r
322 unsigned long ulTemp;
\r
324 eDriverState = eJUST_RESET;
\r
325 ucControlState = 0;
\r
327 /* Reset all the end points. */
\r
328 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
329 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
331 /* Enable data to be sent and received. */
\r
332 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
334 /* Repair the configuration end point. */
\r
335 portENTER_CRITICAL();
\r
337 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
338 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
339 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
340 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
342 portEXIT_CRITICAL();
\r
343 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
345 /*------------------------------------------------------------*/
\r
347 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
349 static xUSB_REQUEST xRequest;
\r
350 unsigned long ulRxBytes;
\r
352 /* Get number of bytes received, if any */
\r
353 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
354 ulRxBytes &= usbRX_COUNT_MASK;
\r
356 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
358 /* We received a TX complete interrupt. What we do depends on
\r
359 what we sent to get this interrupt. */
\r
361 if( eDriverState == eJUST_GOT_CONFIG )
\r
363 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
364 are now at the end of the enumeration.
\r
366 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
367 Request for unsupported config should stall. */
\r
368 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
370 /* Set up endpoints */
\r
371 portENTER_CRITICAL();
\r
373 unsigned long ulTemp;
\r
375 /* Set endpoint 1 to bulk-out */
\r
376 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
377 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
378 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
379 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
380 /* Set endpoint 2 to bulk-in */
\r
381 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
382 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
383 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
384 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
385 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
386 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
387 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
388 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
389 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
391 portEXIT_CRITICAL();
\r
393 eDriverState = eREADY_TO_SEND;
\r
395 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
397 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
398 to the addressed state. */
\r
399 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
401 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
405 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
408 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
409 eDriverState = eNOTHING;
\r
413 /* The TXCOMP was not for any special type of transmission. See
\r
414 if there is any more data to send. */
\r
415 prvSendNextSegment();
\r
419 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
421 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
422 unsigned char ucBytesToGet;
\r
424 /* Got data. Cancel any outgoing data. */
\r
425 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
427 /* Determine how many bytes we need to receive. */
\r
428 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
429 if( ucBytesToGet > ulRxBytes )
\r
431 ucBytesToGet = ulRxBytes;
\r
434 /* If we're not expecting any data, it's an ack - just quit now. */
\r
435 if( !ucBytesToGet )
\r
440 /* Get the required data and update the index. */
\r
441 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
442 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
445 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
447 /* Received a SETUP packet. May be followed by data packets. */
\r
449 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
451 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
453 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
454 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
456 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
457 xRequest.usValue <<= 8;
\r
458 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
460 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
461 xRequest.usIndex <<= 8;
\r
462 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
464 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
465 xRequest.usLength <<= 8;
\r
466 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
468 pxControlRx.ulNextCharIndex = 0;
\r
469 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
471 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
473 /* Too big! No space for control data, stall and abort. */
\r
478 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
482 /* We're sending the data, don't wait for any. */
\r
483 pxControlRx.ulTotalDataLength = 0;
\r
488 /* See if we've got a pending request and all its associated data ready */
\r
489 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
490 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
492 unsigned char ucRequest;
\r
494 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
495 generate a zero based request selection. This is just done to
\r
496 break up the requests into subsections for clarity. The
\r
497 alternative would be to have more huge switch statement that would
\r
498 be difficult to optimise. */
\r
499 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
500 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
502 switch( ucRequest )
\r
504 case usbSTANDARD_DEVICE_REQUEST:
\r
505 /* Standard Device request */
\r
506 prvHandleStandardDeviceRequest( &xRequest );
\r
509 case usbSTANDARD_INTERFACE_REQUEST:
\r
510 /* Standard Interface request */
\r
511 prvHandleStandardInterfaceRequest( &xRequest );
\r
514 case usbSTANDARD_END_POINT_REQUEST:
\r
515 /* Standard Endpoint request */
\r
516 prvHandleStandardEndPointRequest( &xRequest );
\r
519 case usbCLASS_INTERFACE_REQUEST:
\r
520 /* Class Interface request */
\r
521 prvHandleClassInterfaceRequest( &xRequest );
\r
524 default: /* This is not something we want to respond to. */
\r
529 /*------------------------------------------------------------*/
\r
531 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
533 /* The type is in the high byte. Return whatever has been requested. */
\r
534 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
536 case usbDESCRIPTOR_TYPE_DEVICE:
\r
537 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
540 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
541 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
544 case usbDESCRIPTOR_TYPE_STRING:
\r
546 /* The index to the string descriptor is the lower byte. */
\r
547 switch( pxRequest->usValue & 0xff )
\r
549 case usbLANGUAGE_STRING:
\r
550 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
553 case usbMANUFACTURER_STRING:
\r
554 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
557 case usbPRODUCT_STRING:
\r
558 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
561 case usbCONFIGURATION_STRING:
\r
562 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
565 case usbINTERFACE_STRING:
\r
566 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
580 /*------------------------------------------------------------*/
\r
582 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
584 unsigned short usStatus = 0;
\r
586 switch( pxRequest->ucRequest )
\r
588 case usbGET_STATUS_REQUEST:
\r
589 /* Just send two byte dummy status. */
\r
590 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
593 case usbGET_DESCRIPTOR_REQUEST:
\r
594 /* Send device descriptor */
\r
595 prvGetStandardDeviceDescriptor( pxRequest );
\r
598 case usbGET_CONFIGURATION_REQUEST:
\r
599 /* Send selected device configuration */
\r
600 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
603 case usbSET_FEATURE_REQUEST:
\r
607 case usbSET_ADDRESS_REQUEST:
\r
608 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
610 eDriverState = eJUST_GOT_ADDRESS;
\r
611 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
614 case usbSET_CONFIGURATION_REQUEST:
\r
615 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
616 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
617 eDriverState = eJUST_GOT_CONFIG;
\r
622 /* Any unsupported request results in a STALL response. */
\r
627 /*------------------------------------------------------------*/
\r
629 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
631 switch( pxRequest->ucRequest )
\r
633 case usbSEND_ENCAPSULATED_COMMAND:
\r
637 case usbGET_ENCAPSULATED_RESPONSE:
\r
641 case usbSET_LINE_CODING:
\r
642 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
644 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
647 case usbGET_LINE_CODING:
\r
648 /* Get line coding */
\r
649 prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
652 case usbSET_CONTROL_LINE_STATE:
\r
653 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
655 ucControlState = pxRequest->usValue;
\r
663 /*------------------------------------------------------------*/
\r
665 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
667 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
674 /*-----------------------------------------------------------*/
\r
676 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
678 unsigned short usStatus = 0;
\r
680 switch( pxRequest->ucRequest )
\r
682 case usbGET_STATUS_REQUEST:
\r
683 /* Send dummy 2 bytes. */
\r
684 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
687 case usbGET_DESCRIPTOR_REQUEST:
\r
688 prvGetStandardInterfaceDescriptor( pxRequest );
\r
691 /* This minimal implementation does not respond to these. */
\r
692 case usbGET_INTERFACE_REQUEST:
\r
693 case usbSET_FEATURE_REQUEST:
\r
694 case usbSET_INTERFACE_REQUEST:
\r
701 /*-----------------------------------------------------------*/
\r
703 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
705 switch( pxRequest->ucRequest )
\r
707 /* This minimal implementation does not expect to respond to these. */
\r
708 case usbGET_STATUS_REQUEST:
\r
709 case usbCLEAR_FEATURE_REQUEST:
\r
710 case usbSET_FEATURE_REQUEST:
\r
717 /*-----------------------------------------------------------*/
\r
719 static void vDetachUSBInterface( void)
\r
721 /* Setup the PIO for the USB pull up resistor. */
\r
722 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
723 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
726 /* Disable pull up */
\r
727 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
729 /*-----------------------------------------------------------*/
\r
731 static void vInitUSBInterface( void )
\r
733 extern void ( vUSB_ISR_Wrapper )( void );
\r
735 /* Create the queue used to communicate between the USB ISR and task. */
\r
736 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
738 /* Create the queues used to hold Rx and Tx characters. */
\r
739 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );
\r
740 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );
\r
742 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
744 /* Not enough RAM to create queues!. */
\r
748 /* Initialise a few state variables. */
\r
749 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
750 pxControlRx.ulNextCharIndex = ( unsigned long ) 0;
\r
751 ucUSBConfig = ( unsigned char ) 0;
\r
752 eDriverState = eNOTHING;
\r
753 ucControlState = 0;
\r
754 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
757 /* HARDWARE SETUP */
\r
759 /* Set the PLL USB Divider */
\r
760 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
762 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
763 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
764 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
766 /* Setup the PIO for the USB pull up resistor. */
\r
767 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
768 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
771 /* Start without the pullup - this will get set at the end of this
\r
773 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
776 /* When using the USB debugger the peripheral registers do not always get
\r
777 set to the correct default values. To make sure set the relevant registers
\r
779 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
780 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
781 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
782 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
783 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;
\r
784 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;
\r
785 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
786 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
788 /* Enable the transceiver. */
\r
789 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
791 /* Enable the USB interrupts - other interrupts get enabled as the
\r
792 enumeration process progresses. */
\r
793 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
794 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
797 /* Wait a short while before making our presence known. */
\r
798 vTaskDelay( usbINIT_DELAY );
\r
799 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
801 /*-----------------------------------------------------------*/
\r
803 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
805 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
807 /* Cap the data length to that requested. */
\r
808 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
810 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
812 /* We are sending a descriptor. If the descriptor is an exact
\r
813 multiple of the FIFO length then it will have to be terminated
\r
814 with a NULL packet. Set the state to indicate this if
\r
816 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
818 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
822 /* Here we assume that the previous message has been sent. THERE IS NO
\r
823 BUFFER OVERFLOW PROTECTION HERE.
\r
825 Copy the data to send into the buffer as we cannot send it all at once
\r
826 (if it is greater than 8 bytes in length). */
\r
827 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
829 /* Reinitialise the buffer index so we start sending from the start of
\r
831 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
832 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
834 /* Send the first 8 bytes now. The rest will get sent in response to
\r
835 TXCOMP interrupts. */
\r
836 prvSendNextSegment();
\r
838 /*-----------------------------------------------------------*/
\r
840 static void prvSendNextSegment( void )
\r
842 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
844 /* Is there any data to send? */
\r
845 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
847 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
849 /* We can only send 8 bytes to the fifo at a time. */
\r
850 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
852 ulNextLength = usbFIFO_LENGTH;
\r
856 ulNextLength = ulLengthLeftToSend;
\r
859 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
861 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
863 vTaskDelay( usbSHORTEST_DELAY );
\r
866 /* Write the data to the FIFO. */
\r
867 while( ulNextLength > ( unsigned long ) 0 )
\r
869 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
872 pxControlTx.ulNextCharIndex++;
\r
875 /* Start the transmission. */
\r
876 portENTER_CRITICAL();
\r
878 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
879 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
880 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
882 portEXIT_CRITICAL();
\r
886 /* There is no data to send. If we were sending a descriptor and the
\r
887 descriptor was an exact multiple of the max packet size then we need
\r
888 to send a null to terminate the transmission. */
\r
889 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
892 eDriverState = eNOTHING;
\r