2 FreeRTOS.org V5.0.2 - Copyright (C) 2003-2008 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 ***************************************************************************
\r
29 * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, *
\r
30 * and even write all or part of your application on your behalf. *
\r
31 * See http://www.OpenRTOS.com for details of the services we provide to *
\r
32 * expedite your project. *
\r
34 ***************************************************************************
\r
35 ***************************************************************************
\r
37 Please ensure to read the configuration and relevant port sections of the
\r
38 online documentation.
\r
40 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
43 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
46 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
47 licensing and training services.
\r
51 USB Communications Device Class driver.
\r
52 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
53 interface. Control is through endpoint 0, device-to-host notification is
\r
54 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
55 bulk endpoints 1 and 2.
\r
57 - developed from original FreeRTOS HID example by Scott Miller
\r
58 - modified to support 3.2 GCC by najay
\r
61 /* Standard includes. */
\r
65 /* Demo board includes. */
\r
68 /* Scheduler includes. */
\r
69 #include "FreeRTOS.h"
\r
73 /* Demo app includes. */
\r
74 #include "USB-CDC.h"
\r
75 #include "descriptors.h"
\r
77 #define usbNO_BLOCK ( ( portTickType ) 0 )
\r
79 /* Reset all endpoints */
\r
80 static void prvResetEndPoints( void );
\r
82 /* Clear pull up resistor to detach device from host */
\r
83 static void vDetachUSBInterface( void );
\r
85 /* Set up interface and initialize variables */
\r
86 static void vInitUSBInterface( void );
\r
88 /* Handle control endpoint events. */
\r
89 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
91 /* Handle standard device requests. */
\r
92 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
94 /* Handle standard interface requests. */
\r
95 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
97 /* Handle endpoint requests. */
\r
98 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
100 /* Handle class interface requests. */
\r
101 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
103 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
104 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthLeftToSend, portLONG lSendingDescriptor );
\r
106 /* Send next segment of data for the control transfer */
\r
107 static void prvSendNextSegment( void );
\r
109 /* Send stall - used to respond to unsupported requests */
\r
110 static void prvSendStall( void );
\r
112 /* Send a zero-length (null) packet */
\r
113 static void prvSendZLP( void );
\r
115 /* Handle requests for standard interface descriptors */
\r
116 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
118 /*------------------------------------------------------------*/
\r
120 /* File scope static variables */
\r
121 static unsigned portCHAR ucUSBConfig = ( unsigned portCHAR ) 0;
\r
122 static unsigned portLONG ulReceivedAddress = ( unsigned portLONG ) 0;
\r
123 static eDRIVER_STATE eDriverState = eNOTHING;
\r
125 /* Incoming and outgoing control data structures */
\r
126 static xCONTROL_MESSAGE pxControlTx;
\r
127 static xCONTROL_MESSAGE pxControlRx;
\r
129 /* Queue holding pointers to pending messages */
\r
130 xQueueHandle xUSBInterruptQueue;
\r
132 /* Queues used to hold received characters, and characters waiting to be
\r
133 transmitted. Rx queue must be larger than FIFO size. */
\r
134 static xQueueHandle xRxCDC;
\r
135 static xQueueHandle xTxCDC;
\r
137 /* Line coding - 115,200 baud, N-8-1 */
\r
138 static const unsigned portCHAR pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
140 /* Status variables. */
\r
141 static unsigned portCHAR ucControlState;
\r
142 static unsigned int uiCurrentBank;
\r
145 /*------------------------------------------------------------*/
\r
148 void vUSBCDCTask( void *pvParameters )
\r
150 xISRStatus *pxMessage;
\r
151 unsigned portLONG ulStatus;
\r
152 unsigned portLONG ulRxBytes;
\r
153 unsigned portCHAR ucByte;
\r
154 portBASE_TYPE xByte;
\r
156 ( void ) pvParameters;
\r
158 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
159 portENTER_CRITICAL();
\r
160 vDetachUSBInterface();
\r
161 portEXIT_CRITICAL();
\r
163 vTaskDelay( portTICK_RATE_MS * 60 );
\r
165 /* Init USB interface */
\r
166 portENTER_CRITICAL();
\r
167 vInitUSBInterface();
\r
168 portEXIT_CRITICAL();
\r
170 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
174 /* Look for data coming from the ISR. */
\r
175 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
177 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
179 /* All endpoint 0 interrupts are handled here. */
\r
180 prvProcessEndPoint0Interrupt( pxMessage );
\r
183 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
185 /* End of bus reset - reset the endpoints and de-configure. */
\r
186 prvResetEndPoints();
\r
190 /* See if we're ready to send and receive data. */
\r
191 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
193 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
195 for( xByte = 0; xByte < 64; xByte++ )
\r
197 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
199 /* No data buffered to transmit. */
\r
203 /* Got a byte to transmit. */
\r
204 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
206 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
209 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
210 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
212 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
214 /* Only process FIFO if there's room to store it in the queue */
\r
215 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
217 while( ulRxBytes-- )
\r
219 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
220 xQueueSend( xRxCDC, &ucByte, 0 );
\r
223 /* Release the FIFO */
\r
224 portENTER_CRITICAL();
\r
226 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
227 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
228 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
230 portEXIT_CRITICAL();
\r
232 /* Re-enable endpoint 1's interrupts */
\r
233 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
235 /* Update the current bank in use */
\r
236 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
238 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
242 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
254 /*------------------------------------------------------------*/
\r
256 void vUSBSendByte( portCHAR cByte )
\r
258 /* Queue the byte to be sent. The USB task will send it. */
\r
259 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
261 /*------------------------------------------------------------*/
\r
263 static void prvSendZLP( void )
\r
265 unsigned portLONG ulStatus;
\r
267 /* Wait until the FIFO is free - even though we are not going to use it.
\r
268 THERE IS NO TIMEOUT HERE! */
\r
269 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
271 vTaskDelay( usbSHORTEST_DELAY );
\r
274 portENTER_CRITICAL();
\r
276 /* Cancel any further pending data */
\r
277 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
279 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
280 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
281 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
282 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
284 portEXIT_CRITICAL();
\r
286 /*------------------------------------------------------------*/
\r
288 static void prvSendStall( void )
\r
290 unsigned portLONG ulStatus;
\r
292 portENTER_CRITICAL();
\r
294 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
295 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
296 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
297 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
299 portEXIT_CRITICAL();
\r
301 /*------------------------------------------------------------*/
\r
303 static void prvResetEndPoints( void )
\r
305 unsigned portLONG ulTemp;
\r
307 eDriverState = eJUST_RESET;
\r
308 ucControlState = 0;
\r
310 /* Reset all the end points. */
\r
311 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
312 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned portLONG ) 0x00;
\r
314 /* Enable data to be sent and received. */
\r
315 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
317 /* Repair the configuration end point. */
\r
318 portENTER_CRITICAL();
\r
320 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
321 usbCSR_SET_BIT( &ulTemp, ( ( unsigned portLONG ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
322 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
323 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
325 portEXIT_CRITICAL();
\r
326 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
328 /*------------------------------------------------------------*/
\r
330 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
332 static xUSB_REQUEST xRequest;
\r
333 unsigned portLONG ulRxBytes;
\r
335 /* Get number of bytes received, if any */
\r
336 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
337 ulRxBytes &= usbRX_COUNT_MASK;
\r
339 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
341 /* We received a TX complete interrupt. What we do depends on
\r
342 what we sent to get this interrupt. */
\r
344 if( eDriverState == eJUST_GOT_CONFIG )
\r
346 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
347 are now at the end of the enumeration.
\r
349 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
350 Request for unsupported config should stall. */
\r
351 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
353 /* Set up endpoints */
\r
354 portENTER_CRITICAL();
\r
356 unsigned portLONG ulTemp;
\r
358 /* Set endpoint 1 to bulk-out */
\r
359 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
360 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
361 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
362 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
363 /* Set endpoint 2 to bulk-in */
\r
364 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
365 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
366 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
367 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
368 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
369 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
370 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
371 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
372 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
374 portEXIT_CRITICAL();
\r
376 eDriverState = eREADY_TO_SEND;
\r
378 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
380 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
381 to the addressed state. */
\r
382 if( ulReceivedAddress != ( unsigned portLONG ) 0 )
\r
384 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
388 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
391 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
392 eDriverState = eNOTHING;
\r
396 /* The TXCOMP was not for any special type of transmission. See
\r
397 if there is any more data to send. */
\r
398 prvSendNextSegment();
\r
402 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
404 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
405 unsigned portCHAR ucBytesToGet;
\r
407 /* Got data. Cancel any outgoing data. */
\r
408 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
410 /* Determine how many bytes we need to receive. */
\r
411 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
412 if( ucBytesToGet > ulRxBytes )
\r
414 ucBytesToGet = ulRxBytes;
\r
417 /* If we're not expecting any data, it's an ack - just quit now. */
\r
418 if( !ucBytesToGet )
\r
423 /* Get the required data and update the index. */
\r
424 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
425 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
428 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
430 /* Received a SETUP packet. May be followed by data packets. */
\r
432 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
434 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
436 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
437 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
439 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
440 xRequest.usValue <<= 8;
\r
441 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
443 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
444 xRequest.usIndex <<= 8;
\r
445 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
447 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
448 xRequest.usLength <<= 8;
\r
449 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
451 pxControlRx.ulNextCharIndex = 0;
\r
452 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
454 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
456 /* Too big! No space for control data, stall and abort. */
\r
461 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
465 /* We're sending the data, don't wait for any. */
\r
466 pxControlRx.ulTotalDataLength = 0;
\r
471 /* See if we've got a pending request and all its associated data ready */
\r
472 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
473 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
475 unsigned portCHAR ucRequest;
\r
477 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
478 generate a zero based request selection. This is just done to
\r
479 break up the requests into subsections for clarity. The
\r
480 alternative would be to have more huge switch statement that would
\r
481 be difficult to optimise. */
\r
482 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
483 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
485 switch( ucRequest )
\r
487 case usbSTANDARD_DEVICE_REQUEST:
\r
488 /* Standard Device request */
\r
489 prvHandleStandardDeviceRequest( &xRequest );
\r
492 case usbSTANDARD_INTERFACE_REQUEST:
\r
493 /* Standard Interface request */
\r
494 prvHandleStandardInterfaceRequest( &xRequest );
\r
497 case usbSTANDARD_END_POINT_REQUEST:
\r
498 /* Standard Endpoint request */
\r
499 prvHandleStandardEndPointRequest( &xRequest );
\r
502 case usbCLASS_INTERFACE_REQUEST:
\r
503 /* Class Interface request */
\r
504 prvHandleClassInterfaceRequest( &xRequest );
\r
507 default: /* This is not something we want to respond to. */
\r
512 /*------------------------------------------------------------*/
\r
514 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
516 /* The type is in the high byte. Return whatever has been requested. */
\r
517 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
519 case usbDESCRIPTOR_TYPE_DEVICE:
\r
520 prvSendControlData( ( unsigned portCHAR * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
523 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
524 prvSendControlData( ( unsigned portCHAR * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
527 case usbDESCRIPTOR_TYPE_STRING:
\r
529 /* The index to the string descriptor is the lower byte. */
\r
530 switch( pxRequest->usValue & 0xff )
\r
532 case usbLANGUAGE_STRING:
\r
533 prvSendControlData( ( unsigned portCHAR * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
536 case usbMANUFACTURER_STRING:
\r
537 prvSendControlData( ( unsigned portCHAR * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
540 case usbPRODUCT_STRING:
\r
541 prvSendControlData( ( unsigned portCHAR * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
544 case usbCONFIGURATION_STRING:
\r
545 prvSendControlData( ( unsigned portCHAR * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
548 case usbINTERFACE_STRING:
\r
549 prvSendControlData( ( unsigned portCHAR * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
563 /*------------------------------------------------------------*/
\r
565 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
567 unsigned portSHORT usStatus = 0;
\r
569 switch( pxRequest->ucRequest )
\r
571 case usbGET_STATUS_REQUEST:
\r
572 /* Just send two byte dummy status. */
\r
573 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
576 case usbGET_DESCRIPTOR_REQUEST:
\r
577 /* Send device descriptor */
\r
578 prvGetStandardDeviceDescriptor( pxRequest );
\r
581 case usbGET_CONFIGURATION_REQUEST:
\r
582 /* Send selected device configuration */
\r
583 prvSendControlData( ( unsigned portCHAR * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
586 case usbSET_FEATURE_REQUEST:
\r
590 case usbSET_ADDRESS_REQUEST:
\r
591 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
593 eDriverState = eJUST_GOT_ADDRESS;
\r
594 ulReceivedAddress = ( unsigned portLONG ) pxRequest->usValue;
\r
597 case usbSET_CONFIGURATION_REQUEST:
\r
598 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
599 ucUSBConfig = ( unsigned portCHAR ) ( pxRequest->usValue & 0xff );
\r
600 eDriverState = eJUST_GOT_CONFIG;
\r
605 /* Any unsupported request results in a STALL response. */
\r
610 /*------------------------------------------------------------*/
\r
612 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
614 switch( pxRequest->ucRequest )
\r
616 case usbSEND_ENCAPSULATED_COMMAND:
\r
620 case usbGET_ENCAPSULATED_RESPONSE:
\r
624 case usbSET_LINE_CODING:
\r
625 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
627 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
630 case usbGET_LINE_CODING:
\r
631 /* Get line coding */
\r
632 prvSendControlData( (unsigned portCHAR *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
635 case usbSET_CONTROL_LINE_STATE:
\r
636 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
638 ucControlState = pxRequest->usValue;
\r
646 /*------------------------------------------------------------*/
\r
648 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
650 switch( ( pxRequest->usValue & ( unsigned portSHORT ) 0xff00 ) >> 8 )
\r
657 /*-----------------------------------------------------------*/
\r
659 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
661 unsigned portSHORT usStatus = 0;
\r
663 switch( pxRequest->ucRequest )
\r
665 case usbGET_STATUS_REQUEST:
\r
666 /* Send dummy 2 bytes. */
\r
667 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
670 case usbGET_DESCRIPTOR_REQUEST:
\r
671 prvGetStandardInterfaceDescriptor( pxRequest );
\r
674 /* This minimal implementation does not respond to these. */
\r
675 case usbGET_INTERFACE_REQUEST:
\r
676 case usbSET_FEATURE_REQUEST:
\r
677 case usbSET_INTERFACE_REQUEST:
\r
684 /*-----------------------------------------------------------*/
\r
686 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
688 switch( pxRequest->ucRequest )
\r
690 /* This minimal implementation does not expect to respond to these. */
\r
691 case usbGET_STATUS_REQUEST:
\r
692 case usbCLEAR_FEATURE_REQUEST:
\r
693 case usbSET_FEATURE_REQUEST:
\r
700 /*-----------------------------------------------------------*/
\r
702 static void vDetachUSBInterface( void)
\r
704 /* Setup the PIO for the USB pull up resistor. */
\r
705 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
706 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
709 /* Disable pull up */
\r
710 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
712 /*-----------------------------------------------------------*/
\r
714 static void vInitUSBInterface( void )
\r
716 extern void ( vUSB_ISR_Wrapper )( void );
\r
718 /* Create the queue used to communicate between the USB ISR and task. */
\r
719 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
721 /* Create the queues used to hold Rx and Tx characters. */
\r
722 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned portCHAR ) sizeof( signed portCHAR ) );
\r
723 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned portCHAR ) sizeof( signed portCHAR ) );
\r
725 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
727 /* Not enough RAM to create queues!. */
\r
731 /* Initialise a few state variables. */
\r
732 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
733 pxControlRx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
734 ucUSBConfig = ( unsigned portCHAR ) 0;
\r
735 eDriverState = eNOTHING;
\r
736 ucControlState = 0;
\r
737 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
740 /* HARDWARE SETUP */
\r
742 /* Set the PLL USB Divider */
\r
743 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
745 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
746 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
747 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
749 /* Setup the PIO for the USB pull up resistor. */
\r
750 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
751 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
754 /* Start without the pullup - this will get set at the end of this
\r
756 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
759 /* When using the USB debugger the peripheral registers do not always get
\r
760 set to the correct default values. To make sure set the relevant registers
\r
762 AT91C_BASE_UDP->UDP_IDR = ( unsigned portLONG ) 0xffffffff;
\r
763 AT91C_BASE_UDP->UDP_ICR = ( unsigned portLONG ) 0xffffffff;
\r
764 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned portLONG ) 0x00;
\r
765 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned portLONG ) 0x00;
\r
766 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned portLONG ) 0x00;
\r
767 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned portLONG ) 0x00;
\r
768 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
769 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
771 /* Enable the transceiver. */
\r
772 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
774 /* Enable the USB interrupts - other interrupts get enabled as the
\r
775 enumeration process progresses. */
\r
776 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );
\r
777 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
780 /* Wait a short while before making our presence known. */
\r
781 vTaskDelay( usbINIT_DELAY );
\r
782 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
784 /*-----------------------------------------------------------*/
\r
786 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthToSend, portLONG lSendingDescriptor )
\r
788 if( ( ( unsigned portLONG ) usRequestedLength < ulLengthToSend ) )
\r
790 /* Cap the data length to that requested. */
\r
791 ulLengthToSend = ( unsigned portSHORT ) usRequestedLength;
\r
793 else if( ( ulLengthToSend < ( unsigned portLONG ) usRequestedLength ) && lSendingDescriptor )
\r
795 /* We are sending a descriptor. If the descriptor is an exact
\r
796 multiple of the FIFO length then it will have to be terminated
\r
797 with a NULL packet. Set the state to indicate this if
\r
799 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
801 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
805 /* Here we assume that the previous message has been sent. THERE IS NO
\r
806 BUFFER OVERFLOW PROTECTION HERE.
\r
808 Copy the data to send into the buffer as we cannot send it all at once
\r
809 (if it is greater than 8 bytes in length). */
\r
810 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
812 /* Reinitialise the buffer index so we start sending from the start of
\r
814 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
815 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
817 /* Send the first 8 bytes now. The rest will get sent in response to
\r
818 TXCOMP interrupts. */
\r
819 prvSendNextSegment();
\r
821 /*-----------------------------------------------------------*/
\r
823 static void prvSendNextSegment( void )
\r
825 volatile unsigned portLONG ulNextLength, ulStatus, ulLengthLeftToSend;
\r
827 /* Is there any data to send? */
\r
828 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
830 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
832 /* We can only send 8 bytes to the fifo at a time. */
\r
833 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
835 ulNextLength = usbFIFO_LENGTH;
\r
839 ulNextLength = ulLengthLeftToSend;
\r
842 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
844 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
846 vTaskDelay( usbSHORTEST_DELAY );
\r
849 /* Write the data to the FIFO. */
\r
850 while( ulNextLength > ( unsigned portLONG ) 0 )
\r
852 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
855 pxControlTx.ulNextCharIndex++;
\r
858 /* Start the transmission. */
\r
859 portENTER_CRITICAL();
\r
861 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
862 usbCSR_SET_BIT( &ulStatus, ( ( unsigned portLONG ) 0x10 ) );
\r
863 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
865 portEXIT_CRITICAL();
\r
869 /* There is no data to send. If we were sending a descriptor and the
\r
870 descriptor was an exact multiple of the max packet size then we need
\r
871 to send a null to terminate the transmission. */
\r
872 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
875 eDriverState = eNOTHING;
\r