2 FreeRTOS V7.4.1 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not it can be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
76 USB Communications Device Class driver.
\r
77 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
78 interface. Control is through endpoint 0, device-to-host notification is
\r
79 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
80 bulk endpoints 1 and 2.
\r
82 - developed from original FreeRTOS HID example by Scott Miller
\r
83 - modified to support 3.2 GCC by najay
\r
86 /* Standard includes. */
\r
90 /* Demo board includes. */
\r
93 /* Scheduler includes. */
\r
94 #include "FreeRTOS.h"
\r
98 /* Demo app includes. */
\r
99 #include "USB-CDC.h"
\r
100 #include "descriptors.h"
\r
102 #define usbNO_BLOCK ( ( portTickType ) 0 )
\r
104 /* Reset all endpoints */
\r
105 static void prvResetEndPoints( void );
\r
107 /* Clear pull up resistor to detach device from host */
\r
108 static void vDetachUSBInterface( void );
\r
110 /* Set up interface and initialize variables */
\r
111 static void vInitUSBInterface( void );
\r
113 /* Handle control endpoint events. */
\r
114 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
116 /* Handle standard device requests. */
\r
117 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
119 /* Handle standard interface requests. */
\r
120 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
122 /* Handle endpoint requests. */
\r
123 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
125 /* Handle class interface requests. */
\r
126 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
128 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
129 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
131 /* Send next segment of data for the control transfer */
\r
132 static void prvSendNextSegment( void );
\r
134 /* Send stall - used to respond to unsupported requests */
\r
135 static void prvSendStall( void );
\r
137 /* Send a zero-length (null) packet */
\r
138 static void prvSendZLP( void );
\r
140 /* Handle requests for standard interface descriptors */
\r
141 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
143 /*------------------------------------------------------------*/
\r
145 /* File scope static variables */
\r
146 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
147 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
148 static eDRIVER_STATE eDriverState = eNOTHING;
\r
150 /* Incoming and outgoing control data structures */
\r
151 static xCONTROL_MESSAGE pxControlTx;
\r
152 static xCONTROL_MESSAGE pxControlRx;
\r
154 /* Queue holding pointers to pending messages */
\r
155 xQueueHandle xUSBInterruptQueue;
\r
157 /* Queues used to hold received characters, and characters waiting to be
\r
158 transmitted. Rx queue must be larger than FIFO size. */
\r
159 static xQueueHandle xRxCDC;
\r
160 static xQueueHandle xTxCDC;
\r
162 /* Line coding - 115,200 baud, N-8-1 */
\r
163 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
165 /* Status variables. */
\r
166 static unsigned char ucControlState;
\r
167 static unsigned int uiCurrentBank;
\r
170 /*------------------------------------------------------------*/
\r
173 void vUSBCDCTask( void *pvParameters )
\r
175 xISRStatus *pxMessage;
\r
176 unsigned long ulStatus;
\r
177 unsigned long ulRxBytes;
\r
178 unsigned char ucByte;
\r
179 portBASE_TYPE xByte;
\r
181 ( void ) pvParameters;
\r
183 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
184 portENTER_CRITICAL();
\r
185 vDetachUSBInterface();
\r
186 portEXIT_CRITICAL();
\r
188 vTaskDelay( portTICK_RATE_MS * 60 );
\r
190 /* Init USB interface */
\r
191 portENTER_CRITICAL();
\r
192 vInitUSBInterface();
\r
193 portEXIT_CRITICAL();
\r
195 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
199 /* Look for data coming from the ISR. */
\r
200 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
202 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
204 /* All endpoint 0 interrupts are handled here. */
\r
205 prvProcessEndPoint0Interrupt( pxMessage );
\r
208 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
210 /* End of bus reset - reset the endpoints and de-configure. */
\r
211 prvResetEndPoints();
\r
215 /* See if we're ready to send and receive data. */
\r
216 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
218 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
220 for( xByte = 0; xByte < 64; xByte++ )
\r
222 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
224 /* No data buffered to transmit. */
\r
228 /* Got a byte to transmit. */
\r
229 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
231 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
234 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
235 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
237 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
239 /* Only process FIFO if there's room to store it in the queue */
\r
240 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
242 while( ulRxBytes-- )
\r
244 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
245 xQueueSend( xRxCDC, &ucByte, 0 );
\r
248 /* Release the FIFO */
\r
249 portENTER_CRITICAL();
\r
251 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
252 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
253 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
255 portEXIT_CRITICAL();
\r
257 /* Re-enable endpoint 1's interrupts */
\r
258 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
260 /* Update the current bank in use */
\r
261 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
263 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
267 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
279 /*------------------------------------------------------------*/
\r
281 void vUSBSendByte( char cByte )
\r
283 /* Queue the byte to be sent. The USB task will send it. */
\r
284 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
286 /*------------------------------------------------------------*/
\r
288 static void prvSendZLP( void )
\r
290 unsigned long ulStatus;
\r
292 /* Wait until the FIFO is free - even though we are not going to use it.
\r
293 THERE IS NO TIMEOUT HERE! */
\r
294 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
296 vTaskDelay( usbSHORTEST_DELAY );
\r
299 portENTER_CRITICAL();
\r
301 /* Cancel any further pending data */
\r
302 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
304 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
305 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
306 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
307 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
309 portEXIT_CRITICAL();
\r
311 /*------------------------------------------------------------*/
\r
313 static void prvSendStall( void )
\r
315 unsigned long ulStatus;
\r
317 portENTER_CRITICAL();
\r
319 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
320 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
321 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
322 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
324 portEXIT_CRITICAL();
\r
326 /*------------------------------------------------------------*/
\r
328 static void prvResetEndPoints( void )
\r
330 unsigned long ulTemp;
\r
332 eDriverState = eJUST_RESET;
\r
333 ucControlState = 0;
\r
335 /* Reset all the end points. */
\r
336 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
337 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
339 /* Enable data to be sent and received. */
\r
340 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
342 /* Repair the configuration end point. */
\r
343 portENTER_CRITICAL();
\r
345 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
346 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
347 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
348 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
350 portEXIT_CRITICAL();
\r
351 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
353 /*------------------------------------------------------------*/
\r
355 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
357 static xUSB_REQUEST xRequest;
\r
358 unsigned long ulRxBytes;
\r
360 /* Get number of bytes received, if any */
\r
361 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
362 ulRxBytes &= usbRX_COUNT_MASK;
\r
364 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
366 /* We received a TX complete interrupt. What we do depends on
\r
367 what we sent to get this interrupt. */
\r
369 if( eDriverState == eJUST_GOT_CONFIG )
\r
371 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
372 are now at the end of the enumeration.
\r
374 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
375 Request for unsupported config should stall. */
\r
376 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
378 /* Set up endpoints */
\r
379 portENTER_CRITICAL();
\r
381 unsigned long ulTemp;
\r
383 /* Set endpoint 1 to bulk-out */
\r
384 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
385 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
386 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
387 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
388 /* Set endpoint 2 to bulk-in */
\r
389 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
390 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
391 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
392 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
393 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
394 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
395 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
396 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
397 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
399 portEXIT_CRITICAL();
\r
401 eDriverState = eREADY_TO_SEND;
\r
403 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
405 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
406 to the addressed state. */
\r
407 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
409 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
413 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
416 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
417 eDriverState = eNOTHING;
\r
421 /* The TXCOMP was not for any special type of transmission. See
\r
422 if there is any more data to send. */
\r
423 prvSendNextSegment();
\r
427 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
429 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
430 unsigned char ucBytesToGet;
\r
432 /* Got data. Cancel any outgoing data. */
\r
433 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
435 /* Determine how many bytes we need to receive. */
\r
436 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
437 if( ucBytesToGet > ulRxBytes )
\r
439 ucBytesToGet = ulRxBytes;
\r
442 /* If we're not expecting any data, it's an ack - just quit now. */
\r
443 if( !ucBytesToGet )
\r
448 /* Get the required data and update the index. */
\r
449 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
450 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
453 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
455 /* Received a SETUP packet. May be followed by data packets. */
\r
457 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
459 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
461 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
462 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
464 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
465 xRequest.usValue <<= 8;
\r
466 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
468 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
469 xRequest.usIndex <<= 8;
\r
470 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
472 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
473 xRequest.usLength <<= 8;
\r
474 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
476 pxControlRx.ulNextCharIndex = 0;
\r
477 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
479 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
481 /* Too big! No space for control data, stall and abort. */
\r
486 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
490 /* We're sending the data, don't wait for any. */
\r
491 pxControlRx.ulTotalDataLength = 0;
\r
496 /* See if we've got a pending request and all its associated data ready */
\r
497 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
498 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
500 unsigned char ucRequest;
\r
502 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
503 generate a zero based request selection. This is just done to
\r
504 break up the requests into subsections for clarity. The
\r
505 alternative would be to have more huge switch statement that would
\r
506 be difficult to optimise. */
\r
507 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
508 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
510 switch( ucRequest )
\r
512 case usbSTANDARD_DEVICE_REQUEST:
\r
513 /* Standard Device request */
\r
514 prvHandleStandardDeviceRequest( &xRequest );
\r
517 case usbSTANDARD_INTERFACE_REQUEST:
\r
518 /* Standard Interface request */
\r
519 prvHandleStandardInterfaceRequest( &xRequest );
\r
522 case usbSTANDARD_END_POINT_REQUEST:
\r
523 /* Standard Endpoint request */
\r
524 prvHandleStandardEndPointRequest( &xRequest );
\r
527 case usbCLASS_INTERFACE_REQUEST:
\r
528 /* Class Interface request */
\r
529 prvHandleClassInterfaceRequest( &xRequest );
\r
532 default: /* This is not something we want to respond to. */
\r
537 /*------------------------------------------------------------*/
\r
539 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
541 /* The type is in the high byte. Return whatever has been requested. */
\r
542 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
544 case usbDESCRIPTOR_TYPE_DEVICE:
\r
545 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
548 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
549 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
552 case usbDESCRIPTOR_TYPE_STRING:
\r
554 /* The index to the string descriptor is the lower byte. */
\r
555 switch( pxRequest->usValue & 0xff )
\r
557 case usbLANGUAGE_STRING:
\r
558 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
561 case usbMANUFACTURER_STRING:
\r
562 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
565 case usbPRODUCT_STRING:
\r
566 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
569 case usbCONFIGURATION_STRING:
\r
570 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
573 case usbINTERFACE_STRING:
\r
574 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
588 /*------------------------------------------------------------*/
\r
590 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
592 unsigned short usStatus = 0;
\r
594 switch( pxRequest->ucRequest )
\r
596 case usbGET_STATUS_REQUEST:
\r
597 /* Just send two byte dummy status. */
\r
598 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
601 case usbGET_DESCRIPTOR_REQUEST:
\r
602 /* Send device descriptor */
\r
603 prvGetStandardDeviceDescriptor( pxRequest );
\r
606 case usbGET_CONFIGURATION_REQUEST:
\r
607 /* Send selected device configuration */
\r
608 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
611 case usbSET_FEATURE_REQUEST:
\r
615 case usbSET_ADDRESS_REQUEST:
\r
616 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
618 eDriverState = eJUST_GOT_ADDRESS;
\r
619 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
622 case usbSET_CONFIGURATION_REQUEST:
\r
623 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
624 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
625 eDriverState = eJUST_GOT_CONFIG;
\r
630 /* Any unsupported request results in a STALL response. */
\r
635 /*------------------------------------------------------------*/
\r
637 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
639 switch( pxRequest->ucRequest )
\r
641 case usbSEND_ENCAPSULATED_COMMAND:
\r
645 case usbGET_ENCAPSULATED_RESPONSE:
\r
649 case usbSET_LINE_CODING:
\r
650 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
652 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
655 case usbGET_LINE_CODING:
\r
656 /* Get line coding */
\r
657 prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
660 case usbSET_CONTROL_LINE_STATE:
\r
661 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
663 ucControlState = pxRequest->usValue;
\r
671 /*------------------------------------------------------------*/
\r
673 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
675 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
682 /*-----------------------------------------------------------*/
\r
684 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
686 unsigned short usStatus = 0;
\r
688 switch( pxRequest->ucRequest )
\r
690 case usbGET_STATUS_REQUEST:
\r
691 /* Send dummy 2 bytes. */
\r
692 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
695 case usbGET_DESCRIPTOR_REQUEST:
\r
696 prvGetStandardInterfaceDescriptor( pxRequest );
\r
699 /* This minimal implementation does not respond to these. */
\r
700 case usbGET_INTERFACE_REQUEST:
\r
701 case usbSET_FEATURE_REQUEST:
\r
702 case usbSET_INTERFACE_REQUEST:
\r
709 /*-----------------------------------------------------------*/
\r
711 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
713 switch( pxRequest->ucRequest )
\r
715 /* This minimal implementation does not expect to respond to these. */
\r
716 case usbGET_STATUS_REQUEST:
\r
717 case usbCLEAR_FEATURE_REQUEST:
\r
718 case usbSET_FEATURE_REQUEST:
\r
725 /*-----------------------------------------------------------*/
\r
727 static void vDetachUSBInterface( void)
\r
729 /* Setup the PIO for the USB pull up resistor. */
\r
730 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
731 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
734 /* Disable pull up */
\r
735 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
737 /*-----------------------------------------------------------*/
\r
739 static void vInitUSBInterface( void )
\r
741 extern void ( vUSB_ISR_Wrapper )( void );
\r
743 /* Create the queue used to communicate between the USB ISR and task. */
\r
744 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
746 /* Create the queues used to hold Rx and Tx characters. */
\r
747 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );
\r
748 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );
\r
750 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
752 /* Not enough RAM to create queues!. */
\r
756 /* Initialise a few state variables. */
\r
757 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
758 pxControlRx.ulNextCharIndex = ( unsigned long ) 0;
\r
759 ucUSBConfig = ( unsigned char ) 0;
\r
760 eDriverState = eNOTHING;
\r
761 ucControlState = 0;
\r
762 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
765 /* HARDWARE SETUP */
\r
767 /* Set the PLL USB Divider */
\r
768 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
770 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
771 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
772 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
774 /* Setup the PIO for the USB pull up resistor. */
\r
775 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
776 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
779 /* Start without the pullup - this will get set at the end of this
\r
781 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
784 /* When using the USB debugger the peripheral registers do not always get
\r
785 set to the correct default values. To make sure set the relevant registers
\r
787 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
788 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
789 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
790 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
791 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;
\r
792 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;
\r
793 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
794 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
796 /* Enable the transceiver. */
\r
797 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
799 /* Enable the USB interrupts - other interrupts get enabled as the
\r
800 enumeration process progresses. */
\r
801 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
802 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
805 /* Wait a short while before making our presence known. */
\r
806 vTaskDelay( usbINIT_DELAY );
\r
807 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
809 /*-----------------------------------------------------------*/
\r
811 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
813 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
815 /* Cap the data length to that requested. */
\r
816 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
818 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
820 /* We are sending a descriptor. If the descriptor is an exact
\r
821 multiple of the FIFO length then it will have to be terminated
\r
822 with a NULL packet. Set the state to indicate this if
\r
824 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
826 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
830 /* Here we assume that the previous message has been sent. THERE IS NO
\r
831 BUFFER OVERFLOW PROTECTION HERE.
\r
833 Copy the data to send into the buffer as we cannot send it all at once
\r
834 (if it is greater than 8 bytes in length). */
\r
835 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
837 /* Reinitialise the buffer index so we start sending from the start of
\r
839 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
840 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
842 /* Send the first 8 bytes now. The rest will get sent in response to
\r
843 TXCOMP interrupts. */
\r
844 prvSendNextSegment();
\r
846 /*-----------------------------------------------------------*/
\r
848 static void prvSendNextSegment( void )
\r
850 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
852 /* Is there any data to send? */
\r
853 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
855 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
857 /* We can only send 8 bytes to the fifo at a time. */
\r
858 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
860 ulNextLength = usbFIFO_LENGTH;
\r
864 ulNextLength = ulLengthLeftToSend;
\r
867 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
869 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
871 vTaskDelay( usbSHORTEST_DELAY );
\r
874 /* Write the data to the FIFO. */
\r
875 while( ulNextLength > ( unsigned long ) 0 )
\r
877 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
880 pxControlTx.ulNextCharIndex++;
\r
883 /* Start the transmission. */
\r
884 portENTER_CRITICAL();
\r
886 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
887 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
888 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
890 portEXIT_CRITICAL();
\r
894 /* There is no data to send. If we were sending a descriptor and the
\r
895 descriptor was an exact multiple of the max packet size then we need
\r
896 to send a null to terminate the transmission. */
\r
897 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
900 eDriverState = eNOTHING;
\r