2 FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 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 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
31 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
\r
32 with commercial development and support options.
\r
33 ***************************************************************************
\r
37 USB Communications Device Class driver.
\r
38 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
39 interface. Control is through endpoint 0, device-to-host notification is
\r
40 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
41 bulk endpoints 1 and 2.
\r
43 - developed from original FreeRTOS HID example by Scott Miller
\r
44 - modified to support 3.2 GCC by najay
\r
47 /* Standard includes. */
\r
51 /* Demo board includes. */
\r
54 /* Scheduler includes. */
\r
55 #include "FreeRTOS.h"
\r
59 /* Demo app includes. */
\r
60 #include "USB-CDC.h"
\r
61 #include "descriptors.h"
\r
63 #define usbNO_BLOCK ( ( portTickType ) 0 )
\r
65 /* Reset all endpoints */
\r
66 static void prvResetEndPoints( void );
\r
68 /* Clear pull up resistor to detach device from host */
\r
69 static void vDetachUSBInterface( void );
\r
71 /* Set up interface and initialize variables */
\r
72 static void vInitUSBInterface( void );
\r
74 /* Handle control endpoint events. */
\r
75 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
77 /* Handle standard device requests. */
\r
78 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
80 /* Handle standard interface requests. */
\r
81 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
83 /* Handle endpoint requests. */
\r
84 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
86 /* Handle class interface requests. */
\r
87 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
89 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
90 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthLeftToSend, portLONG lSendingDescriptor );
\r
92 /* Send next segment of data for the control transfer */
\r
93 static void prvSendNextSegment( void );
\r
95 /* Send stall - used to respond to unsupported requests */
\r
96 static void prvSendStall( void );
\r
98 /* Send a zero-length (null) packet */
\r
99 static void prvSendZLP( void );
\r
101 /* Handle requests for standard interface descriptors */
\r
102 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
104 /*------------------------------------------------------------*/
\r
106 /* File scope static variables */
\r
107 static unsigned portCHAR ucUSBConfig = ( unsigned portCHAR ) 0;
\r
108 static unsigned portLONG ulReceivedAddress = ( unsigned portLONG ) 0;
\r
109 static eDRIVER_STATE eDriverState = eNOTHING;
\r
111 /* Incoming and outgoing control data structures */
\r
112 static xCONTROL_MESSAGE pxControlTx;
\r
113 static xCONTROL_MESSAGE pxControlRx;
\r
115 /* Queue holding pointers to pending messages */
\r
116 xQueueHandle xUSBInterruptQueue;
\r
118 /* Queues used to hold received characters, and characters waiting to be
\r
119 transmitted. Rx queue must be larger than FIFO size. */
\r
120 static xQueueHandle xRxCDC;
\r
121 static xQueueHandle xTxCDC;
\r
123 /* Line coding - 115,200 baud, N-8-1 */
\r
124 static const unsigned portCHAR pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
126 /* Status variables. */
\r
127 static unsigned portCHAR ucControlState;
\r
128 static unsigned int uiCurrentBank;
\r
131 /*------------------------------------------------------------*/
\r
134 void vUSBCDCTask( void *pvParameters )
\r
136 xISRStatus *pxMessage;
\r
137 unsigned portLONG ulStatus;
\r
138 unsigned portLONG ulRxBytes;
\r
139 unsigned portCHAR ucByte;
\r
140 portBASE_TYPE xByte;
\r
142 ( void ) pvParameters;
\r
144 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
145 portENTER_CRITICAL();
\r
146 vDetachUSBInterface();
\r
147 portEXIT_CRITICAL();
\r
149 vTaskDelay( portTICK_RATE_MS * 60 );
\r
151 /* Init USB interface */
\r
152 portENTER_CRITICAL();
\r
153 vInitUSBInterface();
\r
154 portEXIT_CRITICAL();
\r
156 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
160 /* Look for data coming from the ISR. */
\r
161 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
163 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
165 /* All endpoint 0 interrupts are handled here. */
\r
166 prvProcessEndPoint0Interrupt( pxMessage );
\r
169 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
171 /* End of bus reset - reset the endpoints and de-configure. */
\r
172 prvResetEndPoints();
\r
176 /* See if we're ready to send and receive data. */
\r
177 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
179 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
181 for( xByte = 0; xByte < 64; xByte++ )
\r
183 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
185 /* No data buffered to transmit. */
\r
189 /* Got a byte to transmit. */
\r
190 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
192 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
195 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
196 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
198 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
200 /* Only process FIFO if there's room to store it in the queue */
\r
201 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
203 while( ulRxBytes-- )
\r
205 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
206 xQueueSend( xRxCDC, &ucByte, 0 );
\r
209 /* Release the FIFO */
\r
210 portENTER_CRITICAL();
\r
212 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
213 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
214 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
216 portEXIT_CRITICAL();
\r
218 /* Re-enable endpoint 1's interrupts */
\r
219 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
221 /* Update the current bank in use */
\r
222 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
224 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
228 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
240 /*------------------------------------------------------------*/
\r
242 void vUSBSendByte( portCHAR cByte )
\r
244 /* Queue the byte to be sent. The USB task will send it. */
\r
245 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
247 /*------------------------------------------------------------*/
\r
249 static void prvSendZLP( void )
\r
251 unsigned portLONG ulStatus;
\r
253 /* Wait until the FIFO is free - even though we are not going to use it.
\r
254 THERE IS NO TIMEOUT HERE! */
\r
255 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
257 vTaskDelay( usbSHORTEST_DELAY );
\r
260 portENTER_CRITICAL();
\r
262 /* Cancel any further pending data */
\r
263 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
265 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
266 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
267 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
268 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
270 portEXIT_CRITICAL();
\r
272 /*------------------------------------------------------------*/
\r
274 static void prvSendStall( void )
\r
276 unsigned portLONG ulStatus;
\r
278 portENTER_CRITICAL();
\r
280 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
281 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
282 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
283 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
285 portEXIT_CRITICAL();
\r
287 /*------------------------------------------------------------*/
\r
289 static void prvResetEndPoints( void )
\r
291 unsigned portLONG ulTemp;
\r
293 eDriverState = eJUST_RESET;
\r
294 ucControlState = 0;
\r
296 /* Reset all the end points. */
\r
297 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
298 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned portLONG ) 0x00;
\r
300 /* Enable data to be sent and received. */
\r
301 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
303 /* Repair the configuration end point. */
\r
304 portENTER_CRITICAL();
\r
306 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
307 usbCSR_SET_BIT( &ulTemp, ( ( unsigned portLONG ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
308 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
309 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
311 portEXIT_CRITICAL();
\r
312 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
314 /*------------------------------------------------------------*/
\r
316 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
318 static xUSB_REQUEST xRequest;
\r
319 unsigned portLONG ulRxBytes;
\r
321 /* Get number of bytes received, if any */
\r
322 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
323 ulRxBytes &= usbRX_COUNT_MASK;
\r
325 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
327 /* We received a TX complete interrupt. What we do depends on
\r
328 what we sent to get this interrupt. */
\r
330 if( eDriverState == eJUST_GOT_CONFIG )
\r
332 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
333 are now at the end of the enumeration.
\r
335 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
336 Request for unsupported config should stall. */
\r
337 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
339 /* Set up endpoints */
\r
340 portENTER_CRITICAL();
\r
342 unsigned portLONG ulTemp;
\r
344 /* Set endpoint 1 to bulk-out */
\r
345 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
346 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
347 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
348 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
349 /* Set endpoint 2 to bulk-in */
\r
350 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
351 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
352 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
353 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
354 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
355 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
356 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
357 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
358 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
360 portEXIT_CRITICAL();
\r
362 eDriverState = eREADY_TO_SEND;
\r
364 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
366 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
367 to the addressed state. */
\r
368 if( ulReceivedAddress != ( unsigned portLONG ) 0 )
\r
370 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
374 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
377 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
378 eDriverState = eNOTHING;
\r
382 /* The TXCOMP was not for any special type of transmission. See
\r
383 if there is any more data to send. */
\r
384 prvSendNextSegment();
\r
388 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
390 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
391 unsigned portCHAR ucBytesToGet;
\r
393 /* Got data. Cancel any outgoing data. */
\r
394 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
396 /* Determine how many bytes we need to receive. */
\r
397 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
398 if( ucBytesToGet > ulRxBytes )
\r
400 ucBytesToGet = ulRxBytes;
\r
403 /* If we're not expecting any data, it's an ack - just quit now. */
\r
404 if( !ucBytesToGet )
\r
409 /* Get the required data and update the index. */
\r
410 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
411 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
414 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
416 /* Received a SETUP packet. May be followed by data packets. */
\r
418 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
420 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
422 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
423 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
425 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
426 xRequest.usValue <<= 8;
\r
427 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
429 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
430 xRequest.usIndex <<= 8;
\r
431 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
433 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
434 xRequest.usLength <<= 8;
\r
435 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
437 pxControlRx.ulNextCharIndex = 0;
\r
438 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
440 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
442 /* Too big! No space for control data, stall and abort. */
\r
447 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
451 /* We're sending the data, don't wait for any. */
\r
452 pxControlRx.ulTotalDataLength = 0;
\r
457 /* See if we've got a pending request and all its associated data ready */
\r
458 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
459 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
461 unsigned portCHAR ucRequest;
\r
463 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
464 generate a zero based request selection. This is just done to
\r
465 break up the requests into subsections for clarity. The
\r
466 alternative would be to have more huge switch statement that would
\r
467 be difficult to optimise. */
\r
468 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
469 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
471 switch( ucRequest )
\r
473 case usbSTANDARD_DEVICE_REQUEST:
\r
474 /* Standard Device request */
\r
475 prvHandleStandardDeviceRequest( &xRequest );
\r
478 case usbSTANDARD_INTERFACE_REQUEST:
\r
479 /* Standard Interface request */
\r
480 prvHandleStandardInterfaceRequest( &xRequest );
\r
483 case usbSTANDARD_END_POINT_REQUEST:
\r
484 /* Standard Endpoint request */
\r
485 prvHandleStandardEndPointRequest( &xRequest );
\r
488 case usbCLASS_INTERFACE_REQUEST:
\r
489 /* Class Interface request */
\r
490 prvHandleClassInterfaceRequest( &xRequest );
\r
493 default: /* This is not something we want to respond to. */
\r
498 /*------------------------------------------------------------*/
\r
500 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
502 /* The type is in the high byte. Return whatever has been requested. */
\r
503 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
505 case usbDESCRIPTOR_TYPE_DEVICE:
\r
506 prvSendControlData( ( unsigned portCHAR * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
509 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
510 prvSendControlData( ( unsigned portCHAR * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
513 case usbDESCRIPTOR_TYPE_STRING:
\r
515 /* The index to the string descriptor is the lower byte. */
\r
516 switch( pxRequest->usValue & 0xff )
\r
518 case usbLANGUAGE_STRING:
\r
519 prvSendControlData( ( unsigned portCHAR * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
522 case usbMANUFACTURER_STRING:
\r
523 prvSendControlData( ( unsigned portCHAR * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
526 case usbPRODUCT_STRING:
\r
527 prvSendControlData( ( unsigned portCHAR * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
530 case usbCONFIGURATION_STRING:
\r
531 prvSendControlData( ( unsigned portCHAR * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
534 case usbINTERFACE_STRING:
\r
535 prvSendControlData( ( unsigned portCHAR * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
549 /*------------------------------------------------------------*/
\r
551 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
553 unsigned portSHORT usStatus = 0;
\r
555 switch( pxRequest->ucRequest )
\r
557 case usbGET_STATUS_REQUEST:
\r
558 /* Just send two byte dummy status. */
\r
559 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
562 case usbGET_DESCRIPTOR_REQUEST:
\r
563 /* Send device descriptor */
\r
564 prvGetStandardDeviceDescriptor( pxRequest );
\r
567 case usbGET_CONFIGURATION_REQUEST:
\r
568 /* Send selected device configuration */
\r
569 prvSendControlData( ( unsigned portCHAR * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
572 case usbSET_FEATURE_REQUEST:
\r
576 case usbSET_ADDRESS_REQUEST:
\r
577 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
579 eDriverState = eJUST_GOT_ADDRESS;
\r
580 ulReceivedAddress = ( unsigned portLONG ) pxRequest->usValue;
\r
583 case usbSET_CONFIGURATION_REQUEST:
\r
584 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
585 ucUSBConfig = ( unsigned portCHAR ) ( pxRequest->usValue & 0xff );
\r
586 eDriverState = eJUST_GOT_CONFIG;
\r
591 /* Any unsupported request results in a STALL response. */
\r
596 /*------------------------------------------------------------*/
\r
598 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
600 switch( pxRequest->ucRequest )
\r
602 case usbSEND_ENCAPSULATED_COMMAND:
\r
606 case usbGET_ENCAPSULATED_RESPONSE:
\r
610 case usbSET_LINE_CODING:
\r
611 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
613 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
616 case usbGET_LINE_CODING:
\r
617 /* Get line coding */
\r
618 prvSendControlData( (unsigned portCHAR *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
621 case usbSET_CONTROL_LINE_STATE:
\r
622 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
624 ucControlState = pxRequest->usValue;
\r
632 /*------------------------------------------------------------*/
\r
634 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
636 switch( ( pxRequest->usValue & ( unsigned portSHORT ) 0xff00 ) >> 8 )
\r
643 /*-----------------------------------------------------------*/
\r
645 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
647 unsigned portSHORT usStatus = 0;
\r
649 switch( pxRequest->ucRequest )
\r
651 case usbGET_STATUS_REQUEST:
\r
652 /* Send dummy 2 bytes. */
\r
653 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
656 case usbGET_DESCRIPTOR_REQUEST:
\r
657 prvGetStandardInterfaceDescriptor( pxRequest );
\r
660 /* This minimal implementation does not respond to these. */
\r
661 case usbGET_INTERFACE_REQUEST:
\r
662 case usbSET_FEATURE_REQUEST:
\r
663 case usbSET_INTERFACE_REQUEST:
\r
670 /*-----------------------------------------------------------*/
\r
672 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
674 switch( pxRequest->ucRequest )
\r
676 /* This minimal implementation does not expect to respond to these. */
\r
677 case usbGET_STATUS_REQUEST:
\r
678 case usbCLEAR_FEATURE_REQUEST:
\r
679 case usbSET_FEATURE_REQUEST:
\r
686 /*-----------------------------------------------------------*/
\r
688 static void vDetachUSBInterface( void)
\r
690 /* Setup the PIO for the USB pull up resistor. */
\r
691 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
692 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
695 /* Disable pull up */
\r
696 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
698 /*-----------------------------------------------------------*/
\r
700 static void vInitUSBInterface( void )
\r
702 extern void ( vUSB_ISR )( void );
\r
704 /* Create the queue used to communicate between the USB ISR and task. */
\r
705 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
707 /* Create the queues used to hold Rx and Tx characters. */
\r
708 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned portCHAR ) sizeof( signed portCHAR ) );
\r
709 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned portCHAR ) sizeof( signed portCHAR ) );
\r
711 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
713 /* Not enough RAM to create queues!. */
\r
717 /* Initialise a few state variables. */
\r
718 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
719 pxControlRx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
720 ucUSBConfig = ( unsigned portCHAR ) 0;
\r
721 eDriverState = eNOTHING;
\r
722 ucControlState = 0;
\r
723 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
726 /* HARDWARE SETUP */
\r
728 /* Set the PLL USB Divider */
\r
729 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
731 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
732 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
733 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
735 /* Setup the PIO for the USB pull up resistor. */
\r
736 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
737 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
740 /* Start without the pullup - this will get set at the end of this
\r
742 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
745 /* When using the USB debugger the peripheral registers do not always get
\r
746 set to the correct default values. To make sure set the relevant registers
\r
748 AT91C_BASE_UDP->UDP_IDR = ( unsigned portLONG ) 0xffffffff;
\r
749 AT91C_BASE_UDP->UDP_ICR = ( unsigned portLONG ) 0xffffffff;
\r
750 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned portLONG ) 0x00;
\r
751 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned portLONG ) 0x00;
\r
752 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned portLONG ) 0x00;
\r
753 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned portLONG ) 0x00;
\r
754 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
755 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
757 /* Enable the transceiver. */
\r
758 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
760 /* Enable the USB interrupts - other interrupts get enabled as the
\r
761 enumeration process progresses. */
\r
762 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR );
\r
763 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
766 /* Wait a short while before making our presence known. */
\r
767 vTaskDelay( usbINIT_DELAY );
\r
768 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
770 /*-----------------------------------------------------------*/
\r
772 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthToSend, portLONG lSendingDescriptor )
\r
774 if( ( ( unsigned portLONG ) usRequestedLength < ulLengthToSend ) )
\r
776 /* Cap the data length to that requested. */
\r
777 ulLengthToSend = ( unsigned portSHORT ) usRequestedLength;
\r
779 else if( ( ulLengthToSend < ( unsigned portLONG ) usRequestedLength ) && lSendingDescriptor )
\r
781 /* We are sending a descriptor. If the descriptor is an exact
\r
782 multiple of the FIFO length then it will have to be terminated
\r
783 with a NULL packet. Set the state to indicate this if
\r
785 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
787 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
791 /* Here we assume that the previous message has been sent. THERE IS NO
\r
792 BUFFER OVERFLOW PROTECTION HERE.
\r
794 Copy the data to send into the buffer as we cannot send it all at once
\r
795 (if it is greater than 8 bytes in length). */
\r
796 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
798 /* Reinitialise the buffer index so we start sending from the start of
\r
800 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
801 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
803 /* Send the first 8 bytes now. The rest will get sent in response to
\r
804 TXCOMP interrupts. */
\r
805 prvSendNextSegment();
\r
807 /*-----------------------------------------------------------*/
\r
809 static void prvSendNextSegment( void )
\r
811 volatile unsigned portLONG ulNextLength, ulStatus, ulLengthLeftToSend;
\r
813 /* Is there any data to send? */
\r
814 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
816 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
818 /* We can only send 8 bytes to the fifo at a time. */
\r
819 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
821 ulNextLength = usbFIFO_LENGTH;
\r
825 ulNextLength = ulLengthLeftToSend;
\r
828 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
830 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
832 vTaskDelay( usbSHORTEST_DELAY );
\r
835 /* Write the data to the FIFO. */
\r
836 while( ulNextLength > ( unsigned portLONG ) 0 )
\r
838 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
841 pxControlTx.ulNextCharIndex++;
\r
844 /* Start the transmission. */
\r
845 portENTER_CRITICAL();
\r
847 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
848 usbCSR_SET_BIT( &ulStatus, ( ( unsigned portLONG ) 0x10 ) );
\r
849 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
851 portEXIT_CRITICAL();
\r
855 /* There is no data to send. If we were sending a descriptor and the
\r
856 descriptor was an exact multiple of the max packet size then we need
\r
857 to send a null to terminate the transmission. */
\r
858 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
861 eDriverState = eNOTHING;
\r