2 FreeRTOS V8.2.0rc1 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
13 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
14 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
15 >>! obliged to provide the source code for proprietary components !<<
\r
16 >>! outside of the FreeRTOS kernel. !<<
\r
18 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
20 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
21 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * Having a problem? Start by reading the FAQ "My application does *
\r
28 * not run, what could be wrong?". Have you defined configASSERT()? *
\r
30 * http://www.FreeRTOS.org/FAQHelp.html *
\r
32 ***************************************************************************
\r
34 ***************************************************************************
\r
36 * FreeRTOS provides completely free yet professionally developed, *
\r
37 * robust, strictly quality controlled, supported, and cross *
\r
38 * platform software that is more than just the market leader, it *
\r
39 * is the industry's de facto standard. *
\r
41 * Help yourself get started quickly while simultaneously helping *
\r
42 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
43 * tutorial book, reference manual, or both: *
\r
44 * http://www.FreeRTOS.org/Documentation *
\r
46 ***************************************************************************
\r
48 ***************************************************************************
\r
50 * Investing in training allows your team to be as productive as *
\r
51 * possible as early as possible, lowering your overall development *
\r
52 * cost, and enabling you to bring a more robust product to market *
\r
53 * earlier than would otherwise be possible. Richard Barry is both *
\r
54 * the architect and key author of FreeRTOS, and so also the world's *
\r
55 * leading authority on what is the world's most popular real time *
\r
56 * kernel for deeply embedded MCU designs. Obtaining your training *
\r
57 * from Richard ensures your team will gain directly from his in-depth *
\r
58 * product knowledge and years of usage experience. Contact Real Time *
\r
59 * Engineers Ltd to enquire about the FreeRTOS Masterclass, presented *
\r
60 * by Richard Barry: http://www.FreeRTOS.org/contact
\r
62 ***************************************************************************
\r
64 ***************************************************************************
\r
66 * You are receiving this top quality software for free. Please play *
\r
67 * fair and reciprocate by reporting any suspected issues and *
\r
68 * participating in the community forum: *
\r
69 * http://www.FreeRTOS.org/support *
\r
73 ***************************************************************************
\r
75 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
76 license and Real Time Engineers Ltd. contact details.
\r
78 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
79 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
80 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
82 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
83 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
85 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
86 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
87 licenses offer ticketed support, indemnification and commercial middleware.
\r
89 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
90 engineered and independently SIL3 certified version for use in safety and
\r
91 mission critical applications that require provable dependability.
\r
97 USB Communications Device Class driver.
\r
98 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
99 interface. Control is through endpoint 0, device-to-host notification is
\r
100 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
101 bulk endpoints 1 and 2.
\r
103 - developed from original FreeRTOS HID example by Scott Miller
\r
104 - modified to support 3.2 GCC by najay
\r
107 /* Standard includes. */
\r
108 #include <string.h>
\r
111 /* Demo board includes. */
\r
114 /* Scheduler includes. */
\r
115 #include "FreeRTOS.h"
\r
119 /* Demo app includes. */
\r
120 #include "USB-CDC.h"
\r
121 #include "descriptors.h"
\r
123 #define usbNO_BLOCK ( ( TickType_t ) 0 )
\r
125 /* Reset all endpoints */
\r
126 static void prvResetEndPoints( void );
\r
128 /* Clear pull up resistor to detach device from host */
\r
129 static void vDetachUSBInterface( void );
\r
131 /* Set up interface and initialize variables */
\r
132 static void vInitUSBInterface( void );
\r
134 /* Handle control endpoint events. */
\r
135 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
137 /* Handle standard device requests. */
\r
138 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
140 /* Handle standard interface requests. */
\r
141 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
143 /* Handle endpoint requests. */
\r
144 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
146 /* Handle class interface requests. */
\r
147 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
149 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
150 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
152 /* Send next segment of data for the control transfer */
\r
153 static void prvSendNextSegment( void );
\r
155 /* Send stall - used to respond to unsupported requests */
\r
156 static void prvSendStall( void );
\r
158 /* Send a zero-length (null) packet */
\r
159 static void prvSendZLP( void );
\r
161 /* Handle requests for standard interface descriptors */
\r
162 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
164 /*------------------------------------------------------------*/
\r
166 /* File scope static variables */
\r
167 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
168 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
169 static eDRIVER_STATE eDriverState = eNOTHING;
\r
171 /* Incoming and outgoing control data structures */
\r
172 static xCONTROL_MESSAGE pxControlTx;
\r
173 static xCONTROL_MESSAGE pxControlRx;
\r
175 /* Queue holding pointers to pending messages */
\r
176 QueueHandle_t xUSBInterruptQueue;
\r
178 /* Queues used to hold received characters, and characters waiting to be
\r
179 transmitted. Rx queue must be larger than FIFO size. */
\r
180 static QueueHandle_t xRxCDC;
\r
181 static QueueHandle_t xTxCDC;
\r
183 /* Line coding - 115,200 baud, N-8-1 */
\r
184 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
186 /* Status variables. */
\r
187 static unsigned char ucControlState;
\r
188 static unsigned int uiCurrentBank;
\r
191 /*------------------------------------------------------------*/
\r
194 void vUSBCDCTask( void *pvParameters )
\r
196 xISRStatus *pxMessage;
\r
197 unsigned long ulStatus;
\r
198 unsigned long ulRxBytes;
\r
199 unsigned char ucByte;
\r
200 portBASE_TYPE xByte;
\r
202 ( void ) pvParameters;
\r
204 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
205 portENTER_CRITICAL();
\r
206 vDetachUSBInterface();
\r
207 portEXIT_CRITICAL();
\r
209 vTaskDelay( portTICK_PERIOD_MS * 60 );
\r
211 /* Init USB interface */
\r
212 portENTER_CRITICAL();
\r
213 vInitUSBInterface();
\r
214 portEXIT_CRITICAL();
\r
216 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
220 /* Look for data coming from the ISR. */
\r
221 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
223 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
225 /* All endpoint 0 interrupts are handled here. */
\r
226 prvProcessEndPoint0Interrupt( pxMessage );
\r
229 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
231 /* End of bus reset - reset the endpoints and de-configure. */
\r
232 prvResetEndPoints();
\r
236 /* See if we're ready to send and receive data. */
\r
237 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
239 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
241 for( xByte = 0; xByte < 64; xByte++ )
\r
243 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
245 /* No data buffered to transmit. */
\r
249 /* Got a byte to transmit. */
\r
250 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
252 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
255 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
256 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
258 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
260 /* Only process FIFO if there's room to store it in the queue */
\r
261 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
263 while( ulRxBytes-- )
\r
265 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
266 xQueueSend( xRxCDC, &ucByte, 0 );
\r
269 /* Release the FIFO */
\r
270 portENTER_CRITICAL();
\r
272 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
273 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
274 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
276 portEXIT_CRITICAL();
\r
278 /* Re-enable endpoint 1's interrupts */
\r
279 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
281 /* Update the current bank in use */
\r
282 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
284 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
288 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
300 /*------------------------------------------------------------*/
\r
302 void vUSBSendByte( char cByte )
\r
304 /* Queue the byte to be sent. The USB task will send it. */
\r
305 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
307 /*------------------------------------------------------------*/
\r
309 static void prvSendZLP( void )
\r
311 unsigned long ulStatus;
\r
313 /* Wait until the FIFO is free - even though we are not going to use it.
\r
314 THERE IS NO TIMEOUT HERE! */
\r
315 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
317 vTaskDelay( usbSHORTEST_DELAY );
\r
320 portENTER_CRITICAL();
\r
322 /* Cancel any further pending data */
\r
323 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
325 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
326 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
327 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
328 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
330 portEXIT_CRITICAL();
\r
332 /*------------------------------------------------------------*/
\r
334 static void prvSendStall( void )
\r
336 unsigned long ulStatus;
\r
338 portENTER_CRITICAL();
\r
340 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
341 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
342 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
343 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
345 portEXIT_CRITICAL();
\r
347 /*------------------------------------------------------------*/
\r
349 static void prvResetEndPoints( void )
\r
351 unsigned long ulTemp;
\r
353 eDriverState = eJUST_RESET;
\r
354 ucControlState = 0;
\r
356 /* Reset all the end points. */
\r
357 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
358 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
360 /* Enable data to be sent and received. */
\r
361 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
363 /* Repair the configuration end point. */
\r
364 portENTER_CRITICAL();
\r
366 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
367 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
368 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
369 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
371 portEXIT_CRITICAL();
\r
372 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
374 /*------------------------------------------------------------*/
\r
376 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
378 static xUSB_REQUEST xRequest;
\r
379 unsigned long ulRxBytes;
\r
381 /* Get number of bytes received, if any */
\r
382 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
383 ulRxBytes &= usbRX_COUNT_MASK;
\r
385 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
387 /* We received a TX complete interrupt. What we do depends on
\r
388 what we sent to get this interrupt. */
\r
390 if( eDriverState == eJUST_GOT_CONFIG )
\r
392 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
393 are now at the end of the enumeration.
\r
395 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
396 Request for unsupported config should stall. */
\r
397 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
399 /* Set up endpoints */
\r
400 portENTER_CRITICAL();
\r
402 unsigned long ulTemp;
\r
404 /* Set endpoint 1 to bulk-out */
\r
405 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
406 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
407 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
408 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
409 /* Set endpoint 2 to bulk-in */
\r
410 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
411 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
412 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
413 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
414 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
415 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
416 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
417 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
418 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
420 portEXIT_CRITICAL();
\r
422 eDriverState = eREADY_TO_SEND;
\r
424 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
426 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
427 to the addressed state. */
\r
428 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
430 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
434 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
437 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
438 eDriverState = eNOTHING;
\r
442 /* The TXCOMP was not for any special type of transmission. See
\r
443 if there is any more data to send. */
\r
444 prvSendNextSegment();
\r
448 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
450 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
451 unsigned char ucBytesToGet;
\r
453 /* Got data. Cancel any outgoing data. */
\r
454 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
456 /* Determine how many bytes we need to receive. */
\r
457 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
458 if( ucBytesToGet > ulRxBytes )
\r
460 ucBytesToGet = ulRxBytes;
\r
463 /* If we're not expecting any data, it's an ack - just quit now. */
\r
464 if( !ucBytesToGet )
\r
469 /* Get the required data and update the index. */
\r
470 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
471 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
474 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
476 /* Received a SETUP packet. May be followed by data packets. */
\r
478 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
480 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
482 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
483 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
485 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
486 xRequest.usValue <<= 8;
\r
487 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
489 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
490 xRequest.usIndex <<= 8;
\r
491 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
493 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
494 xRequest.usLength <<= 8;
\r
495 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
497 pxControlRx.ulNextCharIndex = 0;
\r
498 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
500 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
502 /* Too big! No space for control data, stall and abort. */
\r
507 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
511 /* We're sending the data, don't wait for any. */
\r
512 pxControlRx.ulTotalDataLength = 0;
\r
517 /* See if we've got a pending request and all its associated data ready */
\r
518 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
519 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
521 unsigned char ucRequest;
\r
523 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
524 generate a zero based request selection. This is just done to
\r
525 break up the requests into subsections for clarity. The
\r
526 alternative would be to have more huge switch statement that would
\r
527 be difficult to optimise. */
\r
528 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
529 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
531 switch( ucRequest )
\r
533 case usbSTANDARD_DEVICE_REQUEST:
\r
534 /* Standard Device request */
\r
535 prvHandleStandardDeviceRequest( &xRequest );
\r
538 case usbSTANDARD_INTERFACE_REQUEST:
\r
539 /* Standard Interface request */
\r
540 prvHandleStandardInterfaceRequest( &xRequest );
\r
543 case usbSTANDARD_END_POINT_REQUEST:
\r
544 /* Standard Endpoint request */
\r
545 prvHandleStandardEndPointRequest( &xRequest );
\r
548 case usbCLASS_INTERFACE_REQUEST:
\r
549 /* Class Interface request */
\r
550 prvHandleClassInterfaceRequest( &xRequest );
\r
553 default: /* This is not something we want to respond to. */
\r
558 /*------------------------------------------------------------*/
\r
560 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
562 /* The type is in the high byte. Return whatever has been requested. */
\r
563 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
565 case usbDESCRIPTOR_TYPE_DEVICE:
\r
566 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
569 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
570 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
573 case usbDESCRIPTOR_TYPE_STRING:
\r
575 /* The index to the string descriptor is the lower byte. */
\r
576 switch( pxRequest->usValue & 0xff )
\r
578 case usbLANGUAGE_STRING:
\r
579 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
582 case usbMANUFACTURER_STRING:
\r
583 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
586 case usbPRODUCT_STRING:
\r
587 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
590 case usbCONFIGURATION_STRING:
\r
591 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
594 case usbINTERFACE_STRING:
\r
595 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
609 /*------------------------------------------------------------*/
\r
611 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
613 unsigned short usStatus = 0;
\r
615 switch( pxRequest->ucRequest )
\r
617 case usbGET_STATUS_REQUEST:
\r
618 /* Just send two byte dummy status. */
\r
619 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
622 case usbGET_DESCRIPTOR_REQUEST:
\r
623 /* Send device descriptor */
\r
624 prvGetStandardDeviceDescriptor( pxRequest );
\r
627 case usbGET_CONFIGURATION_REQUEST:
\r
628 /* Send selected device configuration */
\r
629 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
632 case usbSET_FEATURE_REQUEST:
\r
636 case usbSET_ADDRESS_REQUEST:
\r
637 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
639 eDriverState = eJUST_GOT_ADDRESS;
\r
640 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
643 case usbSET_CONFIGURATION_REQUEST:
\r
644 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
645 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
646 eDriverState = eJUST_GOT_CONFIG;
\r
651 /* Any unsupported request results in a STALL response. */
\r
656 /*------------------------------------------------------------*/
\r
658 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
660 switch( pxRequest->ucRequest )
\r
662 case usbSEND_ENCAPSULATED_COMMAND:
\r
666 case usbGET_ENCAPSULATED_RESPONSE:
\r
670 case usbSET_LINE_CODING:
\r
671 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
673 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
676 case usbGET_LINE_CODING:
\r
677 /* Get line coding */
\r
678 prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
681 case usbSET_CONTROL_LINE_STATE:
\r
682 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
684 ucControlState = pxRequest->usValue;
\r
692 /*------------------------------------------------------------*/
\r
694 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
696 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
703 /*-----------------------------------------------------------*/
\r
705 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
707 unsigned short usStatus = 0;
\r
709 switch( pxRequest->ucRequest )
\r
711 case usbGET_STATUS_REQUEST:
\r
712 /* Send dummy 2 bytes. */
\r
713 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
716 case usbGET_DESCRIPTOR_REQUEST:
\r
717 prvGetStandardInterfaceDescriptor( pxRequest );
\r
720 /* This minimal implementation does not respond to these. */
\r
721 case usbGET_INTERFACE_REQUEST:
\r
722 case usbSET_FEATURE_REQUEST:
\r
723 case usbSET_INTERFACE_REQUEST:
\r
730 /*-----------------------------------------------------------*/
\r
732 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
734 switch( pxRequest->ucRequest )
\r
736 /* This minimal implementation does not expect to respond to these. */
\r
737 case usbGET_STATUS_REQUEST:
\r
738 case usbCLEAR_FEATURE_REQUEST:
\r
739 case usbSET_FEATURE_REQUEST:
\r
746 /*-----------------------------------------------------------*/
\r
748 static void vDetachUSBInterface( void)
\r
750 /* Setup the PIO for the USB pull up resistor. */
\r
751 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
752 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
755 /* Disable pull up */
\r
756 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
758 /*-----------------------------------------------------------*/
\r
760 static void vInitUSBInterface( void )
\r
762 extern void ( vUSB_ISR_Wrapper )( void );
\r
764 /* Create the queue used to communicate between the USB ISR and task. */
\r
765 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
767 /* Create the queues used to hold Rx and Tx characters. */
\r
768 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );
\r
769 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );
\r
771 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
773 /* Not enough RAM to create queues!. */
\r
777 /* Initialise a few state variables. */
\r
778 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
779 pxControlRx.ulNextCharIndex = ( unsigned long ) 0;
\r
780 ucUSBConfig = ( unsigned char ) 0;
\r
781 eDriverState = eNOTHING;
\r
782 ucControlState = 0;
\r
783 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
786 /* HARDWARE SETUP */
\r
788 /* Set the PLL USB Divider */
\r
789 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
791 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
792 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
793 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
795 /* Setup the PIO for the USB pull up resistor. */
\r
796 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
797 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
800 /* Start without the pullup - this will get set at the end of this
\r
802 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
805 /* When using the USB debugger the peripheral registers do not always get
\r
806 set to the correct default values. To make sure set the relevant registers
\r
808 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
809 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
810 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
811 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
812 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;
\r
813 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;
\r
814 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
815 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
817 /* Enable the transceiver. */
\r
818 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
820 /* Enable the USB interrupts - other interrupts get enabled as the
\r
821 enumeration process progresses. */
\r
822 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
823 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
826 /* Wait a short while before making our presence known. */
\r
827 vTaskDelay( usbINIT_DELAY );
\r
828 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
830 /*-----------------------------------------------------------*/
\r
832 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
834 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
836 /* Cap the data length to that requested. */
\r
837 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
839 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
841 /* We are sending a descriptor. If the descriptor is an exact
\r
842 multiple of the FIFO length then it will have to be terminated
\r
843 with a NULL packet. Set the state to indicate this if
\r
845 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
847 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
851 /* Here we assume that the previous message has been sent. THERE IS NO
\r
852 BUFFER OVERFLOW PROTECTION HERE.
\r
854 Copy the data to send into the buffer as we cannot send it all at once
\r
855 (if it is greater than 8 bytes in length). */
\r
856 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
858 /* Reinitialise the buffer index so we start sending from the start of
\r
860 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
861 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
863 /* Send the first 8 bytes now. The rest will get sent in response to
\r
864 TXCOMP interrupts. */
\r
865 prvSendNextSegment();
\r
867 /*-----------------------------------------------------------*/
\r
869 static void prvSendNextSegment( void )
\r
871 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
873 /* Is there any data to send? */
\r
874 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
876 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
878 /* We can only send 8 bytes to the fifo at a time. */
\r
879 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
881 ulNextLength = usbFIFO_LENGTH;
\r
885 ulNextLength = ulLengthLeftToSend;
\r
888 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
890 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
892 vTaskDelay( usbSHORTEST_DELAY );
\r
895 /* Write the data to the FIFO. */
\r
896 while( ulNextLength > ( unsigned long ) 0 )
\r
898 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
901 pxControlTx.ulNextCharIndex++;
\r
904 /* Start the transmission. */
\r
905 portENTER_CRITICAL();
\r
907 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
908 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
909 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
911 portEXIT_CRITICAL();
\r
915 /* There is no data to send. If we were sending a descriptor and the
\r
916 descriptor was an exact multiple of the max packet size then we need
\r
917 to send a null to terminate the transmission. */
\r
918 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
921 eDriverState = eNOTHING;
\r