2 * FreeRTOS Kernel V10.0.1
\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.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 Sample interrupt driven USB device driver. This is a minimal implementation
\r
30 for demonstration only. Although functional, it is not a full and compliant
\r
33 The USB device enumerates as a simple 3 axis joystick, and once configured
\r
34 transmits 3 axis of data which can be viewed from the USB host machine.
\r
36 This file implements the USB interrupt service routine, and a demo FreeRTOS
\r
37 task. The interrupt service routine handles the USB hardware - taking a
\r
38 snapshot of the USB status at the point of the interrupt. The task receives
\r
39 the status information from the interrupt for processing at the task level.
\r
41 See the FreeRTOS.org WEB documentation for more information.
\r
47 + Descriptors that have a length that is an exact multiple of usbFIFO_LENGTH
\r
48 can now be transmitted. To this end an extra parameter has been
\r
49 added to the prvSendControlData() function, and the state
\r
50 eSENDING_EVEN_DESCRIPTOR has been introduced. Thanks to Scott Miller for
\r
51 assisting with this contribution.
\r
55 + Replaced the duplicated RX_DATA_BK0 in the interrupt mask with the
\r
59 /* Standard includes. */
\r
62 /* Demo board includes. */
\r
65 /* Scheduler includes. */
\r
66 #include "FreeRTOS.h"
\r
71 /* Descriptor type definitions. */
\r
72 #define usbDESCRIPTOR_TYPE_DEVICE ( 0x01 )
\r
73 #define usbDESCRIPTOR_TYPE_CONFIGURATION ( 0x02 )
\r
74 #define usbDESCRIPTOR_TYPE_STRING ( 0x03 )
\r
76 /* USB request type definitions. */
\r
77 #define usbGET_REPORT_REQUEST ( 0x01 )
\r
78 #define usbGET_IDLE_REQUEST ( 0x02 )
\r
79 #define usbGET_PROTOCOL_REQUEST ( 0x03 )
\r
80 #define usbSET_REPORT_REQUEST ( 0x09 )
\r
81 #define usbSET_IDLE_REQUEST ( 0x0A )
\r
82 #define usbSET_PROTOCOL_REQUEST ( 0x0B )
\r
83 #define usbGET_CONFIGURATION_REQUEST ( 0x08 )
\r
84 #define usbGET_STATUS_REQUEST ( 0x00 )
\r
85 #define usbCLEAR_FEATURE_REQUEST ( 0x01 )
\r
86 #define usbSET_FEATURE_REQUEST ( 0x03 )
\r
87 #define usbSET_ADDRESS_REQUEST ( 0x05 )
\r
88 #define usbGET_DESCRIPTOR_REQUEST ( 0x06 )
\r
89 #define usbSET_CONFIGURATION_REQUEST ( 0x09 )
\r
90 #define usbGET_INTERFACE_REQUEST ( 0x0A )
\r
91 #define usbSET_INTERFACE_REQUEST ( 0x0B )
\r
94 /* Misc USB definitions. */
\r
95 #define usbDEVICE_CLASS_VENDOR_SPECIFIC ( 0xFF )
\r
96 #define usbBUS_POWERED ( 0x80 )
\r
97 #define usbHID_REPORT_DESCRIPTOR ( 0x22 )
\r
98 #define AT91C_UDP_TRANSCEIVER_ENABLE ( *( ( unsigned long * ) 0xfffb0074 ) )
\r
100 /* Index to the various string. */
\r
101 #define usbLANGUAGE_STRING ( 0 )
\r
102 #define usbMANUFACTURER_STRING ( 1 )
\r
103 #define usbPRODUCT_STRING ( 2 )
\r
104 #define usbCONFIGURATION_STRING ( 3 )
\r
105 #define usbINTERFACE_STRING ( 4 )
\r
107 /* Data indexes for reading the request from the xISRStatus.ucFifoData[]
\r
108 into xUSB_REQUEST. The data order is designed for speed - so looks a
\r
110 #define usbREQUEST_TYPE_INDEX ( 7 )
\r
111 #define usbREQUEST_INDEX ( 6 )
\r
112 #define usbVALUE_HIGH_BYTE ( 4 )
\r
113 #define usbVALUE_LOW_BYTE ( 5 )
\r
114 #define usbINDEX_HIGH_BYTE ( 2 )
\r
115 #define usbINDEX_LOW_BYTE ( 3 )
\r
116 #define usbLENGTH_HIGH_BYTE ( 0 )
\r
117 #define usbLENGTH_LOW_BYTE ( 1 )
\r
119 /* Misc application definitions. */
\r
120 #define usbINTERRUPT_PRIORITY ( 3 )
\r
121 #define usbQUEUE_LENGTH ( 0x3 ) /* Must have all bits set! */
\r
122 #define usbFIFO_LENGTH ( ( unsigned long ) 8 )
\r
123 #define usbEND_POINT_0 ( 0 )
\r
124 #define usbEND_POINT_1 ( 1 )
\r
125 #define usbXUP ( 1 )
\r
126 #define usbXDOWN ( 2 )
\r
127 #define usbYUP ( 3 )
\r
128 #define usbYDOWN ( 4 )
\r
129 #define usbMAX_COORD ( 120 )
\r
130 #define usbMAX_TX_MESSAGE_SIZE ( 128 )
\r
131 #define usbRX_COUNT_MASK ( ( unsigned long ) 0x7ff )
\r
132 #define AT91C_UDP_STALLSENT AT91C_UDP_ISOERROR
\r
133 #define usbSHORTEST_DELAY ( ( TickType_t ) 1 )
\r
134 #define usbINIT_DELAY ( ( TickType_t ) 500 / portTICK_PERIOD_MS )
\r
135 #define usbSHORT_DELAY ( ( TickType_t ) 50 / portTICK_PERIOD_MS )
\r
136 #define usbEND_POINT_RESET_MASK ( ( unsigned long ) 0x0f )
\r
137 #define usbDATA_INC ( ( char ) 5 )
\r
138 #define usbEXPECTED_NUMBER_OF_BYTES ( ( unsigned long ) 8 )
\r
140 /* Control request types. */
\r
141 #define usbSTANDARD_DEVICE_REQUEST ( 0 )
\r
142 #define usbSTANDARD_INTERFACE_REQUEST ( 1 )
\r
143 #define usbSTANDARD_END_POINT_REQUEST ( 2 )
\r
144 #define usbCLASS_INTERFACE_REQUEST ( 5 )
\r
146 /*-----------------------------------------------------------*/
\r
148 /* Structure used to take a snapshot of the USB status from within the ISR. */
\r
149 typedef struct X_ISR_STATUS
\r
151 unsigned long ulISR;
\r
152 unsigned long ulCSR0;
\r
153 unsigned char ucFifoData[ 8 ];
\r
156 /* Structure used to hold the received requests. */
\r
159 unsigned char ucReqType;
\r
160 unsigned char ucRequest;
\r
161 unsigned short usValue;
\r
162 unsigned short usIndex;
\r
163 unsigned short usLength;
\r
172 eSENDING_EVEN_DESCRIPTOR,
\r
176 /* Structure used to control the data being sent to the host. */
\r
179 unsigned char ucTxBuffer[ usbMAX_TX_MESSAGE_SIZE ];
\r
180 unsigned long ulNextCharIndex;
\r
181 unsigned long ulTotalDataLength;
\r
184 /*-----------------------------------------------------------*/
\r
187 * The USB interrupt service routine. This takes a snapshot of the USB
\r
188 * device at the time of the interrupt, clears the interrupts, and posts
\r
189 * the data to the USB processing task.
\r
191 __arm void vUSB_ISR( void );
\r
194 * Called after the bus reset interrupt - this function readies all the
\r
195 * end points for communication.
\r
197 static void prvResetEndPoints( void );
\r
200 * Setup the USB hardware, install the interrupt service routine and
\r
201 * initialise all the state variables.
\r
203 static void vInitUSBInterface( void );
\r
206 * Decode and act upon an interrupt generated by the control end point.
\r
208 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
211 * For simplicity requests are separated into device, interface, class
\r
212 * interface and end point requests.
\r
214 * Decode and handle standard device requests originating on the control
\r
217 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
220 * For simplicity requests are separated into device, interface, class
\r
221 * interface and end point requests.
\r
223 * Decode and handle standard interface requests originating on the control
\r
226 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
229 * For simplicity requests are separated into device, interface, class
\r
230 * interface and end point requests.
\r
232 * Decode and handle standard end point requests originating on the control
\r
235 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
238 * For simplicity requests are separated into device, interface, class
\r
239 * interface and end point requests.
\r
241 * Decode and handle the class interface requests.
\r
243 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
246 * Setup the Tx buffer to send data in response to a control request.
\r
248 * The data to be transmitted is buffered, the state variables are updated,
\r
249 * then prvSendNextSegment() is called to start the transmission off. Once
\r
250 * the first segment has been sent the remaining segments are transmitted
\r
251 * in response to TXCOMP interrupts until the entire buffer has been
\r
254 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
257 * Examine the Tx buffer to see if there is any more data to be transmitted.
\r
259 * If there is data to be transmitted then send the next segment. A segment
\r
260 * can have a maximum of 8 bytes (this is defined as the maximum for the end
\r
261 * point by the descriptor). The final segment may be less than 8 bytes if
\r
262 * the total data length was not an exact multiple of 8.
\r
264 static void prvSendNextSegment( void );
\r
267 * A stall condition is forced each time the host makes a request that is not
\r
268 * supported by this minimal implementation.
\r
270 * A stall is forced by setting the appropriate bit in the end points control
\r
271 * and status register.
\r
273 static void prvSendStall( void );
\r
276 * A NULL (or zero length packet) is transmitted in acknowledge the reception
\r
277 * of certain events from the host.
\r
279 static void prvUSBTransmitNull( void );
\r
282 * When the host requests a descriptor this function is called to determine
\r
283 * which descriptor is being requested and start its transmission.
\r
285 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
288 * This demo USB device enumerates as a simple 3 axis joystick. Once
\r
289 * configured this function is periodically called to generate some sample
\r
292 * The x and y axis are made to move in a square. The z axis is made to
\r
293 * repeatedly increment up to its maximum.
\r
295 static void prvTransmitSampleValues( void );
\r
298 * The created task to handle the USB demo functionality.
\r
300 void vUSBDemoTask( void *pvParameters );
\r
302 /*-----------------------------------------------------------*/
\r
305 - DESCRIPTOR DEFINITIONS -
\r
308 /* String descriptors used during the enumeration process.
\r
309 These take the form:
\r
312 Length of descriptor,
\r
317 const char pxLanguageStringDescriptor[] =
\r
320 usbDESCRIPTOR_TYPE_STRING,
\r
324 const char pxManufacturerStringDescriptor[] =
\r
327 usbDESCRIPTOR_TYPE_STRING,
\r
339 const char pxProductStringDescriptor[] =
\r
342 usbDESCRIPTOR_TYPE_STRING,
\r
367 const char pxConfigurationStringDescriptor[] =
\r
370 usbDESCRIPTOR_TYPE_STRING,
\r
392 const char pxInterfaceStringDescriptor[] =
\r
395 usbDESCRIPTOR_TYPE_STRING,
\r
413 /* Enumeration descriptors. */
\r
414 const char pxReportDescriptor[] =
\r
416 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
\r
417 0x09, 0x04, /* USAGE (Joystick) */
\r
418 0xa1, 0x01, /* COLLECTION (Application) */
\r
419 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
\r
420 0x09, 0x01, /* USAGE (Pointer) */
\r
421 0xa1, 0x00, /* COLLECTION (Physical) */
\r
422 0x09, 0x30, /* USAGE (X) */
\r
423 0x09, 0x31, /* USAGE (Y) */
\r
424 0x09, 0x32, /* USAGE (Z) */
\r
425 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
\r
426 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
\r
427 0x75, 0x08, /* REPORT_SIZE (8) */
\r
428 0x95, 0x03, /* REPORT_COUNT (3) */
\r
429 0x81, 0x02, /* INPUT (Data,Var,Abs) */
\r
430 0xc0, /* END_COLLECTION */
\r
431 0xc0 /* END_COLLECTION */
\r
434 const char pxDeviceDescriptor[] =
\r
436 /* Device descriptor */
\r
437 0x12, /* bLength */
\r
438 0x01, /* bDescriptorType */
\r
439 0x10, 0x01, /* bcdUSBL */
\r
440 usbDEVICE_CLASS_VENDOR_SPECIFIC, /* bDeviceClass: */
\r
441 0x00, /* bDeviceSubclass: */
\r
442 0x00, /* bDeviceProtocol: */
\r
443 0x08, /* bMaxPacketSize0 */
\r
444 0xFF, 0xFF, /* idVendorL */
\r
445 0x01, 0x00, /* idProductL */
\r
446 0x00, 0x01, /* bcdDeviceL */
\r
447 usbMANUFACTURER_STRING, /* iManufacturer */
\r
448 usbPRODUCT_STRING, /* iProduct */
\r
449 0x00, /* SerialNumber */
\r
450 0x01 /* bNumConfigs */
\r
453 const char pxConfigDescriptor[] = {
\r
454 /* Configuration 1 descriptor */
\r
455 0x09, /* CbLength */
\r
456 0x02, /* CbDescriptorType */
\r
457 0x22, 0x00, /* CwTotalLength 2 EP + Control */
\r
458 0x01, /* CbNumInterfaces */
\r
459 0x01, /* CbConfigurationValue */
\r
460 usbCONFIGURATION_STRING,/* CiConfiguration */
\r
461 usbBUS_POWERED, /* CbmAttributes Bus powered + Remote Wakeup*/
\r
462 0x32, /* CMaxPower: 100mA */
\r
464 /* Joystick Interface Descriptor Requirement */
\r
465 0x09, /* bLength */
\r
466 0x04, /* bDescriptorType */
\r
467 0x00, /* bInterfaceNumber */
\r
468 0x00, /* bAlternateSetting */
\r
469 0x01, /* bNumEndpoints */
\r
470 0x03, /* bInterfaceClass: HID code */
\r
471 0x00, /* bInterfaceSubclass */
\r
472 0x00, /* bInterfaceProtocol */
\r
473 usbINTERFACE_STRING,/* iInterface */
\r
475 /* HID Descriptor */
\r
476 0x09, /* bLength */
\r
477 0x21, /* bDescriptor type: HID Descriptor Type */
\r
478 0x00, 0x01, /* bcdHID */
\r
479 0x00, /* bCountryCode */
\r
480 0x01, /* bNumDescriptors */
\r
481 usbHID_REPORT_DESCRIPTOR, /* bDescriptorType */
\r
482 sizeof( pxReportDescriptor ), 0x00, /* wItemLength */
\r
484 /* Endpoint 1 descriptor */
\r
485 0x07, /* bLength */
\r
486 0x05, /* bDescriptorType */
\r
487 0x81, /* bEndpointAddress, Endpoint 01 - IN */
\r
488 0x03, /* bmAttributes INT */
\r
489 0x03, 0x00, /* wMaxPacketSize: 3 bytes (x, y, z) */
\r
490 0x0A /* bInterval */
\r
493 /*-----------------------------------------------------------*/
\r
495 /* File scope state variables. */
\r
496 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
497 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
498 static eDRIVER_STATE eDriverState = eNOTHING;
\r
500 /* Array in which the USB interrupt status is passed between the ISR and task. */
\r
501 static xISRStatus xISRMessages[ usbQUEUE_LENGTH + 1 ];
\r
503 /* Structure used to control the characters being sent to the host. */
\r
504 static xTX_MESSAGE pxCharsForTx;
\r
506 /* Queue used to pass messages between the ISR and the task. */
\r
507 static QueueHandle_t xUSBInterruptQueue;
\r
509 /* ISR entry has to be written in the asm file as we want a context switch
\r
510 to occur from within the ISR. See the port documentation on the FreeRTOS.org
\r
511 WEB site for more information. */
\r
512 extern void vUSBISREntry( void );
\r
514 /*-----------------------------------------------------------*/
\r
516 /* Macros to manipulate the control and status registers. These registers
\r
517 cannot be accessed using a direct read modify write operation outside of the
\r
518 ISR as some bits are left unchanged by writing with a 0, and some are left
\r
519 unchanged by writing with a 1. */
\r
521 #define usbINT_CLEAR_MASK (AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 )
\r
523 #define usbCSR_SET_BIT( pulValueNow, ulBit ) \
\r
525 /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \
\r
526 /* STALLSENT and RX_DATA_BK1 to 1 so the */ \
\r
527 /* write has no effect. */ \
\r
528 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( unsigned long ) 0x4f; \
\r
530 /* Clear the FORCE_STALL and TXPKTRDY bits */ \
\r
531 /* so the write has no effect. */ \
\r
532 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( unsigned long ) 0xffffffcf; \
\r
534 /* Set whichever bit we want set. */ \
\r
535 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( ulBit ); \
\r
538 #define usbCSR_CLEAR_BIT( pulValueNow, ulBit ) \
\r
540 /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \
\r
541 /* STALLSENT and RX_DATA_BK1 to 1 so the */ \
\r
542 /* write has no effect. */ \
\r
543 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( unsigned long ) 0x4f; \
\r
545 /* Clear the FORCE_STALL and TXPKTRDY bits */ \
\r
546 /* so the write has no effect. */ \
\r
547 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( unsigned long ) 0xffffffcf; \
\r
549 /* Clear whichever bit we want clear. */ \
\r
550 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( ~ulBit ); \
\r
553 /*-----------------------------------------------------------*/
\r
555 __arm void vUSB_ISR( void )
\r
557 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
558 static volatile unsigned long ulNextMessage = 0;
\r
559 xISRStatus *pxMessage;
\r
560 unsigned long ulTemp, ulRxBytes;
\r
562 /* Take the next message from the queue. Note that usbQUEUE_LENGTH *must*
\r
563 be all 1's, as in 0x01, 0x03, 0x07, etc. */
\r
564 pxMessage = &( xISRMessages[ ( ulNextMessage & usbQUEUE_LENGTH ) ] );
\r
567 /* Take a snapshot of the current USB state for processing at the task
\r
569 pxMessage->ulISR = AT91C_BASE_UDP->UDP_ISR;
\r
570 pxMessage->ulCSR0 = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
572 /* Clear the interrupts from the ICR register. The bus end interrupt is
\r
573 cleared separately as it does not appear in the mask register. */
\r
574 AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_IMR | AT91C_UDP_ENDBUSRES;
\r
576 /* If there are bytes in the FIFO then we have to retrieve them here.
\r
577 Ideally this would be done at the task level. However we need to clear the
\r
578 RXSETUP interrupt before leaving the ISR, and this may cause the data in
\r
579 the FIFO to be overwritten. Also the DIR bit has to be changed before the
\r
580 RXSETUP bit is cleared (as per the SAM7 manual). */
\r
581 ulTemp = pxMessage->ulCSR0;
\r
583 /* Are there any bytes in the FIFO? */
\r
584 ulRxBytes = ulTemp >> 16;
\r
585 ulRxBytes &= usbRX_COUNT_MASK;
\r
587 /* With this minimal implementation we are only interested in receiving
\r
588 setup bytes on the control end point. */
\r
589 if( ( ulRxBytes > 0 ) && ( ulTemp & AT91C_UDP_RXSETUP ) )
\r
591 /* Take off 1 for a zero based index. */
\r
592 while( ulRxBytes > 0 )
\r
595 pxMessage->ucFifoData[ ulRxBytes ] = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ];
\r
598 /* The direction must be changed first. */
\r
599 usbCSR_SET_BIT( &ulTemp, ( AT91C_UDP_DIR ) );
\r
600 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
603 /* Must write zero's to TXCOMP, STALLSENT, RXSETUP, and the RX DATA
\r
604 registers to clear the interrupts in the CSR register. */
\r
605 usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
\r
606 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
608 /* Also clear the interrupts in the CSR1 register. */
\r
609 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
610 usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
\r
611 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
613 /* The message now contains the entire state and optional data from
\r
614 the USB interrupt. This can now be posted on the Rx queue ready for
\r
615 processing at the task level. */
\r
616 xQueueSendFromISR( xUSBInterruptQueue, &pxMessage, &xHigherPriorityTaskWoken );
\r
618 /* We may want to switch to the USB task, if this message has made
\r
619 it the highest priority task that is ready to execute. */
\r
620 portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
\r
622 /* Clear the AIC ready for the next interrupt. */
\r
623 AT91C_BASE_AIC->AIC_EOICR = 0;
\r
625 /*-----------------------------------------------------------*/
\r
627 void vUSBDemoTask( void *pvParameters )
\r
629 xISRStatus *pxMessage;
\r
631 /* The parameters are not used in this task. */
\r
632 ( void ) pvParameters;
\r
634 /* Init USB device */
\r
635 portENTER_CRITICAL();
\r
636 vInitUSBInterface();
\r
637 portEXIT_CRITICAL();
\r
639 /* Process interrupts as they arrive. The ISR takes a snapshot of the
\r
640 interrupt status then posts the information on this queue for processing
\r
641 at the task level. This simple demo implementation only processes
\r
642 a few interrupt sources. */
\r
645 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORT_DELAY ) )
\r
647 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
649 /* Process end point 0 interrupt. */
\r
650 prvProcessEndPoint0Interrupt( pxMessage );
\r
653 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
655 /* Process an end of bus reset interrupt. */
\r
656 prvResetEndPoints();
\r
661 /* The ISR did not post any data for us to process on the queue, so
\r
662 just generate and send some sample data. */
\r
663 if( eDriverState == eREADY_TO_SEND )
\r
665 prvTransmitSampleValues();
\r
670 /*-----------------------------------------------------------*/
\r
672 static void prvTransmitSampleValues( void )
\r
674 unsigned long ulStatus;
\r
675 static long lState = usbXUP;
\r
677 /* Variables to hold dummy x, y and z joystick axis data. */
\r
678 static signed char x = 0, y = 0, z = 0;
\r
680 /* Generate some sample data in the x and y axis - draw a square. */
\r
683 case usbXUP : x += usbDATA_INC;
\r
684 if( x >= usbMAX_COORD )
\r
690 case usbXDOWN : x -= usbDATA_INC;
\r
691 if( x <= -usbMAX_COORD )
\r
697 case usbYUP : y += usbDATA_INC;
\r
698 if( y >= usbMAX_COORD )
\r
704 case usbYDOWN : y -= usbDATA_INC;
\r
705 if( y <= -usbMAX_COORD )
\r
712 /* Just make the z axis go up and down. */
\r
715 /* Can we place data in the fifo? */
\r
716 if( !( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & AT91C_UDP_TXPKTRDY ) )
\r
718 /* Write our sample data to the fifo. */
\r
719 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = x;
\r
720 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = y;
\r
721 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = z;
\r
723 /* Send the data. */
\r
724 portENTER_CRITICAL();
\r
726 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
727 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
\r
728 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
730 portEXIT_CRITICAL();
\r
733 /*-----------------------------------------------------------*/
\r
735 static void prvUSBTransmitNull( void )
\r
737 unsigned long ulStatus;
\r
739 /* Wait until the FIFO is free - even though we are not going to use it.
\r
740 THERE IS NO TIMEOUT HERE! */
\r
741 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
743 vTaskDelay( usbSHORTEST_DELAY );
\r
746 portENTER_CRITICAL();
\r
748 /* Set the length of data to send to equal the index of the next byte
\r
749 to send. This will prevent the ACK to this NULL packet causing any
\r
750 further data transmissions. */
\r
751 pxCharsForTx.ulTotalDataLength = pxCharsForTx.ulNextCharIndex;
\r
753 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
754 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
755 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
\r
756 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
758 portEXIT_CRITICAL();
\r
760 /*-----------------------------------------------------------*/
\r
762 static void prvSendStall( void )
\r
764 unsigned long ulStatus;
\r
766 portENTER_CRITICAL();
\r
768 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
769 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
770 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
771 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
773 portEXIT_CRITICAL();
\r
775 /*-----------------------------------------------------------*/
\r
777 static void prvResetEndPoints( void )
\r
779 unsigned long ulTemp;
\r
781 eDriverState = eJUST_RESET;
\r
783 /* Reset all the end points. */
\r
784 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
785 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
787 /* Enable data to be sent and received. */
\r
788 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
790 /* Repair the configuration end point. */
\r
791 portENTER_CRITICAL();
\r
793 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
794 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
795 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
796 AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT0 );
\r
798 portEXIT_CRITICAL();
\r
800 /*-----------------------------------------------------------*/
\r
802 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
804 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
806 /* We only expect to receive zero length data here as ACK's.
\r
807 Set the data pointer to the end of the current Tx packet to
\r
808 ensure we don't send out any more data. */
\r
809 pxCharsForTx.ulNextCharIndex = pxCharsForTx.ulTotalDataLength;
\r
812 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
814 /* We received a TX complete interrupt. What we do depends on
\r
815 what we sent to get this interrupt. */
\r
817 if( eDriverState == eJUST_GOT_CONFIG )
\r
819 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
820 are now at the end of the enumeration. */
\r
821 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
823 /* Read the end point for data transfer. */
\r
824 portENTER_CRITICAL();
\r
826 unsigned long ulTemp;
\r
828 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
829 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
830 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
831 AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT1 );
\r
833 portEXIT_CRITICAL();
\r
835 eDriverState = eREADY_TO_SEND;
\r
837 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
839 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
840 to the addressed state. */
\r
841 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
843 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
847 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
850 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
851 eDriverState = eNOTHING;
\r
855 /* The TXCOMP was not for any special type of transmission. See
\r
856 if there is any more data to send. */
\r
857 prvSendNextSegment();
\r
861 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
863 xUSB_REQUEST xRequest;
\r
864 unsigned char ucRequest;
\r
865 unsigned long ulRxBytes;
\r
867 /* A data packet is available. */
\r
868 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
869 ulRxBytes &= usbRX_COUNT_MASK;
\r
871 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
873 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
875 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
876 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
878 /* NOT PORTABLE CODE! */
\r
879 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
880 xRequest.usValue <<= 8;
\r
881 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
883 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
884 xRequest.usIndex <<= 8;
\r
885 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
887 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
888 xRequest.usLength <<= 8;
\r
889 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
891 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
892 generate a zero based request selection. This is just done to
\r
893 break up the requests into subsections for clarity. The
\r
894 alternative would be to have more huge switch statement that would
\r
895 be difficult to optimise. */
\r
896 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
897 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
899 switch( ucRequest )
\r
901 case usbSTANDARD_DEVICE_REQUEST:
\r
902 /* Standard Device request */
\r
903 prvHandleStandardDeviceRequest( &xRequest );
\r
906 case usbSTANDARD_INTERFACE_REQUEST:
\r
907 /* Standard Interface request */
\r
908 prvHandleStandardInterfaceRequest( &xRequest );
\r
911 case usbSTANDARD_END_POINT_REQUEST:
\r
912 /* Standard Endpoint request */
\r
913 prvHandleStandardEndPointRequest( &xRequest );
\r
916 case usbCLASS_INTERFACE_REQUEST:
\r
917 /* Class Interface request */
\r
918 prvHandleClassInterfaceRequest( &xRequest );
\r
921 default: /* This is not something we want to respond to. */
\r
927 /*-----------------------------------------------------------*/
\r
929 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
931 /* The type is in the high byte. Return whatever has been requested. */
\r
932 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
934 case usbDESCRIPTOR_TYPE_DEVICE:
\r
935 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
938 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
939 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
942 case usbDESCRIPTOR_TYPE_STRING:
\r
944 /* The index to the string descriptor is the lower byte. */
\r
945 switch( pxRequest->usValue & 0xff )
\r
947 case usbLANGUAGE_STRING:
\r
948 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
951 case usbMANUFACTURER_STRING:
\r
952 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
955 case usbPRODUCT_STRING:
\r
956 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
959 case usbCONFIGURATION_STRING:
\r
960 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
963 case usbINTERFACE_STRING:
\r
964 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
968 /* Don't know what this string is. */
\r
976 /* We are not responding to anything else. */
\r
981 /*-----------------------------------------------------------*/
\r
983 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
985 unsigned short usStatus = 0;
\r
987 switch( pxRequest->ucRequest )
\r
989 case usbGET_STATUS_REQUEST:
\r
990 /* Just send two byte dummy status. */
\r
991 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
994 case usbGET_DESCRIPTOR_REQUEST:
\r
995 /* Send device descriptor */
\r
996 prvGetStandardDeviceDescriptor( pxRequest );
\r
999 case usbGET_CONFIGURATION_REQUEST:
\r
1000 /* Send selected device configuration */
\r
1001 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
1004 case usbSET_FEATURE_REQUEST:
\r
1005 prvUSBTransmitNull();
\r
1008 case usbSET_ADDRESS_REQUEST:
\r
1010 /* Acknowledge the SET_ADDRESS, but (according to the manual) we
\r
1011 cannot actually move to the addressed state until we get a TXCOMP
\r
1012 interrupt from this NULL packet. Therefore we just remember the
\r
1013 address and set our state so we know we have received the address. */
\r
1014 prvUSBTransmitNull();
\r
1015 eDriverState = eJUST_GOT_ADDRESS;
\r
1016 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
1019 case usbSET_CONFIGURATION_REQUEST:
\r
1021 /* Acknowledge the SET_CONFIGURATION, but (according to the manual)
\r
1022 we cannot actually move to the configured state until we get a
\r
1023 TXCOMP interrupt from this NULL packet. Therefore we just remember the
\r
1024 config and set our state so we know we have received the go ahead. */
\r
1025 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
1026 eDriverState = eJUST_GOT_CONFIG;
\r
1027 prvUSBTransmitNull();
\r
1032 /* We don't answer to anything else. */
\r
1037 /*-----------------------------------------------------------*/
\r
1039 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
1041 switch( pxRequest->ucRequest )
\r
1043 case usbSET_IDLE_REQUEST:
\r
1044 prvUSBTransmitNull();
\r
1047 /* This minimal implementation ignores these. */
\r
1048 case usbGET_REPORT_REQUEST:
\r
1049 case usbGET_IDLE_REQUEST:
\r
1050 case usbGET_PROTOCOL_REQUEST:
\r
1051 case usbSET_REPORT_REQUEST:
\r
1052 case usbSET_PROTOCOL_REQUEST:
\r
1059 /*-----------------------------------------------------------*/
\r
1061 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
1063 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
1065 case usbHID_REPORT_DESCRIPTOR:
\r
1066 prvSendControlData( ( unsigned char * ) pxReportDescriptor, pxRequest->usLength, sizeof( pxReportDescriptor ), pdTRUE );
\r
1071 /* Don't expect to send any others. */
\r
1076 /*-----------------------------------------------------------*/
\r
1078 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
1080 unsigned short usStatus = 0;
\r
1082 switch( pxRequest->ucRequest )
\r
1084 case usbGET_STATUS_REQUEST:
\r
1085 /* Send dummy 2 bytes. */
\r
1086 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
1089 case usbGET_DESCRIPTOR_REQUEST:
\r
1090 prvGetStandardInterfaceDescriptor( pxRequest );
\r
1093 /* This minimal implementation does not respond to these. */
\r
1094 case usbGET_INTERFACE_REQUEST:
\r
1095 case usbSET_FEATURE_REQUEST:
\r
1096 case usbSET_INTERFACE_REQUEST:
\r
1103 /*-----------------------------------------------------------*/
\r
1105 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
1107 switch( pxRequest->ucRequest )
\r
1109 /* This minimal implementation does not expect to respond to these. */
\r
1110 case usbGET_STATUS_REQUEST:
\r
1111 case usbCLEAR_FEATURE_REQUEST:
\r
1112 case usbSET_FEATURE_REQUEST:
\r
1119 /*-----------------------------------------------------------*/
\r
1121 static void vInitUSBInterface( void )
\r
1123 volatile unsigned long ulTemp;
\r
1125 /* Create the queue used to communicate between the USB ISR and task. */
\r
1126 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
1128 /* Initialise a few state variables. */
\r
1129 pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;
\r
1130 ucUSBConfig = ( unsigned char ) 0;
\r
1131 eDriverState = eNOTHING;
\r
1133 /* HARDWARE SETUP */
\r
1135 /* Set the PLL USB Divider */
\r
1136 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
1138 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
1139 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
1140 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
1142 /* Setup the PIO for the USB pull up resistor. */
\r
1143 AT91F_PIO_CfgOutput(AT91C_BASE_PIOA,AT91C_PIO_PA16);
\r
1145 /* Start without the pullup - this will get set at the end of this
\r
1147 AT91F_PIO_SetOutput( AT91C_BASE_PIOA, AT91C_PIO_PA16 );
\r
1149 /* When using the USB debugger the peripheral registers do not always get
\r
1150 set to the correct default values. To make sure set the relevant registers
\r
1152 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
1153 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
1154 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
1155 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
1156 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
1157 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
1159 /* Enable the transceiver. */
\r
1160 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
1162 /* Enable the USB interrupts - other interrupts get enabled as the
\r
1163 enumeration process progresses. */
\r
1164 AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ( void (*)( void ) ) vUSBISREntry );
\r
1165 AT91F_AIC_EnableIt( AT91C_BASE_AIC, AT91C_ID_UDP );
\r
1167 /* Wait a short while before making our presence known. */
\r
1168 vTaskDelay( usbINIT_DELAY );
\r
1169 AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA16 );
\r
1171 /*-----------------------------------------------------------*/
\r
1173 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
1175 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
1177 /* Cap the data length to that requested. */
\r
1178 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
1180 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
1182 /* We are sending a descriptor. If the descriptor is an exact
\r
1183 multiple of the FIFO length then it will have to be terminated
\r
1184 with a NULL packet. Set the state to indicate this if
\r
1186 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
1188 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
1192 /* Here we assume that the previous message has been sent. THERE IS NO
\r
1193 BUFFER OVERFLOW PROTECTION HERE.
\r
1195 Copy the data to send into the buffer as we cannot send it all at once
\r
1196 (if it is greater than 8 bytes in length). */
\r
1197 memcpy( pxCharsForTx.ucTxBuffer, pucData, ulLengthToSend );
\r
1199 /* Reinitialise the buffer index so we start sending from the start of
\r
1201 pxCharsForTx.ulTotalDataLength = ulLengthToSend;
\r
1202 pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;
\r
1204 /* Send the first 8 bytes now. The rest will get sent in response to
\r
1205 TXCOMP interrupts. */
\r
1206 prvSendNextSegment();
\r
1208 /*-----------------------------------------------------------*/
\r
1210 static void prvSendNextSegment( void )
\r
1212 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
1214 /* Is there any data to send? */
\r
1215 if( pxCharsForTx.ulTotalDataLength > pxCharsForTx.ulNextCharIndex )
\r
1217 ulLengthLeftToSend = pxCharsForTx.ulTotalDataLength - pxCharsForTx.ulNextCharIndex;
\r
1219 /* We can only send 8 bytes to the fifo at a time. */
\r
1220 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
1222 ulNextLength = usbFIFO_LENGTH;
\r
1226 ulNextLength = ulLengthLeftToSend;
\r
1229 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
1231 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
1233 vTaskDelay( usbSHORTEST_DELAY );
\r
1236 /* Write the data to the FIFO. */
\r
1237 while( ulNextLength > ( unsigned long ) 0 )
\r
1239 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxCharsForTx.ucTxBuffer[ pxCharsForTx.ulNextCharIndex ];
\r
1242 pxCharsForTx.ulNextCharIndex++;
\r
1245 /* Start the transmission. */
\r
1246 portENTER_CRITICAL();
\r
1248 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
1249 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
1250 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
1252 portEXIT_CRITICAL();
\r
1256 /* There is no data to send. If we were sending a descriptor and the
\r
1257 descriptor was an exact multiple of the max packet size then we need
\r
1258 to send a null to terminate the transmission. */
\r
1259 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
1261 prvUSBTransmitNull();
\r
1262 eDriverState = eNOTHING;
\r