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 Sample interrupt driven USB device driver. This is a minimal implementation
\r
31 for demonstration only. Although functional, it is not a full and compliant
\r
34 The USB device enumerates as a simple 3 axis joystick, and once configured
\r
35 transmits 3 axis of data which can be viewed from the USB host machine.
\r
37 This file implements the USB interrupt service routine, and a demo FreeRTOS
\r
38 task. The interrupt service routine handles the USB hardware - taking a
\r
39 snapshot of the USB status at the point of the interrupt. The task receives
\r
40 the status information from the interrupt for processing at the task level.
\r
42 See the FreeRTOS.org WEB documentation for more information.
\r
48 + Descriptors that have a length that is an exact multiple of usbFIFO_LENGTH
\r
49 can now be transmitted. To this end an extra parameter has been
\r
50 added to the prvSendControlData() function, and the state
\r
51 eSENDING_EVEN_DESCRIPTOR has been introduced. Thanks to Scott Miller for
\r
52 assisting with this contribution.
\r
56 + Replaced the duplicated RX_DATA_BK0 in the interrupt mask with the
\r
60 /* Standard includes. */
\r
63 /* Demo board includes. */
\r
66 /* Scheduler includes. */
\r
67 #include "FreeRTOS.h"
\r
72 /* Descriptor type definitions. */
\r
73 #define usbDESCRIPTOR_TYPE_DEVICE ( 0x01 )
\r
74 #define usbDESCRIPTOR_TYPE_CONFIGURATION ( 0x02 )
\r
75 #define usbDESCRIPTOR_TYPE_STRING ( 0x03 )
\r
77 /* USB request type definitions. */
\r
78 #define usbGET_REPORT_REQUEST ( 0x01 )
\r
79 #define usbGET_IDLE_REQUEST ( 0x02 )
\r
80 #define usbGET_PROTOCOL_REQUEST ( 0x03 )
\r
81 #define usbSET_REPORT_REQUEST ( 0x09 )
\r
82 #define usbSET_IDLE_REQUEST ( 0x0A )
\r
83 #define usbSET_PROTOCOL_REQUEST ( 0x0B )
\r
84 #define usbGET_CONFIGURATION_REQUEST ( 0x08 )
\r
85 #define usbGET_STATUS_REQUEST ( 0x00 )
\r
86 #define usbCLEAR_FEATURE_REQUEST ( 0x01 )
\r
87 #define usbSET_FEATURE_REQUEST ( 0x03 )
\r
88 #define usbSET_ADDRESS_REQUEST ( 0x05 )
\r
89 #define usbGET_DESCRIPTOR_REQUEST ( 0x06 )
\r
90 #define usbSET_CONFIGURATION_REQUEST ( 0x09 )
\r
91 #define usbGET_INTERFACE_REQUEST ( 0x0A )
\r
92 #define usbSET_INTERFACE_REQUEST ( 0x0B )
\r
95 /* Misc USB definitions. */
\r
96 #define usbDEVICE_CLASS_VENDOR_SPECIFIC ( 0xFF )
\r
97 #define usbBUS_POWERED ( 0x80 )
\r
98 #define usbHID_REPORT_DESCRIPTOR ( 0x22 )
\r
99 #define AT91C_UDP_TRANSCEIVER_ENABLE ( *( ( unsigned long * ) 0xfffb0074 ) )
\r
101 /* Index to the various string. */
\r
102 #define usbLANGUAGE_STRING ( 0 )
\r
103 #define usbMANUFACTURER_STRING ( 1 )
\r
104 #define usbPRODUCT_STRING ( 2 )
\r
105 #define usbCONFIGURATION_STRING ( 3 )
\r
106 #define usbINTERFACE_STRING ( 4 )
\r
108 /* Data indexes for reading the request from the xISRStatus.ucFifoData[]
\r
109 into xUSB_REQUEST. The data order is designed for speed - so looks a
\r
111 #define usbREQUEST_TYPE_INDEX ( 7 )
\r
112 #define usbREQUEST_INDEX ( 6 )
\r
113 #define usbVALUE_HIGH_BYTE ( 4 )
\r
114 #define usbVALUE_LOW_BYTE ( 5 )
\r
115 #define usbINDEX_HIGH_BYTE ( 2 )
\r
116 #define usbINDEX_LOW_BYTE ( 3 )
\r
117 #define usbLENGTH_HIGH_BYTE ( 0 )
\r
118 #define usbLENGTH_LOW_BYTE ( 1 )
\r
120 /* Misc application definitions. */
\r
121 #define usbINTERRUPT_PRIORITY ( 3 )
\r
122 #define usbQUEUE_LENGTH ( 0x3 ) /* Must have all bits set! */
\r
123 #define usbFIFO_LENGTH ( ( unsigned long ) 8 )
\r
124 #define usbEND_POINT_0 ( 0 )
\r
125 #define usbEND_POINT_1 ( 1 )
\r
126 #define usbXUP ( 1 )
\r
127 #define usbXDOWN ( 2 )
\r
128 #define usbYUP ( 3 )
\r
129 #define usbYDOWN ( 4 )
\r
130 #define usbMAX_COORD ( 120 )
\r
131 #define usbMAX_TX_MESSAGE_SIZE ( 128 )
\r
132 #define usbRX_COUNT_MASK ( ( unsigned long ) 0x7ff )
\r
133 #define AT91C_UDP_STALLSENT AT91C_UDP_ISOERROR
\r
134 #define usbSHORTEST_DELAY ( ( TickType_t ) 1 )
\r
135 #define usbINIT_DELAY ( ( TickType_t ) 500 / portTICK_PERIOD_MS )
\r
136 #define usbSHORT_DELAY ( ( TickType_t ) 50 / portTICK_PERIOD_MS )
\r
137 #define usbEND_POINT_RESET_MASK ( ( unsigned long ) 0x0f )
\r
138 #define usbDATA_INC ( ( char ) 5 )
\r
139 #define usbEXPECTED_NUMBER_OF_BYTES ( ( unsigned long ) 8 )
\r
141 /* Control request types. */
\r
142 #define usbSTANDARD_DEVICE_REQUEST ( 0 )
\r
143 #define usbSTANDARD_INTERFACE_REQUEST ( 1 )
\r
144 #define usbSTANDARD_END_POINT_REQUEST ( 2 )
\r
145 #define usbCLASS_INTERFACE_REQUEST ( 5 )
\r
147 /*-----------------------------------------------------------*/
\r
149 /* Structure used to take a snapshot of the USB status from within the ISR. */
\r
150 typedef struct X_ISR_STATUS
\r
152 unsigned long ulISR;
\r
153 unsigned long ulCSR0;
\r
154 unsigned char ucFifoData[ 8 ];
\r
157 /* Structure used to hold the received requests. */
\r
160 unsigned char ucReqType;
\r
161 unsigned char ucRequest;
\r
162 unsigned short usValue;
\r
163 unsigned short usIndex;
\r
164 unsigned short usLength;
\r
173 eSENDING_EVEN_DESCRIPTOR,
\r
177 /* Structure used to control the data being sent to the host. */
\r
180 unsigned char ucTxBuffer[ usbMAX_TX_MESSAGE_SIZE ];
\r
181 unsigned long ulNextCharIndex;
\r
182 unsigned long ulTotalDataLength;
\r
185 /*-----------------------------------------------------------*/
\r
188 * The USB interrupt service routine. This takes a snapshot of the USB
\r
189 * device at the time of the interrupt, clears the interrupts, and posts
\r
190 * the data to the USB processing task.
\r
192 __arm void vUSB_ISR( void );
\r
195 * Called after the bus reset interrupt - this function readies all the
\r
196 * end points for communication.
\r
198 static void prvResetEndPoints( void );
\r
201 * Setup the USB hardware, install the interrupt service routine and
\r
202 * initialise all the state variables.
\r
204 static void vInitUSBInterface( void );
\r
207 * Decode and act upon an interrupt generated by the control end point.
\r
209 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
212 * For simplicity requests are separated into device, interface, class
\r
213 * interface and end point requests.
\r
215 * Decode and handle standard device requests originating on the control
\r
218 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
221 * For simplicity requests are separated into device, interface, class
\r
222 * interface and end point requests.
\r
224 * Decode and handle standard interface requests originating on the control
\r
227 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
230 * For simplicity requests are separated into device, interface, class
\r
231 * interface and end point requests.
\r
233 * Decode and handle standard end point requests originating on the control
\r
236 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
239 * For simplicity requests are separated into device, interface, class
\r
240 * interface and end point requests.
\r
242 * Decode and handle the class interface requests.
\r
244 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
247 * Setup the Tx buffer to send data in response to a control request.
\r
249 * The data to be transmitted is buffered, the state variables are updated,
\r
250 * then prvSendNextSegment() is called to start the transmission off. Once
\r
251 * the first segment has been sent the remaining segments are transmitted
\r
252 * in response to TXCOMP interrupts until the entire buffer has been
\r
255 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
258 * Examine the Tx buffer to see if there is any more data to be transmitted.
\r
260 * If there is data to be transmitted then send the next segment. A segment
\r
261 * can have a maximum of 8 bytes (this is defined as the maximum for the end
\r
262 * point by the descriptor). The final segment may be less than 8 bytes if
\r
263 * the total data length was not an exact multiple of 8.
\r
265 static void prvSendNextSegment( void );
\r
268 * A stall condition is forced each time the host makes a request that is not
\r
269 * supported by this minimal implementation.
\r
271 * A stall is forced by setting the appropriate bit in the end points control
\r
272 * and status register.
\r
274 static void prvSendStall( void );
\r
277 * A NULL (or zero length packet) is transmitted in acknowledge the reception
\r
278 * of certain events from the host.
\r
280 static void prvUSBTransmitNull( void );
\r
283 * When the host requests a descriptor this function is called to determine
\r
284 * which descriptor is being requested and start its transmission.
\r
286 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
289 * This demo USB device enumerates as a simple 3 axis joystick. Once
\r
290 * configured this function is periodically called to generate some sample
\r
293 * The x and y axis are made to move in a square. The z axis is made to
\r
294 * repeatedly increment up to its maximum.
\r
296 static void prvTransmitSampleValues( void );
\r
299 * The created task to handle the USB demo functionality.
\r
301 void vUSBDemoTask( void *pvParameters );
\r
303 /*-----------------------------------------------------------*/
\r
306 - DESCRIPTOR DEFINITIONS -
\r
309 /* String descriptors used during the enumeration process.
\r
310 These take the form:
\r
313 Length of descriptor,
\r
318 const char pxLanguageStringDescriptor[] =
\r
321 usbDESCRIPTOR_TYPE_STRING,
\r
325 const char pxManufacturerStringDescriptor[] =
\r
328 usbDESCRIPTOR_TYPE_STRING,
\r
340 const char pxProductStringDescriptor[] =
\r
343 usbDESCRIPTOR_TYPE_STRING,
\r
368 const char pxConfigurationStringDescriptor[] =
\r
371 usbDESCRIPTOR_TYPE_STRING,
\r
393 const char pxInterfaceStringDescriptor[] =
\r
396 usbDESCRIPTOR_TYPE_STRING,
\r
414 /* Enumeration descriptors. */
\r
415 const char pxReportDescriptor[] =
\r
417 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
\r
418 0x09, 0x04, /* USAGE (Joystick) */
\r
419 0xa1, 0x01, /* COLLECTION (Application) */
\r
420 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
\r
421 0x09, 0x01, /* USAGE (Pointer) */
\r
422 0xa1, 0x00, /* COLLECTION (Physical) */
\r
423 0x09, 0x30, /* USAGE (X) */
\r
424 0x09, 0x31, /* USAGE (Y) */
\r
425 0x09, 0x32, /* USAGE (Z) */
\r
426 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
\r
427 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
\r
428 0x75, 0x08, /* REPORT_SIZE (8) */
\r
429 0x95, 0x03, /* REPORT_COUNT (3) */
\r
430 0x81, 0x02, /* INPUT (Data,Var,Abs) */
\r
431 0xc0, /* END_COLLECTION */
\r
432 0xc0 /* END_COLLECTION */
\r
435 const char pxDeviceDescriptor[] =
\r
437 /* Device descriptor */
\r
438 0x12, /* bLength */
\r
439 0x01, /* bDescriptorType */
\r
440 0x10, 0x01, /* bcdUSBL */
\r
441 usbDEVICE_CLASS_VENDOR_SPECIFIC, /* bDeviceClass: */
\r
442 0x00, /* bDeviceSubclass: */
\r
443 0x00, /* bDeviceProtocol: */
\r
444 0x08, /* bMaxPacketSize0 */
\r
445 0xFF, 0xFF, /* idVendorL */
\r
446 0x01, 0x00, /* idProductL */
\r
447 0x00, 0x01, /* bcdDeviceL */
\r
448 usbMANUFACTURER_STRING, /* iManufacturer */
\r
449 usbPRODUCT_STRING, /* iProduct */
\r
450 0x00, /* SerialNumber */
\r
451 0x01 /* bNumConfigs */
\r
454 const char pxConfigDescriptor[] = {
\r
455 /* Configuration 1 descriptor */
\r
456 0x09, /* CbLength */
\r
457 0x02, /* CbDescriptorType */
\r
458 0x22, 0x00, /* CwTotalLength 2 EP + Control */
\r
459 0x01, /* CbNumInterfaces */
\r
460 0x01, /* CbConfigurationValue */
\r
461 usbCONFIGURATION_STRING,/* CiConfiguration */
\r
462 usbBUS_POWERED, /* CbmAttributes Bus powered + Remote Wakeup*/
\r
463 0x32, /* CMaxPower: 100mA */
\r
465 /* Joystick Interface Descriptor Requirement */
\r
466 0x09, /* bLength */
\r
467 0x04, /* bDescriptorType */
\r
468 0x00, /* bInterfaceNumber */
\r
469 0x00, /* bAlternateSetting */
\r
470 0x01, /* bNumEndpoints */
\r
471 0x03, /* bInterfaceClass: HID code */
\r
472 0x00, /* bInterfaceSubclass */
\r
473 0x00, /* bInterfaceProtocol */
\r
474 usbINTERFACE_STRING,/* iInterface */
\r
476 /* HID Descriptor */
\r
477 0x09, /* bLength */
\r
478 0x21, /* bDescriptor type: HID Descriptor Type */
\r
479 0x00, 0x01, /* bcdHID */
\r
480 0x00, /* bCountryCode */
\r
481 0x01, /* bNumDescriptors */
\r
482 usbHID_REPORT_DESCRIPTOR, /* bDescriptorType */
\r
483 sizeof( pxReportDescriptor ), 0x00, /* wItemLength */
\r
485 /* Endpoint 1 descriptor */
\r
486 0x07, /* bLength */
\r
487 0x05, /* bDescriptorType */
\r
488 0x81, /* bEndpointAddress, Endpoint 01 - IN */
\r
489 0x03, /* bmAttributes INT */
\r
490 0x03, 0x00, /* wMaxPacketSize: 3 bytes (x, y, z) */
\r
491 0x0A /* bInterval */
\r
494 /*-----------------------------------------------------------*/
\r
496 /* File scope state variables. */
\r
497 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
498 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
499 static eDRIVER_STATE eDriverState = eNOTHING;
\r
501 /* Array in which the USB interrupt status is passed between the ISR and task. */
\r
502 static xISRStatus xISRMessages[ usbQUEUE_LENGTH + 1 ];
\r
504 /* Structure used to control the characters being sent to the host. */
\r
505 static xTX_MESSAGE pxCharsForTx;
\r
507 /* Queue used to pass messages between the ISR and the task. */
\r
508 static QueueHandle_t xUSBInterruptQueue;
\r
510 /* ISR entry has to be written in the asm file as we want a context switch
\r
511 to occur from within the ISR. See the port documentation on the FreeRTOS.org
\r
512 WEB site for more information. */
\r
513 extern void vUSBISREntry( void );
\r
515 /*-----------------------------------------------------------*/
\r
517 /* Macros to manipulate the control and status registers. These registers
\r
518 cannot be accessed using a direct read modify write operation outside of the
\r
519 ISR as some bits are left unchanged by writing with a 0, and some are left
\r
520 unchanged by writing with a 1. */
\r
522 #define usbINT_CLEAR_MASK (AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 )
\r
524 #define usbCSR_SET_BIT( pulValueNow, ulBit ) \
\r
526 /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \
\r
527 /* STALLSENT and RX_DATA_BK1 to 1 so the */ \
\r
528 /* write has no effect. */ \
\r
529 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( unsigned long ) 0x4f; \
\r
531 /* Clear the FORCE_STALL and TXPKTRDY bits */ \
\r
532 /* so the write has no effect. */ \
\r
533 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( unsigned long ) 0xffffffcf; \
\r
535 /* Set whichever bit we want set. */ \
\r
536 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( ulBit ); \
\r
539 #define usbCSR_CLEAR_BIT( pulValueNow, ulBit ) \
\r
541 /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \
\r
542 /* STALLSENT and RX_DATA_BK1 to 1 so the */ \
\r
543 /* write has no effect. */ \
\r
544 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( unsigned long ) 0x4f; \
\r
546 /* Clear the FORCE_STALL and TXPKTRDY bits */ \
\r
547 /* so the write has no effect. */ \
\r
548 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( unsigned long ) 0xffffffcf; \
\r
550 /* Clear whichever bit we want clear. */ \
\r
551 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( ~ulBit ); \
\r
554 /*-----------------------------------------------------------*/
\r
556 __arm void vUSB_ISR( void )
\r
558 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
559 static volatile unsigned long ulNextMessage = 0;
\r
560 xISRStatus *pxMessage;
\r
561 unsigned long ulTemp, ulRxBytes;
\r
563 /* Take the next message from the queue. Note that usbQUEUE_LENGTH *must*
\r
564 be all 1's, as in 0x01, 0x03, 0x07, etc. */
\r
565 pxMessage = &( xISRMessages[ ( ulNextMessage & usbQUEUE_LENGTH ) ] );
\r
568 /* Take a snapshot of the current USB state for processing at the task
\r
570 pxMessage->ulISR = AT91C_BASE_UDP->UDP_ISR;
\r
571 pxMessage->ulCSR0 = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
573 /* Clear the interrupts from the ICR register. The bus end interrupt is
\r
574 cleared separately as it does not appear in the mask register. */
\r
575 AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_IMR | AT91C_UDP_ENDBUSRES;
\r
577 /* If there are bytes in the FIFO then we have to retrieve them here.
\r
578 Ideally this would be done at the task level. However we need to clear the
\r
579 RXSETUP interrupt before leaving the ISR, and this may cause the data in
\r
580 the FIFO to be overwritten. Also the DIR bit has to be changed before the
\r
581 RXSETUP bit is cleared (as per the SAM7 manual). */
\r
582 ulTemp = pxMessage->ulCSR0;
\r
584 /* Are there any bytes in the FIFO? */
\r
585 ulRxBytes = ulTemp >> 16;
\r
586 ulRxBytes &= usbRX_COUNT_MASK;
\r
588 /* With this minimal implementation we are only interested in receiving
\r
589 setup bytes on the control end point. */
\r
590 if( ( ulRxBytes > 0 ) && ( ulTemp & AT91C_UDP_RXSETUP ) )
\r
592 /* Take off 1 for a zero based index. */
\r
593 while( ulRxBytes > 0 )
\r
596 pxMessage->ucFifoData[ ulRxBytes ] = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ];
\r
599 /* The direction must be changed first. */
\r
600 usbCSR_SET_BIT( &ulTemp, ( AT91C_UDP_DIR ) );
\r
601 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
604 /* Must write zero's to TXCOMP, STALLSENT, RXSETUP, and the RX DATA
\r
605 registers to clear the interrupts in the CSR register. */
\r
606 usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
\r
607 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
609 /* Also clear the interrupts in the CSR1 register. */
\r
610 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
611 usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
\r
612 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
614 /* The message now contains the entire state and optional data from
\r
615 the USB interrupt. This can now be posted on the Rx queue ready for
\r
616 processing at the task level. */
\r
617 xQueueSendFromISR( xUSBInterruptQueue, &pxMessage, &xHigherPriorityTaskWoken );
\r
619 /* We may want to switch to the USB task, if this message has made
\r
620 it the highest priority task that is ready to execute. */
\r
621 portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
\r
623 /* Clear the AIC ready for the next interrupt. */
\r
624 AT91C_BASE_AIC->AIC_EOICR = 0;
\r
626 /*-----------------------------------------------------------*/
\r
628 void vUSBDemoTask( void *pvParameters )
\r
630 xISRStatus *pxMessage;
\r
632 /* The parameters are not used in this task. */
\r
633 ( void ) pvParameters;
\r
635 /* Init USB device */
\r
636 portENTER_CRITICAL();
\r
637 vInitUSBInterface();
\r
638 portEXIT_CRITICAL();
\r
640 /* Process interrupts as they arrive. The ISR takes a snapshot of the
\r
641 interrupt status then posts the information on this queue for processing
\r
642 at the task level. This simple demo implementation only processes
\r
643 a few interrupt sources. */
\r
646 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORT_DELAY ) )
\r
648 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
650 /* Process end point 0 interrupt. */
\r
651 prvProcessEndPoint0Interrupt( pxMessage );
\r
654 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
656 /* Process an end of bus reset interrupt. */
\r
657 prvResetEndPoints();
\r
662 /* The ISR did not post any data for us to process on the queue, so
\r
663 just generate and send some sample data. */
\r
664 if( eDriverState == eREADY_TO_SEND )
\r
666 prvTransmitSampleValues();
\r
671 /*-----------------------------------------------------------*/
\r
673 static void prvTransmitSampleValues( void )
\r
675 unsigned long ulStatus;
\r
676 static long lState = usbXUP;
\r
678 /* Variables to hold dummy x, y and z joystick axis data. */
\r
679 static signed char x = 0, y = 0, z = 0;
\r
681 /* Generate some sample data in the x and y axis - draw a square. */
\r
684 case usbXUP : x += usbDATA_INC;
\r
685 if( x >= usbMAX_COORD )
\r
691 case usbXDOWN : x -= usbDATA_INC;
\r
692 if( x <= -usbMAX_COORD )
\r
698 case usbYUP : y += usbDATA_INC;
\r
699 if( y >= usbMAX_COORD )
\r
705 case usbYDOWN : y -= usbDATA_INC;
\r
706 if( y <= -usbMAX_COORD )
\r
713 /* Just make the z axis go up and down. */
\r
716 /* Can we place data in the fifo? */
\r
717 if( !( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & AT91C_UDP_TXPKTRDY ) )
\r
719 /* Write our sample data to the fifo. */
\r
720 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = x;
\r
721 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = y;
\r
722 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = z;
\r
724 /* Send the data. */
\r
725 portENTER_CRITICAL();
\r
727 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
728 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
\r
729 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
731 portEXIT_CRITICAL();
\r
734 /*-----------------------------------------------------------*/
\r
736 static void prvUSBTransmitNull( void )
\r
738 unsigned long ulStatus;
\r
740 /* Wait until the FIFO is free - even though we are not going to use it.
\r
741 THERE IS NO TIMEOUT HERE! */
\r
742 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
744 vTaskDelay( usbSHORTEST_DELAY );
\r
747 portENTER_CRITICAL();
\r
749 /* Set the length of data to send to equal the index of the next byte
\r
750 to send. This will prevent the ACK to this NULL packet causing any
\r
751 further data transmissions. */
\r
752 pxCharsForTx.ulTotalDataLength = pxCharsForTx.ulNextCharIndex;
\r
754 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
755 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
756 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
\r
757 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
759 portEXIT_CRITICAL();
\r
761 /*-----------------------------------------------------------*/
\r
763 static void prvSendStall( void )
\r
765 unsigned long ulStatus;
\r
767 portENTER_CRITICAL();
\r
769 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
770 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
771 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
772 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
774 portEXIT_CRITICAL();
\r
776 /*-----------------------------------------------------------*/
\r
778 static void prvResetEndPoints( void )
\r
780 unsigned long ulTemp;
\r
782 eDriverState = eJUST_RESET;
\r
784 /* Reset all the end points. */
\r
785 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
786 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
788 /* Enable data to be sent and received. */
\r
789 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
791 /* Repair the configuration end point. */
\r
792 portENTER_CRITICAL();
\r
794 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
795 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
796 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
797 AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT0 );
\r
799 portEXIT_CRITICAL();
\r
801 /*-----------------------------------------------------------*/
\r
803 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
805 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
807 /* We only expect to receive zero length data here as ACK's.
\r
808 Set the data pointer to the end of the current Tx packet to
\r
809 ensure we don't send out any more data. */
\r
810 pxCharsForTx.ulNextCharIndex = pxCharsForTx.ulTotalDataLength;
\r
813 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
815 /* We received a TX complete interrupt. What we do depends on
\r
816 what we sent to get this interrupt. */
\r
818 if( eDriverState == eJUST_GOT_CONFIG )
\r
820 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
821 are now at the end of the enumeration. */
\r
822 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
824 /* Read the end point for data transfer. */
\r
825 portENTER_CRITICAL();
\r
827 unsigned long ulTemp;
\r
829 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
830 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
831 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
832 AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT1 );
\r
834 portEXIT_CRITICAL();
\r
836 eDriverState = eREADY_TO_SEND;
\r
838 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
840 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
841 to the addressed state. */
\r
842 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
844 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
848 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
851 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
852 eDriverState = eNOTHING;
\r
856 /* The TXCOMP was not for any special type of transmission. See
\r
857 if there is any more data to send. */
\r
858 prvSendNextSegment();
\r
862 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
864 xUSB_REQUEST xRequest;
\r
865 unsigned char ucRequest;
\r
866 unsigned long ulRxBytes;
\r
868 /* A data packet is available. */
\r
869 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
870 ulRxBytes &= usbRX_COUNT_MASK;
\r
872 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
874 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
876 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
877 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
879 /* NOT PORTABLE CODE! */
\r
880 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
881 xRequest.usValue <<= 8;
\r
882 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
884 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
885 xRequest.usIndex <<= 8;
\r
886 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
888 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
889 xRequest.usLength <<= 8;
\r
890 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
892 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
893 generate a zero based request selection. This is just done to
\r
894 break up the requests into subsections for clarity. The
\r
895 alternative would be to have more huge switch statement that would
\r
896 be difficult to optimise. */
\r
897 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
898 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
900 switch( ucRequest )
\r
902 case usbSTANDARD_DEVICE_REQUEST:
\r
903 /* Standard Device request */
\r
904 prvHandleStandardDeviceRequest( &xRequest );
\r
907 case usbSTANDARD_INTERFACE_REQUEST:
\r
908 /* Standard Interface request */
\r
909 prvHandleStandardInterfaceRequest( &xRequest );
\r
912 case usbSTANDARD_END_POINT_REQUEST:
\r
913 /* Standard Endpoint request */
\r
914 prvHandleStandardEndPointRequest( &xRequest );
\r
917 case usbCLASS_INTERFACE_REQUEST:
\r
918 /* Class Interface request */
\r
919 prvHandleClassInterfaceRequest( &xRequest );
\r
922 default: /* This is not something we want to respond to. */
\r
928 /*-----------------------------------------------------------*/
\r
930 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
932 /* The type is in the high byte. Return whatever has been requested. */
\r
933 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
935 case usbDESCRIPTOR_TYPE_DEVICE:
\r
936 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
939 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
940 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
943 case usbDESCRIPTOR_TYPE_STRING:
\r
945 /* The index to the string descriptor is the lower byte. */
\r
946 switch( pxRequest->usValue & 0xff )
\r
948 case usbLANGUAGE_STRING:
\r
949 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
952 case usbMANUFACTURER_STRING:
\r
953 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
956 case usbPRODUCT_STRING:
\r
957 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
960 case usbCONFIGURATION_STRING:
\r
961 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
964 case usbINTERFACE_STRING:
\r
965 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
969 /* Don't know what this string is. */
\r
977 /* We are not responding to anything else. */
\r
982 /*-----------------------------------------------------------*/
\r
984 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
986 unsigned short usStatus = 0;
\r
988 switch( pxRequest->ucRequest )
\r
990 case usbGET_STATUS_REQUEST:
\r
991 /* Just send two byte dummy status. */
\r
992 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
995 case usbGET_DESCRIPTOR_REQUEST:
\r
996 /* Send device descriptor */
\r
997 prvGetStandardDeviceDescriptor( pxRequest );
\r
1000 case usbGET_CONFIGURATION_REQUEST:
\r
1001 /* Send selected device configuration */
\r
1002 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
1005 case usbSET_FEATURE_REQUEST:
\r
1006 prvUSBTransmitNull();
\r
1009 case usbSET_ADDRESS_REQUEST:
\r
1011 /* Acknowledge the SET_ADDRESS, but (according to the manual) we
\r
1012 cannot actually move to the addressed state until we get a TXCOMP
\r
1013 interrupt from this NULL packet. Therefore we just remember the
\r
1014 address and set our state so we know we have received the address. */
\r
1015 prvUSBTransmitNull();
\r
1016 eDriverState = eJUST_GOT_ADDRESS;
\r
1017 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
1020 case usbSET_CONFIGURATION_REQUEST:
\r
1022 /* Acknowledge the SET_CONFIGURATION, but (according to the manual)
\r
1023 we cannot actually move to the configured state until we get a
\r
1024 TXCOMP interrupt from this NULL packet. Therefore we just remember the
\r
1025 config and set our state so we know we have received the go ahead. */
\r
1026 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
1027 eDriverState = eJUST_GOT_CONFIG;
\r
1028 prvUSBTransmitNull();
\r
1033 /* We don't answer to anything else. */
\r
1038 /*-----------------------------------------------------------*/
\r
1040 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
1042 switch( pxRequest->ucRequest )
\r
1044 case usbSET_IDLE_REQUEST:
\r
1045 prvUSBTransmitNull();
\r
1048 /* This minimal implementation ignores these. */
\r
1049 case usbGET_REPORT_REQUEST:
\r
1050 case usbGET_IDLE_REQUEST:
\r
1051 case usbGET_PROTOCOL_REQUEST:
\r
1052 case usbSET_REPORT_REQUEST:
\r
1053 case usbSET_PROTOCOL_REQUEST:
\r
1060 /*-----------------------------------------------------------*/
\r
1062 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
1064 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
1066 case usbHID_REPORT_DESCRIPTOR:
\r
1067 prvSendControlData( ( unsigned char * ) pxReportDescriptor, pxRequest->usLength, sizeof( pxReportDescriptor ), pdTRUE );
\r
1072 /* Don't expect to send any others. */
\r
1077 /*-----------------------------------------------------------*/
\r
1079 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
1081 unsigned short usStatus = 0;
\r
1083 switch( pxRequest->ucRequest )
\r
1085 case usbGET_STATUS_REQUEST:
\r
1086 /* Send dummy 2 bytes. */
\r
1087 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
1090 case usbGET_DESCRIPTOR_REQUEST:
\r
1091 prvGetStandardInterfaceDescriptor( pxRequest );
\r
1094 /* This minimal implementation does not respond to these. */
\r
1095 case usbGET_INTERFACE_REQUEST:
\r
1096 case usbSET_FEATURE_REQUEST:
\r
1097 case usbSET_INTERFACE_REQUEST:
\r
1104 /*-----------------------------------------------------------*/
\r
1106 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
1108 switch( pxRequest->ucRequest )
\r
1110 /* This minimal implementation does not expect to respond to these. */
\r
1111 case usbGET_STATUS_REQUEST:
\r
1112 case usbCLEAR_FEATURE_REQUEST:
\r
1113 case usbSET_FEATURE_REQUEST:
\r
1120 /*-----------------------------------------------------------*/
\r
1122 static void vInitUSBInterface( void )
\r
1124 volatile unsigned long ulTemp;
\r
1126 /* Create the queue used to communicate between the USB ISR and task. */
\r
1127 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
1129 /* Initialise a few state variables. */
\r
1130 pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;
\r
1131 ucUSBConfig = ( unsigned char ) 0;
\r
1132 eDriverState = eNOTHING;
\r
1134 /* HARDWARE SETUP */
\r
1136 /* Set the PLL USB Divider */
\r
1137 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
1139 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
1140 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
1141 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
1143 /* Setup the PIO for the USB pull up resistor. */
\r
1144 AT91F_PIO_CfgOutput(AT91C_BASE_PIOA,AT91C_PIO_PA16);
\r
1146 /* Start without the pullup - this will get set at the end of this
\r
1148 AT91F_PIO_SetOutput( AT91C_BASE_PIOA, AT91C_PIO_PA16 );
\r
1150 /* When using the USB debugger the peripheral registers do not always get
\r
1151 set to the correct default values. To make sure set the relevant registers
\r
1153 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
1154 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
1155 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
1156 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
1157 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
1158 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
1160 /* Enable the transceiver. */
\r
1161 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
1163 /* Enable the USB interrupts - other interrupts get enabled as the
\r
1164 enumeration process progresses. */
\r
1165 AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ( void (*)( void ) ) vUSBISREntry );
\r
1166 AT91F_AIC_EnableIt( AT91C_BASE_AIC, AT91C_ID_UDP );
\r
1168 /* Wait a short while before making our presence known. */
\r
1169 vTaskDelay( usbINIT_DELAY );
\r
1170 AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA16 );
\r
1172 /*-----------------------------------------------------------*/
\r
1174 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
1176 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
1178 /* Cap the data length to that requested. */
\r
1179 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
1181 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
1183 /* We are sending a descriptor. If the descriptor is an exact
\r
1184 multiple of the FIFO length then it will have to be terminated
\r
1185 with a NULL packet. Set the state to indicate this if
\r
1187 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
1189 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
1193 /* Here we assume that the previous message has been sent. THERE IS NO
\r
1194 BUFFER OVERFLOW PROTECTION HERE.
\r
1196 Copy the data to send into the buffer as we cannot send it all at once
\r
1197 (if it is greater than 8 bytes in length). */
\r
1198 memcpy( pxCharsForTx.ucTxBuffer, pucData, ulLengthToSend );
\r
1200 /* Reinitialise the buffer index so we start sending from the start of
\r
1202 pxCharsForTx.ulTotalDataLength = ulLengthToSend;
\r
1203 pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;
\r
1205 /* Send the first 8 bytes now. The rest will get sent in response to
\r
1206 TXCOMP interrupts. */
\r
1207 prvSendNextSegment();
\r
1209 /*-----------------------------------------------------------*/
\r
1211 static void prvSendNextSegment( void )
\r
1213 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
1215 /* Is there any data to send? */
\r
1216 if( pxCharsForTx.ulTotalDataLength > pxCharsForTx.ulNextCharIndex )
\r
1218 ulLengthLeftToSend = pxCharsForTx.ulTotalDataLength - pxCharsForTx.ulNextCharIndex;
\r
1220 /* We can only send 8 bytes to the fifo at a time. */
\r
1221 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
1223 ulNextLength = usbFIFO_LENGTH;
\r
1227 ulNextLength = ulLengthLeftToSend;
\r
1230 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
1232 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
1234 vTaskDelay( usbSHORTEST_DELAY );
\r
1237 /* Write the data to the FIFO. */
\r
1238 while( ulNextLength > ( unsigned long ) 0 )
\r
1240 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxCharsForTx.ucTxBuffer[ pxCharsForTx.ulNextCharIndex ];
\r
1243 pxCharsForTx.ulNextCharIndex++;
\r
1246 /* Start the transmission. */
\r
1247 portENTER_CRITICAL();
\r
1249 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
1250 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
1251 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
1253 portEXIT_CRITICAL();
\r
1257 /* There is no data to send. If we were sending a descriptor and the
\r
1258 descriptor was an exact multiple of the max packet size then we need
\r
1259 to send a null to terminate the transmission. */
\r
1260 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
1262 prvUSBTransmitNull();
\r
1263 eDriverState = eNOTHING;
\r