2 FreeRTOS.org V4.0.2 - copyright (C) 2003-2006 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
30 ***************************************************************************
\r
34 USB Communications Device Class driver.
\r
35 Implements task vUSBCDCTask and provides an Abstract Control Model serial
\r
36 interface. Control is through endpoint 0, device-to-host notification is
\r
37 provided by interrupt-in endpoint 3, and raw data is transferred through
\r
38 bulk endpoints 1 and 2.
\r
40 - developed from original FreeRTOS HID example by Scott Miller
\r
41 - modified to support 3.2 GCC by najay
\r
44 /* Standard includes. */
\r
48 /* Demo board includes. */
\r
51 /* Scheduler includes. */
\r
52 #include "FreeRTOS.h"
\r
56 /* Demo app includes. */
\r
57 #include "USB-CDC.h"
\r
58 #include "descriptors.h"
\r
60 #define usbNO_BLOCK ( ( portTickType ) 0 )
\r
62 /* Reset all endpoints */
\r
63 static void prvResetEndPoints( void );
\r
65 /* Clear pull up resistor to detach device from host */
\r
66 static void vDetachUSBInterface( void );
\r
68 /* Set up interface and initialize variables */
\r
69 static void vInitUSBInterface( void );
\r
71 /* Handle control endpoint events. */
\r
72 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
74 /* Handle standard device requests. */
\r
75 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
77 /* Handle standard interface requests. */
\r
78 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
80 /* Handle endpoint requests. */
\r
81 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
83 /* Handle class interface requests. */
\r
84 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
86 /* Prepare control data transfer. prvSendNextSegment starts transfer. */
\r
87 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthLeftToSend, portLONG lSendingDescriptor );
\r
89 /* Send next segment of data for the control transfer */
\r
90 static void prvSendNextSegment( void );
\r
92 /* Send stall - used to respond to unsupported requests */
\r
93 static void prvSendStall( void );
\r
95 /* Send a zero-length (null) packet */
\r
96 static void prvSendZLP( void );
\r
98 /* Handle requests for standard interface descriptors */
\r
99 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
101 /*------------------------------------------------------------*/
\r
103 /* File scope static variables */
\r
104 static unsigned portCHAR ucUSBConfig = ( unsigned portCHAR ) 0;
\r
105 static unsigned portLONG ulReceivedAddress = ( unsigned portLONG ) 0;
\r
106 static eDRIVER_STATE eDriverState = eNOTHING;
\r
108 /* Incoming and outgoing control data structures */
\r
109 static xCONTROL_MESSAGE pxControlTx;
\r
110 static xCONTROL_MESSAGE pxControlRx;
\r
112 /* Queue holding pointers to pending messages */
\r
113 xQueueHandle xUSBInterruptQueue;
\r
115 /* Queues used to hold received characters, and characters waiting to be
\r
116 transmitted. Rx queue must be larger than FIFO size. */
\r
117 static xQueueHandle xRxCDC;
\r
118 static xQueueHandle xTxCDC;
\r
120 /* Line coding - 115,200 baud, N-8-1 */
\r
121 static const unsigned portCHAR pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };
\r
123 /* Status variables. */
\r
124 static unsigned portCHAR ucControlState;
\r
125 static unsigned int uiCurrentBank;
\r
128 /*------------------------------------------------------------*/
\r
131 void vUSBCDCTask( void *pvParameters )
\r
133 xISRStatus *pxMessage;
\r
134 unsigned portLONG ulStatus;
\r
135 unsigned portLONG ulRxBytes;
\r
136 unsigned portCHAR ucByte;
\r
137 portBASE_TYPE xByte;
\r
139 ( void ) pvParameters;
\r
141 /* Disconnect USB device from hub. For debugging - causes host to register reset */
\r
142 portENTER_CRITICAL();
\r
143 vDetachUSBInterface();
\r
144 portEXIT_CRITICAL();
\r
146 vTaskDelay( portTICK_RATE_MS * 60 );
\r
148 /* Init USB interface */
\r
149 portENTER_CRITICAL();
\r
150 vInitUSBInterface();
\r
151 portEXIT_CRITICAL();
\r
153 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */
\r
157 /* Look for data coming from the ISR. */
\r
158 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )
\r
160 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
162 /* All endpoint 0 interrupts are handled here. */
\r
163 prvProcessEndPoint0Interrupt( pxMessage );
\r
166 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
168 /* End of bus reset - reset the endpoints and de-configure. */
\r
169 prvResetEndPoints();
\r
173 /* See if we're ready to send and receive data. */
\r
174 if( eDriverState == eREADY_TO_SEND && ucControlState )
\r
176 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )
\r
178 for( xByte = 0; xByte < 64; xByte++ )
\r
180 if( !xQueueReceive( xTxCDC, &ucByte, 0 ) )
\r
182 /* No data buffered to transmit. */
\r
186 /* Got a byte to transmit. */
\r
187 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;
\r
189 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;
\r
192 /* Check for incoming data (host-to-device) on endpoint 1. */
\r
193 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )
\r
195 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;
\r
197 /* Only process FIFO if there's room to store it in the queue */
\r
198 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )
\r
200 while( ulRxBytes-- )
\r
202 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];
\r
203 xQueueSend( xRxCDC, &ucByte, 0 );
\r
206 /* Release the FIFO */
\r
207 portENTER_CRITICAL();
\r
209 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
210 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );
\r
211 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
213 portEXIT_CRITICAL();
\r
215 /* Re-enable endpoint 1's interrupts */
\r
216 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
218 /* Update the current bank in use */
\r
219 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 )
\r
221 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;
\r
225 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
237 /*------------------------------------------------------------*/
\r
239 void vUSBSendByte( portCHAR cByte )
\r
241 /* Queue the byte to be sent. The USB task will send it. */
\r
242 xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );
\r
244 /*------------------------------------------------------------*/
\r
246 static void prvSendZLP( void )
\r
248 unsigned portLONG ulStatus;
\r
250 /* Wait until the FIFO is free - even though we are not going to use it.
\r
251 THERE IS NO TIMEOUT HERE! */
\r
252 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
254 vTaskDelay( usbSHORTEST_DELAY );
\r
257 portENTER_CRITICAL();
\r
259 /* Cancel any further pending data */
\r
260 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;
\r
262 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
263 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
264 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );
\r
265 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
267 portEXIT_CRITICAL();
\r
269 /*------------------------------------------------------------*/
\r
271 static void prvSendStall( void )
\r
273 unsigned portLONG ulStatus;
\r
275 portENTER_CRITICAL();
\r
277 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
278 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
279 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
280 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
282 portEXIT_CRITICAL();
\r
284 /*------------------------------------------------------------*/
\r
286 static void prvResetEndPoints( void )
\r
288 unsigned portLONG ulTemp;
\r
290 eDriverState = eJUST_RESET;
\r
291 ucControlState = 0;
\r
293 /* Reset all the end points. */
\r
294 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
295 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned portLONG ) 0x00;
\r
297 /* Enable data to be sent and received. */
\r
298 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
300 /* Repair the configuration end point. */
\r
301 portENTER_CRITICAL();
\r
303 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
304 usbCSR_SET_BIT( &ulTemp, ( ( unsigned portLONG ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
305 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
306 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
\r
308 portEXIT_CRITICAL();
\r
309 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
311 /*------------------------------------------------------------*/
\r
313 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
315 static xUSB_REQUEST xRequest;
\r
316 unsigned portLONG ulRxBytes;
\r
318 /* Get number of bytes received, if any */
\r
319 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
320 ulRxBytes &= usbRX_COUNT_MASK;
\r
322 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
324 /* We received a TX complete interrupt. What we do depends on
\r
325 what we sent to get this interrupt. */
\r
327 if( eDriverState == eJUST_GOT_CONFIG )
\r
329 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
330 are now at the end of the enumeration.
\r
332 TODO: Config 0 sets unconfigured state, should enter Address state.
\r
333 Request for unsupported config should stall. */
\r
334 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
336 /* Set up endpoints */
\r
337 portENTER_CRITICAL();
\r
339 unsigned portLONG ulTemp;
\r
341 /* Set endpoint 1 to bulk-out */
\r
342 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
343 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );
\r
344 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
345 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;
\r
346 /* Set endpoint 2 to bulk-in */
\r
347 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];
\r
348 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );
\r
349 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;
\r
350 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;
\r
351 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */
\r
352 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];
\r
353 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
354 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;
\r
355 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */
\r
357 portEXIT_CRITICAL();
\r
359 eDriverState = eREADY_TO_SEND;
\r
361 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
363 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
364 to the addressed state. */
\r
365 if( ulReceivedAddress != ( unsigned portLONG ) 0 )
\r
367 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
371 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
374 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
375 eDriverState = eNOTHING;
\r
379 /* The TXCOMP was not for any special type of transmission. See
\r
380 if there is any more data to send. */
\r
381 prvSendNextSegment();
\r
385 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
387 /* Received a control data packet. May be a 0-length ACK or a data stage. */
\r
388 unsigned portCHAR ucBytesToGet;
\r
390 /* Got data. Cancel any outgoing data. */
\r
391 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;
\r
393 /* Determine how many bytes we need to receive. */
\r
394 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;
\r
395 if( ucBytesToGet > ulRxBytes )
\r
397 ucBytesToGet = ulRxBytes;
\r
400 /* If we're not expecting any data, it's an ack - just quit now. */
\r
401 if( !ucBytesToGet )
\r
406 /* Get the required data and update the index. */
\r
407 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );
\r
408 pxControlRx.ulNextCharIndex += ucBytesToGet;
\r
411 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
413 /* Received a SETUP packet. May be followed by data packets. */
\r
415 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
417 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
419 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
420 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
422 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
423 xRequest.usValue <<= 8;
\r
424 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
426 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
427 xRequest.usIndex <<= 8;
\r
428 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
430 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
431 xRequest.usLength <<= 8;
\r
432 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
434 pxControlRx.ulNextCharIndex = 0;
\r
435 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */
\r
437 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )
\r
439 /* Too big! No space for control data, stall and abort. */
\r
444 pxControlRx.ulTotalDataLength = xRequest.usLength;
\r
448 /* We're sending the data, don't wait for any. */
\r
449 pxControlRx.ulTotalDataLength = 0;
\r
454 /* See if we've got a pending request and all its associated data ready */
\r
455 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) )
\r
456 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )
\r
458 unsigned portCHAR ucRequest;
\r
460 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
461 generate a zero based request selection. This is just done to
\r
462 break up the requests into subsections for clarity. The
\r
463 alternative would be to have more huge switch statement that would
\r
464 be difficult to optimise. */
\r
465 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
466 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
468 switch( ucRequest )
\r
470 case usbSTANDARD_DEVICE_REQUEST:
\r
471 /* Standard Device request */
\r
472 prvHandleStandardDeviceRequest( &xRequest );
\r
475 case usbSTANDARD_INTERFACE_REQUEST:
\r
476 /* Standard Interface request */
\r
477 prvHandleStandardInterfaceRequest( &xRequest );
\r
480 case usbSTANDARD_END_POINT_REQUEST:
\r
481 /* Standard Endpoint request */
\r
482 prvHandleStandardEndPointRequest( &xRequest );
\r
485 case usbCLASS_INTERFACE_REQUEST:
\r
486 /* Class Interface request */
\r
487 prvHandleClassInterfaceRequest( &xRequest );
\r
490 default: /* This is not something we want to respond to. */
\r
495 /*------------------------------------------------------------*/
\r
497 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
499 /* The type is in the high byte. Return whatever has been requested. */
\r
500 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
502 case usbDESCRIPTOR_TYPE_DEVICE:
\r
503 prvSendControlData( ( unsigned portCHAR * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
506 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
507 prvSendControlData( ( unsigned portCHAR * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
510 case usbDESCRIPTOR_TYPE_STRING:
\r
512 /* The index to the string descriptor is the lower byte. */
\r
513 switch( pxRequest->usValue & 0xff )
\r
515 case usbLANGUAGE_STRING:
\r
516 prvSendControlData( ( unsigned portCHAR * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
519 case usbMANUFACTURER_STRING:
\r
520 prvSendControlData( ( unsigned portCHAR * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
523 case usbPRODUCT_STRING:
\r
524 prvSendControlData( ( unsigned portCHAR * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
527 case usbCONFIGURATION_STRING:
\r
528 prvSendControlData( ( unsigned portCHAR * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
531 case usbINTERFACE_STRING:
\r
532 prvSendControlData( ( unsigned portCHAR * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
546 /*------------------------------------------------------------*/
\r
548 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
550 unsigned portSHORT usStatus = 0;
\r
552 switch( pxRequest->ucRequest )
\r
554 case usbGET_STATUS_REQUEST:
\r
555 /* Just send two byte dummy status. */
\r
556 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
559 case usbGET_DESCRIPTOR_REQUEST:
\r
560 /* Send device descriptor */
\r
561 prvGetStandardDeviceDescriptor( pxRequest );
\r
564 case usbGET_CONFIGURATION_REQUEST:
\r
565 /* Send selected device configuration */
\r
566 prvSendControlData( ( unsigned portCHAR * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
569 case usbSET_FEATURE_REQUEST:
\r
573 case usbSET_ADDRESS_REQUEST:
\r
574 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */
\r
576 eDriverState = eJUST_GOT_ADDRESS;
\r
577 ulReceivedAddress = ( unsigned portLONG ) pxRequest->usValue;
\r
580 case usbSET_CONFIGURATION_REQUEST:
\r
581 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */
\r
582 ucUSBConfig = ( unsigned portCHAR ) ( pxRequest->usValue & 0xff );
\r
583 eDriverState = eJUST_GOT_CONFIG;
\r
588 /* Any unsupported request results in a STALL response. */
\r
593 /*------------------------------------------------------------*/
\r
595 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
597 switch( pxRequest->ucRequest )
\r
599 case usbSEND_ENCAPSULATED_COMMAND:
\r
603 case usbGET_ENCAPSULATED_RESPONSE:
\r
607 case usbSET_LINE_CODING:
\r
608 /* Set line coding - baud rate, data bits, parity, stop bits */
\r
610 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );
\r
613 case usbGET_LINE_CODING:
\r
614 /* Get line coding */
\r
615 prvSendControlData( (unsigned portCHAR *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );
\r
618 case usbSET_CONTROL_LINE_STATE:
\r
619 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */
\r
621 ucControlState = pxRequest->usValue;
\r
629 /*------------------------------------------------------------*/
\r
631 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
633 switch( ( pxRequest->usValue & ( unsigned portSHORT ) 0xff00 ) >> 8 )
\r
640 /*-----------------------------------------------------------*/
\r
642 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
644 unsigned portSHORT usStatus = 0;
\r
646 switch( pxRequest->ucRequest )
\r
648 case usbGET_STATUS_REQUEST:
\r
649 /* Send dummy 2 bytes. */
\r
650 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
653 case usbGET_DESCRIPTOR_REQUEST:
\r
654 prvGetStandardInterfaceDescriptor( pxRequest );
\r
657 /* This minimal implementation does not respond to these. */
\r
658 case usbGET_INTERFACE_REQUEST:
\r
659 case usbSET_FEATURE_REQUEST:
\r
660 case usbSET_INTERFACE_REQUEST:
\r
667 /*-----------------------------------------------------------*/
\r
669 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
671 switch( pxRequest->ucRequest )
\r
673 /* This minimal implementation does not expect to respond to these. */
\r
674 case usbGET_STATUS_REQUEST:
\r
675 case usbCLEAR_FEATURE_REQUEST:
\r
676 case usbSET_FEATURE_REQUEST:
\r
683 /*-----------------------------------------------------------*/
\r
685 static void vDetachUSBInterface( void)
\r
687 /* Setup the PIO for the USB pull up resistor. */
\r
688 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
689 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
692 /* Disable pull up */
\r
693 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
695 /*-----------------------------------------------------------*/
\r
697 static void vInitUSBInterface( void )
\r
699 extern void ( vUSB_ISR )( void );
\r
701 /* Create the queue used to communicate between the USB ISR and task. */
\r
702 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
704 /* Create the queues used to hold Rx and Tx characters. */
\r
705 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned portCHAR ) sizeof( signed portCHAR ) );
\r
706 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned portCHAR ) sizeof( signed portCHAR ) );
\r
708 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )
\r
710 /* Not enough RAM to create queues!. */
\r
714 /* Initialise a few state variables. */
\r
715 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
716 pxControlRx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
717 ucUSBConfig = ( unsigned portCHAR ) 0;
\r
718 eDriverState = eNOTHING;
\r
719 ucControlState = 0;
\r
720 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;
\r
723 /* HARDWARE SETUP */
\r
725 /* Set the PLL USB Divider */
\r
726 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
728 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
729 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
730 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
732 /* Setup the PIO for the USB pull up resistor. */
\r
733 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;
\r
734 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;
\r
737 /* Start without the pullup - this will get set at the end of this
\r
739 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;
\r
742 /* When using the USB debugger the peripheral registers do not always get
\r
743 set to the correct default values. To make sure set the relevant registers
\r
745 AT91C_BASE_UDP->UDP_IDR = ( unsigned portLONG ) 0xffffffff;
\r
746 AT91C_BASE_UDP->UDP_ICR = ( unsigned portLONG ) 0xffffffff;
\r
747 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned portLONG ) 0x00;
\r
748 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned portLONG ) 0x00;
\r
749 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned portLONG ) 0x00;
\r
750 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned portLONG ) 0x00;
\r
751 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
752 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
754 /* Enable the transceiver. */
\r
755 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
757 /* Enable the USB interrupts - other interrupts get enabled as the
\r
758 enumeration process progresses. */
\r
759 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR );
\r
760 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;
\r
763 /* Wait a short while before making our presence known. */
\r
764 vTaskDelay( usbINIT_DELAY );
\r
765 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;
\r
767 /*-----------------------------------------------------------*/
\r
769 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthToSend, portLONG lSendingDescriptor )
\r
771 if( ( ( unsigned portLONG ) usRequestedLength < ulLengthToSend ) )
\r
773 /* Cap the data length to that requested. */
\r
774 ulLengthToSend = ( unsigned portSHORT ) usRequestedLength;
\r
776 else if( ( ulLengthToSend < ( unsigned portLONG ) usRequestedLength ) && lSendingDescriptor )
\r
778 /* We are sending a descriptor. If the descriptor is an exact
\r
779 multiple of the FIFO length then it will have to be terminated
\r
780 with a NULL packet. Set the state to indicate this if
\r
782 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
784 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
788 /* Here we assume that the previous message has been sent. THERE IS NO
\r
789 BUFFER OVERFLOW PROTECTION HERE.
\r
791 Copy the data to send into the buffer as we cannot send it all at once
\r
792 (if it is greater than 8 bytes in length). */
\r
793 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );
\r
795 /* Reinitialise the buffer index so we start sending from the start of
\r
797 pxControlTx.ulTotalDataLength = ulLengthToSend;
\r
798 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0;
\r
800 /* Send the first 8 bytes now. The rest will get sent in response to
\r
801 TXCOMP interrupts. */
\r
802 prvSendNextSegment();
\r
804 /*-----------------------------------------------------------*/
\r
806 static void prvSendNextSegment( void )
\r
808 volatile unsigned portLONG ulNextLength, ulStatus, ulLengthLeftToSend;
\r
810 /* Is there any data to send? */
\r
811 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )
\r
813 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;
\r
815 /* We can only send 8 bytes to the fifo at a time. */
\r
816 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
818 ulNextLength = usbFIFO_LENGTH;
\r
822 ulNextLength = ulLengthLeftToSend;
\r
825 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
827 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
829 vTaskDelay( usbSHORTEST_DELAY );
\r
832 /* Write the data to the FIFO. */
\r
833 while( ulNextLength > ( unsigned portLONG ) 0 )
\r
835 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];
\r
838 pxControlTx.ulNextCharIndex++;
\r
841 /* Start the transmission. */
\r
842 portENTER_CRITICAL();
\r
844 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
845 usbCSR_SET_BIT( &ulStatus, ( ( unsigned portLONG ) 0x10 ) );
\r
846 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
848 portEXIT_CRITICAL();
\r
852 /* There is no data to send. If we were sending a descriptor and the
\r
853 descriptor was an exact multiple of the max packet size then we need
\r
854 to send a null to terminate the transmission. */
\r
855 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
858 eDriverState = eNOTHING;
\r