2 FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
28 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
29 >>! obliged to provide the source code for proprietary components !<<
\r
30 >>! outside of the FreeRTOS kernel. !<<
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
67 USB Communications Device Class driver.
\r
68 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
69 interface. Control is through endpoint 0, device-to-host notification is
\r
70 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
71 bulk endpoints 1 and 2.
\r
73 - developed from original FreeRTOS HID example by Scott Miller
\r
74 - modified to support 3.2 GCC by najay
\r
77 /* Standard includes. */
\r
81 /* Demo board includes. */
\r
84 /* Scheduler includes. */
\r
85 #include "FreeRTOS.h"
\r
89 /* Demo app includes. */
\r
90 #include "USB-CDC.h"
\r
91 #include "descriptors.h"
\r
93 #define usbNO_BLOCK ( ( TickType_t ) 0 )
\r
95 /* Reset all endpoints */
\r
96 static void prvResetEndPoints( void );
\r
98 /* Clear pull up resistor to detach device from host */
\r
99 static void vDetachUSBInterface( void );
\r
101 /* Set up interface and initialize variables */
\r
102 static void vInitUSBInterface( void );
\r
104 /* Handle control endpoint events. */
\r
105 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
107 /* Handle standard device requests. */
\r
108 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
110 /* Handle standard interface requests. */
\r
111 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
113 /* Handle endpoint requests. */
\r
114 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
116 /* Handle class interface requests. */
\r
117 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
119 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
120 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
122 /* Send next segment of data for the control transfer */
\r
123 static void prvSendNextSegment( void );
\r
125 /* Send stall - used to respond to unsupported requests */
\r
126 static void prvSendStall( void );
\r
128 /* Send a zero-length (null) packet */
\r
129 static void prvSendZLP( void );
\r
131 /* Handle requests for standard interface descriptors */
\r
132 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
134 /*------------------------------------------------------------*/
\r
136 /* File scope static variables */
\r
137 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
138 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
139 static eDRIVER_STATE eDriverState = eNOTHING;
\r
141 /* Incoming and outgoing control data structures */
\r
142 static xCONTROL_MESSAGE pxControlTx;
\r
143 static xCONTROL_MESSAGE pxControlRx;
\r
145 /* Queue holding pointers to pending messages */
\r
146 QueueHandle_t xUSBInterruptQueue;
\r
148 /* Queues used to hold received characters, and characters waiting to be
\r
149 transmitted. Rx queue must be larger than FIFO size. */
\r
150 static QueueHandle_t xRxCDC;
\r
151 static QueueHandle_t xTxCDC;
\r
153 /* Line coding - 115,200 baud, N-8-1 */
\r
154 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
156 /* Status variables. */
\r
157 static unsigned char ucControlState;
\r
158 static unsigned int uiCurrentBank;
\r
161 /*------------------------------------------------------------*/
\r
164 void vUSBCDCTask( void *pvParameters )
\r
166 xISRStatus *pxMessage;
\r
167 unsigned long ulStatus;
\r
168 unsigned long ulRxBytes;
\r
169 unsigned char ucByte;
\r
170 portBASE_TYPE xByte;
\r
172 ( void ) pvParameters;
\r
174 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
175 portENTER_CRITICAL();
\r
176 vDetachUSBInterface();
\r
177 portEXIT_CRITICAL();
\r
179 vTaskDelay( portTICK_PERIOD_MS * 60 );
\r
181 /* Init USB interface */
\r
182 portENTER_CRITICAL();
\r
183 vInitUSBInterface();
\r
184 portEXIT_CRITICAL();
\r
186 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
190 /* Look for data coming from the ISR. */
\r
191 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
193 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
195 /* All endpoint 0 interrupts are handled here. */
\r
196 prvProcessEndPoint0Interrupt( pxMessage );
\r
199 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
201 /* End of bus reset - reset the endpoints and de-configure. */
\r
202 prvResetEndPoints();
\r
206 /* See if we're ready to send and receive data. */
\r
207 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
209 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
211 for( xByte = 0; xByte < 64; xByte++ )
\r
213 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
215 /* No data buffered to transmit. */
\r
219 /* Got a byte to transmit. */
\r
220 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
222 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
225 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
226 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
228 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
230 /* Only process FIFO if there's room to store it in the queue */
\r
231 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
233 while( ulRxBytes-- )
\r
235 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
236 xQueueSend( xRxCDC, &ucByte, 0 );
\r
239 /* Release the FIFO */
\r
240 portENTER_CRITICAL();
\r
242 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
243 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
244 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
246 portEXIT_CRITICAL();
\r
248 /* Re-enable endpoint 1's interrupts */
\r
249 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
251 /* Update the current bank in use */
\r
252 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
254 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
258 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
270 /*------------------------------------------------------------*/
\r
272 void vUSBSendByte( char cByte )
\r
274 /* Queue the byte to be sent. The USB task will send it. */
\r
275 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
277 /*------------------------------------------------------------*/
\r
279 static void prvSendZLP( void )
\r
281 unsigned long ulStatus;
\r
283 /* Wait until the FIFO is free - even though we are not going to use it.
\r
284 THERE IS NO TIMEOUT HERE! */
\r
285 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
287 vTaskDelay( usbSHORTEST_DELAY );
\r
290 portENTER_CRITICAL();
\r
292 /* Cancel any further pending data */
\r
293 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
295 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
296 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
297 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
298 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
300 portEXIT_CRITICAL();
\r
302 /*------------------------------------------------------------*/
\r
304 static void prvSendStall( void )
\r
306 unsigned long ulStatus;
\r
308 portENTER_CRITICAL();
\r
310 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
311 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
312 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
313 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
315 portEXIT_CRITICAL();
\r
317 /*------------------------------------------------------------*/
\r
319 static void prvResetEndPoints( void )
\r
321 unsigned long ulTemp;
\r
323 eDriverState = eJUST_RESET;
\r
324 ucControlState = 0;
\r
326 /* Reset all the end points. */
\r
327 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
328 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
330 /* Enable data to be sent and received. */
\r
331 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
333 /* Repair the configuration end point. */
\r
334 portENTER_CRITICAL();
\r
336 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
337 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
338 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
339 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
341 portEXIT_CRITICAL();
\r
342 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
344 /*------------------------------------------------------------*/
\r
346 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
348 static xUSB_REQUEST xRequest;
\r
349 unsigned long ulRxBytes;
\r
351 /* Get number of bytes received, if any */
\r
352 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
353 ulRxBytes &= usbRX_COUNT_MASK;
\r
355 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
357 /* We received a TX complete interrupt. What we do depends on
\r
358 what we sent to get this interrupt. */
\r
360 if( eDriverState == eJUST_GOT_CONFIG )
\r
362 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
363 are now at the end of the enumeration.
\r
365 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
366 Request for unsupported config should stall. */
\r
367 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
369 /* Set up endpoints */
\r
370 portENTER_CRITICAL();
\r
372 unsigned long ulTemp;
\r
374 /* Set endpoint 1 to bulk-out */
\r
375 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
376 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
377 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
378 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
379 /* Set endpoint 2 to bulk-in */
\r
380 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
381 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
382 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
383 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
384 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
385 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
386 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
387 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
388 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
390 portEXIT_CRITICAL();
\r
392 eDriverState = eREADY_TO_SEND;
\r
394 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
396 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
397 to the addressed state. */
\r
398 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
400 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
404 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
407 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
408 eDriverState = eNOTHING;
\r
412 /* The TXCOMP was not for any special type of transmission. See
\r
413 if there is any more data to send. */
\r
414 prvSendNextSegment();
\r
418 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
420 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
421 unsigned char ucBytesToGet;
\r
423 /* Got data. Cancel any outgoing data. */
\r
424 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
426 /* Determine how many bytes we need to receive. */
\r
427 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
428 if( ucBytesToGet > ulRxBytes )
\r
430 ucBytesToGet = ulRxBytes;
\r
433 /* If we're not expecting any data, it's an ack - just quit now. */
\r
434 if( !ucBytesToGet )
\r
439 /* Get the required data and update the index. */
\r
440 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
441 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
444 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
446 /* Received a SETUP packet. May be followed by data packets. */
\r
448 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
450 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
452 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
453 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
455 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
456 xRequest.usValue <<= 8;
\r
457 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
459 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
460 xRequest.usIndex <<= 8;
\r
461 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
463 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
464 xRequest.usLength <<= 8;
\r
465 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
467 pxControlRx.ulNextCharIndex = 0;
\r
468 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
470 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
472 /* Too big! No space for control data, stall and abort. */
\r
477 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
481 /* We're sending the data, don't wait for any. */
\r
482 pxControlRx.ulTotalDataLength = 0;
\r
487 /* See if we've got a pending request and all its associated data ready */
\r
488 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
489 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
491 unsigned char ucRequest;
\r
493 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
494 generate a zero based request selection. This is just done to
\r
495 break up the requests into subsections for clarity. The
\r
496 alternative would be to have more huge switch statement that would
\r
497 be difficult to optimise. */
\r
498 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
499 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
501 switch( ucRequest )
\r
503 case usbSTANDARD_DEVICE_REQUEST:
\r
504 /* Standard Device request */
\r
505 prvHandleStandardDeviceRequest( &xRequest );
\r
508 case usbSTANDARD_INTERFACE_REQUEST:
\r
509 /* Standard Interface request */
\r
510 prvHandleStandardInterfaceRequest( &xRequest );
\r
513 case usbSTANDARD_END_POINT_REQUEST:
\r
514 /* Standard Endpoint request */
\r
515 prvHandleStandardEndPointRequest( &xRequest );
\r
518 case usbCLASS_INTERFACE_REQUEST:
\r
519 /* Class Interface request */
\r
520 prvHandleClassInterfaceRequest( &xRequest );
\r
523 default: /* This is not something we want to respond to. */
\r
528 /*------------------------------------------------------------*/
\r
530 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
532 /* The type is in the high byte. Return whatever has been requested. */
\r
533 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
535 case usbDESCRIPTOR_TYPE_DEVICE:
\r
536 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
539 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
540 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
543 case usbDESCRIPTOR_TYPE_STRING:
\r
545 /* The index to the string descriptor is the lower byte. */
\r
546 switch( pxRequest->usValue & 0xff )
\r
548 case usbLANGUAGE_STRING:
\r
549 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
552 case usbMANUFACTURER_STRING:
\r
553 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
556 case usbPRODUCT_STRING:
\r
557 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
560 case usbCONFIGURATION_STRING:
\r
561 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
564 case usbINTERFACE_STRING:
\r
565 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
579 /*------------------------------------------------------------*/
\r
581 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
583 unsigned short usStatus = 0;
\r
585 switch( pxRequest->ucRequest )
\r
587 case usbGET_STATUS_REQUEST:
\r
588 /* Just send two byte dummy status. */
\r
589 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
592 case usbGET_DESCRIPTOR_REQUEST:
\r
593 /* Send device descriptor */
\r
594 prvGetStandardDeviceDescriptor( pxRequest );
\r
597 case usbGET_CONFIGURATION_REQUEST:
\r
598 /* Send selected device configuration */
\r
599 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
602 case usbSET_FEATURE_REQUEST:
\r
606 case usbSET_ADDRESS_REQUEST:
\r
607 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
609 eDriverState = eJUST_GOT_ADDRESS;
\r
610 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
613 case usbSET_CONFIGURATION_REQUEST:
\r
614 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
615 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
616 eDriverState = eJUST_GOT_CONFIG;
\r
621 /* Any unsupported request results in a STALL response. */
\r
626 /*------------------------------------------------------------*/
\r
628 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
630 switch( pxRequest->ucRequest )
\r
632 case usbSEND_ENCAPSULATED_COMMAND:
\r
636 case usbGET_ENCAPSULATED_RESPONSE:
\r
640 case usbSET_LINE_CODING:
\r
641 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
643 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
646 case usbGET_LINE_CODING:
\r
647 /* Get line coding */
\r
648 prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
651 case usbSET_CONTROL_LINE_STATE:
\r
652 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
654 ucControlState = pxRequest->usValue;
\r
662 /*------------------------------------------------------------*/
\r
664 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
666 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
673 /*-----------------------------------------------------------*/
\r
675 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
677 unsigned short usStatus = 0;
\r
679 switch( pxRequest->ucRequest )
\r
681 case usbGET_STATUS_REQUEST:
\r
682 /* Send dummy 2 bytes. */
\r
683 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
686 case usbGET_DESCRIPTOR_REQUEST:
\r
687 prvGetStandardInterfaceDescriptor( pxRequest );
\r
690 /* This minimal implementation does not respond to these. */
\r
691 case usbGET_INTERFACE_REQUEST:
\r
692 case usbSET_FEATURE_REQUEST:
\r
693 case usbSET_INTERFACE_REQUEST:
\r
700 /*-----------------------------------------------------------*/
\r
702 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
704 switch( pxRequest->ucRequest )
\r
706 /* This minimal implementation does not expect to respond to these. */
\r
707 case usbGET_STATUS_REQUEST:
\r
708 case usbCLEAR_FEATURE_REQUEST:
\r
709 case usbSET_FEATURE_REQUEST:
\r
716 /*-----------------------------------------------------------*/
\r
718 static void vDetachUSBInterface( void)
\r
720 /* Setup the PIO for the USB pull up resistor. */
\r
721 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
722 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
725 /* Disable pull up */
\r
726 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
728 /*-----------------------------------------------------------*/
\r
730 static void vInitUSBInterface( void )
\r
732 extern void ( vUSB_ISR_Wrapper )( void );
\r
734 /* Create the queue used to communicate between the USB ISR and task. */
\r
735 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
737 /* Create the queues used to hold Rx and Tx characters. */
\r
738 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );
\r
739 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );
\r
741 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
743 /* Not enough RAM to create queues!. */
\r
747 /* Initialise a few state variables. */
\r
748 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
749 pxControlRx.ulNextCharIndex = ( unsigned long ) 0;
\r
750 ucUSBConfig = ( unsigned char ) 0;
\r
751 eDriverState = eNOTHING;
\r
752 ucControlState = 0;
\r
753 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
756 /* HARDWARE SETUP */
\r
758 /* Set the PLL USB Divider */
\r
759 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
761 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
762 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
763 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
765 /* Setup the PIO for the USB pull up resistor. */
\r
766 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
767 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
770 /* Start without the pullup - this will get set at the end of this
\r
772 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
775 /* When using the USB debugger the peripheral registers do not always get
\r
776 set to the correct default values. To make sure set the relevant registers
\r
778 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
779 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
780 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
781 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
782 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;
\r
783 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;
\r
784 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
785 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
787 /* Enable the transceiver. */
\r
788 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
790 /* Enable the USB interrupts - other interrupts get enabled as the
\r
791 enumeration process progresses. */
\r
792 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
793 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
796 /* Wait a short while before making our presence known. */
\r
797 vTaskDelay( usbINIT_DELAY );
\r
798 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
800 /*-----------------------------------------------------------*/
\r
802 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
804 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
806 /* Cap the data length to that requested. */
\r
807 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
809 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
811 /* We are sending a descriptor. If the descriptor is an exact
\r
812 multiple of the FIFO length then it will have to be terminated
\r
813 with a NULL packet. Set the state to indicate this if
\r
815 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
817 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
821 /* Here we assume that the previous message has been sent. THERE IS NO
\r
822 BUFFER OVERFLOW PROTECTION HERE.
\r
824 Copy the data to send into the buffer as we cannot send it all at once
\r
825 (if it is greater than 8 bytes in length). */
\r
826 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
828 /* Reinitialise the buffer index so we start sending from the start of
\r
830 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
831 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
833 /* Send the first 8 bytes now. The rest will get sent in response to
\r
834 TXCOMP interrupts. */
\r
835 prvSendNextSegment();
\r
837 /*-----------------------------------------------------------*/
\r
839 static void prvSendNextSegment( void )
\r
841 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
843 /* Is there any data to send? */
\r
844 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
846 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
848 /* We can only send 8 bytes to the fifo at a time. */
\r
849 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
851 ulNextLength = usbFIFO_LENGTH;
\r
855 ulNextLength = ulLengthLeftToSend;
\r
858 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
860 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
862 vTaskDelay( usbSHORTEST_DELAY );
\r
865 /* Write the data to the FIFO. */
\r
866 while( ulNextLength > ( unsigned long ) 0 )
\r
868 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
871 pxControlTx.ulNextCharIndex++;
\r
874 /* Start the transmission. */
\r
875 portENTER_CRITICAL();
\r
877 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
878 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
879 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
881 portEXIT_CRITICAL();
\r
885 /* There is no data to send. If we were sending a descriptor and the
\r
886 descriptor was an exact multiple of the max packet size then we need
\r
887 to send a null to terminate the transmission. */
\r
888 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
891 eDriverState = eNOTHING;
\r