2 FreeRTOS V9.0.0rc2 - Copyright (C) 2016 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 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
71 USB Communications Device Class driver.
\r
72 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
73 interface. Control is through endpoint 0, device-to-host notification is
\r
74 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
75 bulk endpoints 1 and 2.
\r
77 - developed from original FreeRTOS HID example by Scott Miller
\r
78 - modified to support 3.2 GCC by najay
\r
81 /* Standard includes. */
\r
85 /* Demo board includes. */
\r
88 /* Scheduler includes. */
\r
89 #include "FreeRTOS.h"
\r
93 /* Demo app includes. */
\r
94 #include "USB-CDC.h"
\r
95 #include "descriptors.h"
\r
97 #define usbNO_BLOCK ( ( TickType_t ) 0 )
\r
99 /* Reset all endpoints */
\r
100 static void prvResetEndPoints( void );
\r
102 /* Clear pull up resistor to detach device from host */
\r
103 static void vDetachUSBInterface( void );
\r
105 /* Set up interface and initialize variables */
\r
106 static void vInitUSBInterface( void );
\r
108 /* Handle control endpoint events. */
\r
109 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
111 /* Handle standard device requests. */
\r
112 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
114 /* Handle standard interface requests. */
\r
115 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
117 /* Handle endpoint requests. */
\r
118 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
120 /* Handle class interface requests. */
\r
121 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
123 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
124 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
126 /* Send next segment of data for the control transfer */
\r
127 static void prvSendNextSegment( void );
\r
129 /* Send stall - used to respond to unsupported requests */
\r
130 static void prvSendStall( void );
\r
132 /* Send a zero-length (null) packet */
\r
133 static void prvSendZLP( void );
\r
135 /* Handle requests for standard interface descriptors */
\r
136 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
138 /*------------------------------------------------------------*/
\r
140 /* File scope static variables */
\r
141 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
142 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
143 static eDRIVER_STATE eDriverState = eNOTHING;
\r
145 /* Incoming and outgoing control data structures */
\r
146 static xCONTROL_MESSAGE pxControlTx;
\r
147 static xCONTROL_MESSAGE pxControlRx;
\r
149 /* Queue holding pointers to pending messages */
\r
150 QueueHandle_t xUSBInterruptQueue;
\r
152 /* Queues used to hold received characters, and characters waiting to be
\r
153 transmitted. Rx queue must be larger than FIFO size. */
\r
154 static QueueHandle_t xRxCDC;
\r
155 static QueueHandle_t xTxCDC;
\r
157 /* Line coding - 115,200 baud, N-8-1 */
\r
158 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
160 /* Status variables. */
\r
161 static unsigned char ucControlState;
\r
162 static unsigned int uiCurrentBank;
\r
165 /*------------------------------------------------------------*/
\r
168 void vUSBCDCTask( void *pvParameters )
\r
170 xISRStatus *pxMessage;
\r
171 unsigned long ulStatus;
\r
172 unsigned long ulRxBytes;
\r
173 unsigned char ucByte;
\r
174 portBASE_TYPE xByte;
\r
176 ( void ) pvParameters;
\r
178 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
179 portENTER_CRITICAL();
\r
180 vDetachUSBInterface();
\r
181 portEXIT_CRITICAL();
\r
183 vTaskDelay( portTICK_PERIOD_MS * 60 );
\r
185 /* Init USB interface */
\r
186 portENTER_CRITICAL();
\r
187 vInitUSBInterface();
\r
188 portEXIT_CRITICAL();
\r
190 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
194 /* Look for data coming from the ISR. */
\r
195 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
197 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
199 /* All endpoint 0 interrupts are handled here. */
\r
200 prvProcessEndPoint0Interrupt( pxMessage );
\r
203 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
205 /* End of bus reset - reset the endpoints and de-configure. */
\r
206 prvResetEndPoints();
\r
210 /* See if we're ready to send and receive data. */
\r
211 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
213 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
215 for( xByte = 0; xByte < 64; xByte++ )
\r
217 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
219 /* No data buffered to transmit. */
\r
223 /* Got a byte to transmit. */
\r
224 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
226 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
229 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
230 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
232 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
234 /* Only process FIFO if there's room to store it in the queue */
\r
235 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
237 while( ulRxBytes-- )
\r
239 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
240 xQueueSend( xRxCDC, &ucByte, 0 );
\r
243 /* Release the FIFO */
\r
244 portENTER_CRITICAL();
\r
246 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
247 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
248 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
250 portEXIT_CRITICAL();
\r
252 /* Re-enable endpoint 1's interrupts */
\r
253 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
255 /* Update the current bank in use */
\r
256 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
258 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
262 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
274 /*------------------------------------------------------------*/
\r
276 void vUSBSendByte( char cByte )
\r
278 /* Queue the byte to be sent. The USB task will send it. */
\r
279 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
281 /*------------------------------------------------------------*/
\r
283 static void prvSendZLP( void )
\r
285 unsigned long ulStatus;
\r
287 /* Wait until the FIFO is free - even though we are not going to use it.
\r
288 THERE IS NO TIMEOUT HERE! */
\r
289 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
291 vTaskDelay( usbSHORTEST_DELAY );
\r
294 portENTER_CRITICAL();
\r
296 /* Cancel any further pending data */
\r
297 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
299 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
300 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
301 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
302 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
304 portEXIT_CRITICAL();
\r
306 /*------------------------------------------------------------*/
\r
308 static void prvSendStall( void )
\r
310 unsigned long ulStatus;
\r
312 portENTER_CRITICAL();
\r
314 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
315 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
316 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
317 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
319 portEXIT_CRITICAL();
\r
321 /*------------------------------------------------------------*/
\r
323 static void prvResetEndPoints( void )
\r
325 unsigned long ulTemp;
\r
327 eDriverState = eJUST_RESET;
\r
328 ucControlState = 0;
\r
330 /* Reset all the end points. */
\r
331 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
332 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
334 /* Enable data to be sent and received. */
\r
335 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
337 /* Repair the configuration end point. */
\r
338 portENTER_CRITICAL();
\r
340 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
341 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
342 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
343 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
345 portEXIT_CRITICAL();
\r
346 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
348 /*------------------------------------------------------------*/
\r
350 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
352 static xUSB_REQUEST xRequest;
\r
353 unsigned long ulRxBytes;
\r
355 /* Get number of bytes received, if any */
\r
356 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
357 ulRxBytes &= usbRX_COUNT_MASK;
\r
359 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
361 /* We received a TX complete interrupt. What we do depends on
\r
362 what we sent to get this interrupt. */
\r
364 if( eDriverState == eJUST_GOT_CONFIG )
\r
366 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
367 are now at the end of the enumeration.
\r
369 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
370 Request for unsupported config should stall. */
\r
371 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
373 /* Set up endpoints */
\r
374 portENTER_CRITICAL();
\r
376 unsigned long ulTemp;
\r
378 /* Set endpoint 1 to bulk-out */
\r
379 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
380 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
381 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
382 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
383 /* Set endpoint 2 to bulk-in */
\r
384 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
385 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
386 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
387 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
388 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
389 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
390 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
391 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
392 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
394 portEXIT_CRITICAL();
\r
396 eDriverState = eREADY_TO_SEND;
\r
398 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
400 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
401 to the addressed state. */
\r
402 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
404 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
408 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
411 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
412 eDriverState = eNOTHING;
\r
416 /* The TXCOMP was not for any special type of transmission. See
\r
417 if there is any more data to send. */
\r
418 prvSendNextSegment();
\r
422 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
424 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
425 unsigned char ucBytesToGet;
\r
427 /* Got data. Cancel any outgoing data. */
\r
428 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
430 /* Determine how many bytes we need to receive. */
\r
431 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
432 if( ucBytesToGet > ulRxBytes )
\r
434 ucBytesToGet = ulRxBytes;
\r
437 /* If we're not expecting any data, it's an ack - just quit now. */
\r
438 if( !ucBytesToGet )
\r
443 /* Get the required data and update the index. */
\r
444 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
445 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
448 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
450 /* Received a SETUP packet. May be followed by data packets. */
\r
452 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
454 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
456 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
457 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
459 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
460 xRequest.usValue <<= 8;
\r
461 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
463 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
464 xRequest.usIndex <<= 8;
\r
465 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
467 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
468 xRequest.usLength <<= 8;
\r
469 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
471 pxControlRx.ulNextCharIndex = 0;
\r
472 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
474 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
476 /* Too big! No space for control data, stall and abort. */
\r
481 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
485 /* We're sending the data, don't wait for any. */
\r
486 pxControlRx.ulTotalDataLength = 0;
\r
491 /* See if we've got a pending request and all its associated data ready */
\r
492 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
493 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
495 unsigned char ucRequest;
\r
497 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
498 generate a zero based request selection. This is just done to
\r
499 break up the requests into subsections for clarity. The
\r
500 alternative would be to have more huge switch statement that would
\r
501 be difficult to optimise. */
\r
502 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
503 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
505 switch( ucRequest )
\r
507 case usbSTANDARD_DEVICE_REQUEST:
\r
508 /* Standard Device request */
\r
509 prvHandleStandardDeviceRequest( &xRequest );
\r
512 case usbSTANDARD_INTERFACE_REQUEST:
\r
513 /* Standard Interface request */
\r
514 prvHandleStandardInterfaceRequest( &xRequest );
\r
517 case usbSTANDARD_END_POINT_REQUEST:
\r
518 /* Standard Endpoint request */
\r
519 prvHandleStandardEndPointRequest( &xRequest );
\r
522 case usbCLASS_INTERFACE_REQUEST:
\r
523 /* Class Interface request */
\r
524 prvHandleClassInterfaceRequest( &xRequest );
\r
527 default: /* This is not something we want to respond to. */
\r
532 /*------------------------------------------------------------*/
\r
534 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
536 /* The type is in the high byte. Return whatever has been requested. */
\r
537 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
539 case usbDESCRIPTOR_TYPE_DEVICE:
\r
540 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
543 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
544 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
547 case usbDESCRIPTOR_TYPE_STRING:
\r
549 /* The index to the string descriptor is the lower byte. */
\r
550 switch( pxRequest->usValue & 0xff )
\r
552 case usbLANGUAGE_STRING:
\r
553 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
556 case usbMANUFACTURER_STRING:
\r
557 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
560 case usbPRODUCT_STRING:
\r
561 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
564 case usbCONFIGURATION_STRING:
\r
565 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
568 case usbINTERFACE_STRING:
\r
569 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
583 /*------------------------------------------------------------*/
\r
585 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
587 unsigned short usStatus = 0;
\r
589 switch( pxRequest->ucRequest )
\r
591 case usbGET_STATUS_REQUEST:
\r
592 /* Just send two byte dummy status. */
\r
593 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
596 case usbGET_DESCRIPTOR_REQUEST:
\r
597 /* Send device descriptor */
\r
598 prvGetStandardDeviceDescriptor( pxRequest );
\r
601 case usbGET_CONFIGURATION_REQUEST:
\r
602 /* Send selected device configuration */
\r
603 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
606 case usbSET_FEATURE_REQUEST:
\r
610 case usbSET_ADDRESS_REQUEST:
\r
611 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
613 eDriverState = eJUST_GOT_ADDRESS;
\r
614 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
617 case usbSET_CONFIGURATION_REQUEST:
\r
618 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
619 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
620 eDriverState = eJUST_GOT_CONFIG;
\r
625 /* Any unsupported request results in a STALL response. */
\r
630 /*------------------------------------------------------------*/
\r
632 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
634 switch( pxRequest->ucRequest )
\r
636 case usbSEND_ENCAPSULATED_COMMAND:
\r
640 case usbGET_ENCAPSULATED_RESPONSE:
\r
644 case usbSET_LINE_CODING:
\r
645 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
647 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
650 case usbGET_LINE_CODING:
\r
651 /* Get line coding */
\r
652 prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
655 case usbSET_CONTROL_LINE_STATE:
\r
656 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
658 ucControlState = pxRequest->usValue;
\r
666 /*------------------------------------------------------------*/
\r
668 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
670 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
677 /*-----------------------------------------------------------*/
\r
679 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
681 unsigned short usStatus = 0;
\r
683 switch( pxRequest->ucRequest )
\r
685 case usbGET_STATUS_REQUEST:
\r
686 /* Send dummy 2 bytes. */
\r
687 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
690 case usbGET_DESCRIPTOR_REQUEST:
\r
691 prvGetStandardInterfaceDescriptor( pxRequest );
\r
694 /* This minimal implementation does not respond to these. */
\r
695 case usbGET_INTERFACE_REQUEST:
\r
696 case usbSET_FEATURE_REQUEST:
\r
697 case usbSET_INTERFACE_REQUEST:
\r
704 /*-----------------------------------------------------------*/
\r
706 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
708 switch( pxRequest->ucRequest )
\r
710 /* This minimal implementation does not expect to respond to these. */
\r
711 case usbGET_STATUS_REQUEST:
\r
712 case usbCLEAR_FEATURE_REQUEST:
\r
713 case usbSET_FEATURE_REQUEST:
\r
720 /*-----------------------------------------------------------*/
\r
722 static void vDetachUSBInterface( void)
\r
724 /* Setup the PIO for the USB pull up resistor. */
\r
725 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
726 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
729 /* Disable pull up */
\r
730 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
732 /*-----------------------------------------------------------*/
\r
734 static void vInitUSBInterface( void )
\r
736 extern void ( vUSB_ISR_Wrapper )( void );
\r
738 /* Create the queue used to communicate between the USB ISR and task. */
\r
739 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
741 /* Create the queues used to hold Rx and Tx characters. */
\r
742 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );
\r
743 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );
\r
745 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
747 /* Not enough RAM to create queues!. */
\r
751 /* Initialise a few state variables. */
\r
752 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
753 pxControlRx.ulNextCharIndex = ( unsigned long ) 0;
\r
754 ucUSBConfig = ( unsigned char ) 0;
\r
755 eDriverState = eNOTHING;
\r
756 ucControlState = 0;
\r
757 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
760 /* HARDWARE SETUP */
\r
762 /* Set the PLL USB Divider */
\r
763 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
765 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
766 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
767 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
769 /* Setup the PIO for the USB pull up resistor. */
\r
770 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
771 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
774 /* Start without the pullup - this will get set at the end of this
\r
776 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
779 /* When using the USB debugger the peripheral registers do not always get
\r
780 set to the correct default values. To make sure set the relevant registers
\r
782 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
783 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
784 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
785 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
786 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;
\r
787 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;
\r
788 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
789 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
791 /* Enable the transceiver. */
\r
792 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
794 /* Enable the USB interrupts - other interrupts get enabled as the
\r
795 enumeration process progresses. */
\r
796 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
797 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
800 /* Wait a short while before making our presence known. */
\r
801 vTaskDelay( usbINIT_DELAY );
\r
802 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
804 /*-----------------------------------------------------------*/
\r
806 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
808 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
810 /* Cap the data length to that requested. */
\r
811 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
813 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
815 /* We are sending a descriptor. If the descriptor is an exact
\r
816 multiple of the FIFO length then it will have to be terminated
\r
817 with a NULL packet. Set the state to indicate this if
\r
819 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
821 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
825 /* Here we assume that the previous message has been sent. THERE IS NO
\r
826 BUFFER OVERFLOW PROTECTION HERE.
\r
828 Copy the data to send into the buffer as we cannot send it all at once
\r
829 (if it is greater than 8 bytes in length). */
\r
830 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
832 /* Reinitialise the buffer index so we start sending from the start of
\r
834 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
835 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
837 /* Send the first 8 bytes now. The rest will get sent in response to
\r
838 TXCOMP interrupts. */
\r
839 prvSendNextSegment();
\r
841 /*-----------------------------------------------------------*/
\r
843 static void prvSendNextSegment( void )
\r
845 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
847 /* Is there any data to send? */
\r
848 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
850 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
852 /* We can only send 8 bytes to the fifo at a time. */
\r
853 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
855 ulNextLength = usbFIFO_LENGTH;
\r
859 ulNextLength = ulLengthLeftToSend;
\r
862 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
864 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
866 vTaskDelay( usbSHORTEST_DELAY );
\r
869 /* Write the data to the FIFO. */
\r
870 while( ulNextLength > ( unsigned long ) 0 )
\r
872 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
875 pxControlTx.ulNextCharIndex++;
\r
878 /* Start the transmission. */
\r
879 portENTER_CRITICAL();
\r
881 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
882 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
883 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
885 portEXIT_CRITICAL();
\r
889 /* There is no data to send. If we were sending a descriptor and the
\r
890 descriptor was an exact multiple of the max packet size then we need
\r
891 to send a null to terminate the transmission. */
\r
892 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
895 eDriverState = eNOTHING;
\r