2 * FreeRTOS Kernel V10.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
30 USB Communications Device Class driver.
\r
31 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
32 interface. Control is through endpoint 0, device-to-host notification is
\r
33 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
34 bulk endpoints 1 and 2.
\r
36 - developed from original FreeRTOS HID example by Scott Miller
\r
37 - modified to support 3.2 GCC by najay
\r
40 /* Standard includes. */
\r
44 /* Demo board includes. */
\r
47 /* Scheduler includes. */
\r
48 #include "FreeRTOS.h"
\r
52 /* Demo app includes. */
\r
53 #include "USB-CDC.h"
\r
54 #include "descriptors.h"
\r
56 #define usbNO_BLOCK ( ( TickType_t ) 0 )
\r
58 /* Reset all endpoints */
\r
59 static void prvResetEndPoints( void );
\r
61 /* Clear pull up resistor to detach device from host */
\r
62 static void vDetachUSBInterface( void );
\r
64 /* Set up interface and initialize variables */
\r
65 static void vInitUSBInterface( void );
\r
67 /* Handle control endpoint events. */
\r
68 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
70 /* Handle standard device requests. */
\r
71 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
73 /* Handle standard interface requests. */
\r
74 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
76 /* Handle endpoint requests. */
\r
77 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
79 /* Handle class interface requests. */
\r
80 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
82 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
83 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
85 /* Send next segment of data for the control transfer */
\r
86 static void prvSendNextSegment( void );
\r
88 /* Send stall - used to respond to unsupported requests */
\r
89 static void prvSendStall( void );
\r
91 /* Send a zero-length (null) packet */
\r
92 static void prvSendZLP( void );
\r
94 /* Handle requests for standard interface descriptors */
\r
95 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
97 /*------------------------------------------------------------*/
\r
99 /* File scope static variables */
\r
100 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
101 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
102 static eDRIVER_STATE eDriverState = eNOTHING;
\r
104 /* Incoming and outgoing control data structures */
\r
105 static xCONTROL_MESSAGE pxControlTx;
\r
106 static xCONTROL_MESSAGE pxControlRx;
\r
108 /* Queue holding pointers to pending messages */
\r
109 QueueHandle_t xUSBInterruptQueue;
\r
111 /* Queues used to hold received characters, and characters waiting to be
\r
112 transmitted. Rx queue must be larger than FIFO size. */
\r
113 static QueueHandle_t xRxCDC;
\r
114 static QueueHandle_t xTxCDC;
\r
116 /* Line coding - 115,200 baud, N-8-1 */
\r
117 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
119 /* Status variables. */
\r
120 static unsigned char ucControlState;
\r
121 static unsigned int uiCurrentBank;
\r
124 /*------------------------------------------------------------*/
\r
127 void vUSBCDCTask( void *pvParameters )
\r
129 xISRStatus *pxMessage;
\r
130 unsigned long ulStatus;
\r
131 unsigned long ulRxBytes;
\r
132 unsigned char ucByte;
\r
133 portBASE_TYPE xByte;
\r
135 ( void ) pvParameters;
\r
137 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
138 portENTER_CRITICAL();
\r
139 vDetachUSBInterface();
\r
140 portEXIT_CRITICAL();
\r
142 vTaskDelay( portTICK_PERIOD_MS * 60 );
\r
144 /* Init USB interface */
\r
145 portENTER_CRITICAL();
\r
146 vInitUSBInterface();
\r
147 portEXIT_CRITICAL();
\r
149 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
153 /* Look for data coming from the ISR. */
\r
154 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
156 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
158 /* All endpoint 0 interrupts are handled here. */
\r
159 prvProcessEndPoint0Interrupt( pxMessage );
\r
162 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
164 /* End of bus reset - reset the endpoints and de-configure. */
\r
165 prvResetEndPoints();
\r
169 /* See if we're ready to send and receive data. */
\r
170 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
172 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
174 for( xByte = 0; xByte < 64; xByte++ )
\r
176 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
178 /* No data buffered to transmit. */
\r
182 /* Got a byte to transmit. */
\r
183 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
185 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
188 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
189 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
191 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
193 /* Only process FIFO if there's room to store it in the queue */
\r
194 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
196 while( ulRxBytes-- )
\r
198 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
199 xQueueSend( xRxCDC, &ucByte, 0 );
\r
202 /* Release the FIFO */
\r
203 portENTER_CRITICAL();
\r
205 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
206 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
207 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
209 portEXIT_CRITICAL();
\r
211 /* Re-enable endpoint 1's interrupts */
\r
212 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
214 /* Update the current bank in use */
\r
215 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
217 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
221 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
233 /*------------------------------------------------------------*/
\r
235 void vUSBSendByte( char cByte )
\r
237 /* Queue the byte to be sent. The USB task will send it. */
\r
238 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
240 /*------------------------------------------------------------*/
\r
242 static void prvSendZLP( void )
\r
244 unsigned long ulStatus;
\r
246 /* Wait until the FIFO is free - even though we are not going to use it.
\r
247 THERE IS NO TIMEOUT HERE! */
\r
248 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
250 vTaskDelay( usbSHORTEST_DELAY );
\r
253 portENTER_CRITICAL();
\r
255 /* Cancel any further pending data */
\r
256 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
258 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
259 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
260 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
261 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
263 portEXIT_CRITICAL();
\r
265 /*------------------------------------------------------------*/
\r
267 static void prvSendStall( void )
\r
269 unsigned long ulStatus;
\r
271 portENTER_CRITICAL();
\r
273 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
274 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
275 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
276 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
278 portEXIT_CRITICAL();
\r
280 /*------------------------------------------------------------*/
\r
282 static void prvResetEndPoints( void )
\r
284 unsigned long ulTemp;
\r
286 eDriverState = eJUST_RESET;
\r
287 ucControlState = 0;
\r
289 /* Reset all the end points. */
\r
290 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
291 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
293 /* Enable data to be sent and received. */
\r
294 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
296 /* Repair the configuration end point. */
\r
297 portENTER_CRITICAL();
\r
299 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
300 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
301 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
302 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
304 portEXIT_CRITICAL();
\r
305 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
307 /*------------------------------------------------------------*/
\r
309 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
311 static xUSB_REQUEST xRequest;
\r
312 unsigned long ulRxBytes;
\r
314 /* Get number of bytes received, if any */
\r
315 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
316 ulRxBytes &= usbRX_COUNT_MASK;
\r
318 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
320 /* We received a TX complete interrupt. What we do depends on
\r
321 what we sent to get this interrupt. */
\r
323 if( eDriverState == eJUST_GOT_CONFIG )
\r
325 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
326 are now at the end of the enumeration.
\r
328 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
329 Request for unsupported config should stall. */
\r
330 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
332 /* Set up endpoints */
\r
333 portENTER_CRITICAL();
\r
335 unsigned long ulTemp;
\r
337 /* Set endpoint 1 to bulk-out */
\r
338 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
339 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
340 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
341 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
342 /* Set endpoint 2 to bulk-in */
\r
343 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
344 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
345 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
346 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
347 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
348 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
349 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
350 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
351 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
353 portEXIT_CRITICAL();
\r
355 eDriverState = eREADY_TO_SEND;
\r
357 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
359 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
360 to the addressed state. */
\r
361 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
363 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
367 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
370 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
371 eDriverState = eNOTHING;
\r
375 /* The TXCOMP was not for any special type of transmission. See
\r
376 if there is any more data to send. */
\r
377 prvSendNextSegment();
\r
381 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
383 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
384 unsigned char ucBytesToGet;
\r
386 /* Got data. Cancel any outgoing data. */
\r
387 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
389 /* Determine how many bytes we need to receive. */
\r
390 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
391 if( ucBytesToGet > ulRxBytes )
\r
393 ucBytesToGet = ulRxBytes;
\r
396 /* If we're not expecting any data, it's an ack - just quit now. */
\r
397 if( !ucBytesToGet )
\r
402 /* Get the required data and update the index. */
\r
403 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
404 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
407 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
409 /* Received a SETUP packet. May be followed by data packets. */
\r
411 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
413 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
415 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
416 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
418 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
419 xRequest.usValue <<= 8;
\r
420 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
422 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
423 xRequest.usIndex <<= 8;
\r
424 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
426 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
427 xRequest.usLength <<= 8;
\r
428 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
430 pxControlRx.ulNextCharIndex = 0;
\r
431 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
433 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
435 /* Too big! No space for control data, stall and abort. */
\r
440 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
444 /* We're sending the data, don't wait for any. */
\r
445 pxControlRx.ulTotalDataLength = 0;
\r
450 /* See if we've got a pending request and all its associated data ready */
\r
451 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
452 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
454 unsigned char ucRequest;
\r
456 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
457 generate a zero based request selection. This is just done to
\r
458 break up the requests into subsections for clarity. The
\r
459 alternative would be to have more huge switch statement that would
\r
460 be difficult to optimise. */
\r
461 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
462 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
464 switch( ucRequest )
\r
466 case usbSTANDARD_DEVICE_REQUEST:
\r
467 /* Standard Device request */
\r
468 prvHandleStandardDeviceRequest( &xRequest );
\r
471 case usbSTANDARD_INTERFACE_REQUEST:
\r
472 /* Standard Interface request */
\r
473 prvHandleStandardInterfaceRequest( &xRequest );
\r
476 case usbSTANDARD_END_POINT_REQUEST:
\r
477 /* Standard Endpoint request */
\r
478 prvHandleStandardEndPointRequest( &xRequest );
\r
481 case usbCLASS_INTERFACE_REQUEST:
\r
482 /* Class Interface request */
\r
483 prvHandleClassInterfaceRequest( &xRequest );
\r
486 default: /* This is not something we want to respond to. */
\r
491 /*------------------------------------------------------------*/
\r
493 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
495 /* The type is in the high byte. Return whatever has been requested. */
\r
496 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
498 case usbDESCRIPTOR_TYPE_DEVICE:
\r
499 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
502 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
503 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
506 case usbDESCRIPTOR_TYPE_STRING:
\r
508 /* The index to the string descriptor is the lower byte. */
\r
509 switch( pxRequest->usValue & 0xff )
\r
511 case usbLANGUAGE_STRING:
\r
512 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
515 case usbMANUFACTURER_STRING:
\r
516 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
519 case usbPRODUCT_STRING:
\r
520 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
523 case usbCONFIGURATION_STRING:
\r
524 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
527 case usbINTERFACE_STRING:
\r
528 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
542 /*------------------------------------------------------------*/
\r
544 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
546 unsigned short usStatus = 0;
\r
548 switch( pxRequest->ucRequest )
\r
550 case usbGET_STATUS_REQUEST:
\r
551 /* Just send two byte dummy status. */
\r
552 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
555 case usbGET_DESCRIPTOR_REQUEST:
\r
556 /* Send device descriptor */
\r
557 prvGetStandardDeviceDescriptor( pxRequest );
\r
560 case usbGET_CONFIGURATION_REQUEST:
\r
561 /* Send selected device configuration */
\r
562 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
565 case usbSET_FEATURE_REQUEST:
\r
569 case usbSET_ADDRESS_REQUEST:
\r
570 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
572 eDriverState = eJUST_GOT_ADDRESS;
\r
573 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
576 case usbSET_CONFIGURATION_REQUEST:
\r
577 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
578 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
579 eDriverState = eJUST_GOT_CONFIG;
\r
584 /* Any unsupported request results in a STALL response. */
\r
589 /*------------------------------------------------------------*/
\r
591 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
593 switch( pxRequest->ucRequest )
\r
595 case usbSEND_ENCAPSULATED_COMMAND:
\r
599 case usbGET_ENCAPSULATED_RESPONSE:
\r
603 case usbSET_LINE_CODING:
\r
604 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
606 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
609 case usbGET_LINE_CODING:
\r
610 /* Get line coding */
\r
611 prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
614 case usbSET_CONTROL_LINE_STATE:
\r
615 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
617 ucControlState = pxRequest->usValue;
\r
625 /*------------------------------------------------------------*/
\r
627 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
629 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
636 /*-----------------------------------------------------------*/
\r
638 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
640 unsigned short usStatus = 0;
\r
642 switch( pxRequest->ucRequest )
\r
644 case usbGET_STATUS_REQUEST:
\r
645 /* Send dummy 2 bytes. */
\r
646 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
649 case usbGET_DESCRIPTOR_REQUEST:
\r
650 prvGetStandardInterfaceDescriptor( pxRequest );
\r
653 /* This minimal implementation does not respond to these. */
\r
654 case usbGET_INTERFACE_REQUEST:
\r
655 case usbSET_FEATURE_REQUEST:
\r
656 case usbSET_INTERFACE_REQUEST:
\r
663 /*-----------------------------------------------------------*/
\r
665 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
667 switch( pxRequest->ucRequest )
\r
669 /* This minimal implementation does not expect to respond to these. */
\r
670 case usbGET_STATUS_REQUEST:
\r
671 case usbCLEAR_FEATURE_REQUEST:
\r
672 case usbSET_FEATURE_REQUEST:
\r
679 /*-----------------------------------------------------------*/
\r
681 static void vDetachUSBInterface( void)
\r
683 /* Setup the PIO for the USB pull up resistor. */
\r
684 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
685 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
688 /* Disable pull up */
\r
689 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
691 /*-----------------------------------------------------------*/
\r
693 static void vInitUSBInterface( void )
\r
695 extern void ( vUSB_ISR_Wrapper )( void );
\r
697 /* Create the queue used to communicate between the USB ISR and task. */
\r
698 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
700 /* Create the queues used to hold Rx and Tx characters. */
\r
701 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );
\r
702 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );
\r
704 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
706 /* Not enough RAM to create queues!. */
\r
710 /* Initialise a few state variables. */
\r
711 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
712 pxControlRx.ulNextCharIndex = ( unsigned long ) 0;
\r
713 ucUSBConfig = ( unsigned char ) 0;
\r
714 eDriverState = eNOTHING;
\r
715 ucControlState = 0;
\r
716 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
719 /* HARDWARE SETUP */
\r
721 /* Set the PLL USB Divider */
\r
722 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
724 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
725 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
726 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
728 /* Setup the PIO for the USB pull up resistor. */
\r
729 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
730 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
733 /* Start without the pullup - this will get set at the end of this
\r
735 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
738 /* When using the USB debugger the peripheral registers do not always get
\r
739 set to the correct default values. To make sure set the relevant registers
\r
741 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
742 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
743 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
744 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
745 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;
\r
746 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;
\r
747 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
748 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
750 /* Enable the transceiver. */
\r
751 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
753 /* Enable the USB interrupts - other interrupts get enabled as the
\r
754 enumeration process progresses. */
\r
755 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
756 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
759 /* Wait a short while before making our presence known. */
\r
760 vTaskDelay( usbINIT_DELAY );
\r
761 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
763 /*-----------------------------------------------------------*/
\r
765 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
767 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
769 /* Cap the data length to that requested. */
\r
770 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
772 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
774 /* We are sending a descriptor. If the descriptor is an exact
\r
775 multiple of the FIFO length then it will have to be terminated
\r
776 with a NULL packet. Set the state to indicate this if
\r
778 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
780 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
784 /* Here we assume that the previous message has been sent. THERE IS NO
\r
785 BUFFER OVERFLOW PROTECTION HERE.
\r
787 Copy the data to send into the buffer as we cannot send it all at once
\r
788 (if it is greater than 8 bytes in length). */
\r
789 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
791 /* Reinitialise the buffer index so we start sending from the start of
\r
793 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
794 pxControlTx.ulNextCharIndex = ( unsigned long ) 0;
\r
796 /* Send the first 8 bytes now. The rest will get sent in response to
\r
797 TXCOMP interrupts. */
\r
798 prvSendNextSegment();
\r
800 /*-----------------------------------------------------------*/
\r
802 static void prvSendNextSegment( void )
\r
804 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
806 /* Is there any data to send? */
\r
807 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
809 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
811 /* We can only send 8 bytes to the fifo at a time. */
\r
812 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
814 ulNextLength = usbFIFO_LENGTH;
\r
818 ulNextLength = ulLengthLeftToSend;
\r
821 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
823 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
825 vTaskDelay( usbSHORTEST_DELAY );
\r
828 /* Write the data to the FIFO. */
\r
829 while( ulNextLength > ( unsigned long ) 0 )
\r
831 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
834 pxControlTx.ulNextCharIndex++;
\r
837 /* Start the transmission. */
\r
838 portENTER_CRITICAL();
\r
840 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
841 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
842 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
844 portEXIT_CRITICAL();
\r
848 /* There is no data to send. If we were sending a descriptor and the
\r
849 descriptor was an exact multiple of the max packet size then we need
\r
850 to send a null to terminate the transmission. */
\r
851 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
854 eDriverState = eNOTHING;
\r