]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_Demo_Rowley_ARM7/USB/USB-CDC.c
Update version number in preparation for official V8.2.0 release.
[freertos] / FreeRTOS / Demo / lwIP_Demo_Rowley_ARM7 / USB / USB-CDC.c
1 /*\r
2     FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
12 \r
13         ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18         ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40         the FAQ page "My application does not run, what could be wrong?".  Have you\r
41         defined configASSERT()?\r
42 \r
43         http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44         embedded software for free we request you assist our global community by\r
45         participating in the support forum.\r
46 \r
47         http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48         be as productive as possible as early as possible.  Now you can receive\r
49         FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50         Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /*\r
71         USB Communications Device Class driver.\r
72         Implements task vUSBCDCTask and provides an Abstract Control Model serial \r
73         interface.  Control is through endpoint 0, device-to-host notification is \r
74         provided by interrupt-in endpoint 3, and raw data is transferred through \r
75         bulk endpoints 1 and 2.\r
76 \r
77         - developed from original FreeRTOS HID example by Scott Miller\r
78         - modified to support 3.2 GCC by najay\r
79 */\r
80 \r
81 /* Standard includes. */\r
82 #include <string.h>\r
83 #include <stdio.h>\r
84 \r
85 /* Demo board includes. */\r
86 #include "Board.h"\r
87 \r
88 /* Scheduler includes. */\r
89 #include "FreeRTOS.h"\r
90 #include "task.h"\r
91 #include "queue.h"\r
92 \r
93 /* Demo app includes. */\r
94 #include "USB-CDC.h"\r
95 #include "descriptors.h"\r
96 \r
97 #define usbNO_BLOCK ( ( TickType_t ) 0 )\r
98 \r
99 /* Reset all endpoints */\r
100 static void prvResetEndPoints( void );\r
101 \r
102 /* Clear pull up resistor to detach device from host */\r
103 static void vDetachUSBInterface( void );\r
104 \r
105 /* Set up interface and initialize variables */\r
106 static void vInitUSBInterface( void );\r
107 \r
108 /* Handle control endpoint events. */\r
109 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );\r
110 \r
111 /* Handle standard device requests. */\r
112 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );\r
113 \r
114 /* Handle standard interface requests. */\r
115 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );\r
116 \r
117 /* Handle endpoint requests. */\r
118 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );\r
119 \r
120 /* Handle class interface requests. */\r
121 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );\r
122 \r
123 /* Prepare control data transfer.  prvSendNextSegment starts transfer. */\r
124 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );\r
125 \r
126 /* Send next segment of data for the control transfer */\r
127 static void prvSendNextSegment( void );\r
128 \r
129 /* Send stall - used to respond to unsupported requests */\r
130 static void prvSendStall( void );\r
131 \r
132 /* Send a zero-length (null) packet */\r
133 static void prvSendZLP( void );\r
134 \r
135 /* Handle requests for standard interface descriptors */\r
136 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );\r
137 \r
138 /*------------------------------------------------------------*/\r
139 \r
140 /* File scope static variables */\r
141 static unsigned char ucUSBConfig = ( unsigned char ) 0;\r
142 static unsigned long ulReceivedAddress = ( unsigned long ) 0;\r
143 static eDRIVER_STATE eDriverState = eNOTHING;\r
144 \r
145 /* Incoming and outgoing control data structures */\r
146 static xCONTROL_MESSAGE pxControlTx;\r
147 static xCONTROL_MESSAGE pxControlRx;\r
148 \r
149 /* Queue holding pointers to pending messages */\r
150 QueueHandle_t xUSBInterruptQueue; \r
151 \r
152 /* Queues used to hold received characters, and characters waiting to be\r
153 transmitted.  Rx queue must be larger than FIFO size. */\r
154 static QueueHandle_t xRxCDC; \r
155 static QueueHandle_t xTxCDC; \r
156 \r
157 /* Line coding - 115,200 baud, N-8-1 */\r
158 static const unsigned char pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 };\r
159 \r
160 /* Status variables. */\r
161 static unsigned char ucControlState;\r
162 static unsigned int uiCurrentBank;\r
163 \r
164 \r
165 /*------------------------------------------------------------*/\r
166 \r
167 \r
168 void vUSBCDCTask( void *pvParameters )\r
169 {\r
170 xISRStatus *pxMessage;\r
171 unsigned long ulStatus;\r
172 unsigned long ulRxBytes;\r
173 unsigned char ucByte;\r
174 portBASE_TYPE xByte;\r
175 \r
176         ( void ) pvParameters;\r
177 \r
178         /* Disconnect USB device from hub.  For debugging - causes host to register reset */\r
179         portENTER_CRITICAL();\r
180                  vDetachUSBInterface();\r
181         portEXIT_CRITICAL();\r
182         \r
183         vTaskDelay( portTICK_PERIOD_MS * 60 );\r
184 \r
185         /* Init USB interface */\r
186         portENTER_CRITICAL();\r
187                 vInitUSBInterface();\r
188         portEXIT_CRITICAL();\r
189         \r
190         /* Main task loop.  Process incoming endpoint 0 interrupts, handle data transfers. */\r
191          \r
192         for( ;; )\r
193         {\r
194                 /* Look for data coming from the ISR. */\r
195                 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) )\r
196                 {\r
197                         if( pxMessage->ulISR & AT91C_UDP_EPINT0 )\r
198                         {\r
199                                 /* All endpoint 0 interrupts are handled here. */\r
200                                 prvProcessEndPoint0Interrupt( pxMessage );\r
201                         }\r
202 \r
203                         if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )\r
204                         {\r
205                                 /* End of bus reset - reset the endpoints and de-configure. */\r
206                                 prvResetEndPoints();            \r
207                         }\r
208                 }\r
209                 \r
210                 /* See if we're ready to send and receive data. */\r
211                 if( eDriverState == eREADY_TO_SEND && ucControlState ) \r
212                 {\r
213                         if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) )\r
214                         {\r
215                                 for( xByte = 0; xByte < 64; xByte++ )\r
216                                 {                                  \r
217                                         if( !xQueueReceive( xTxCDC, &ucByte, 0 ) ) \r
218                                         {\r
219                                                 /* No data buffered to transmit. */\r
220                                                 break;\r
221                                         }\r
222 \r
223                                         /* Got a byte to transmit. */\r
224                                         AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = ucByte;\r
225                                 } \r
226                                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY;\r
227                         }\r
228 \r
229                         /* Check for incoming data (host-to-device) on endpoint 1. */\r
230                         while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) )\r
231                         {\r
232                                 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK;\r
233 \r
234                                 /* Only process FIFO if there's room to store it in the queue */\r
235                                 if( ulRxBytes < ( USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting( xRxCDC ) ) )\r
236                                 {\r
237                                         while( ulRxBytes-- )\r
238                                         {\r
239                                                 ucByte = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ];\r
240                                                 xQueueSend( xRxCDC, &ucByte, 0 );\r
241                                         }\r
242 \r
243                                         /* Release the FIFO */\r
244                                         portENTER_CRITICAL();\r
245                                         {\r
246                                                 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];\r
247                                                 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank );\r
248                                                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;\r
249                                         }\r
250                                         portEXIT_CRITICAL();\r
251 \r
252                                         /* Re-enable endpoint 1's interrupts */\r
253                                         AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;\r
254                                 \r
255                                         /* Update the current bank in use */\r
256                                         if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 ) \r
257                                         {\r
258                                                 uiCurrentBank = AT91C_UDP_RX_DATA_BK1;\r
259                                         }\r
260                                         else \r
261                                         {\r
262                                                 uiCurrentBank = AT91C_UDP_RX_DATA_BK0;\r
263                                         }\r
264 \r
265                                 }\r
266                                 else \r
267                                 {\r
268                                         break;\r
269                                 }\r
270                         }\r
271                 }\r
272         }\r
273 }\r
274 /*------------------------------------------------------------*/\r
275 \r
276 void vUSBSendByte( char cByte )\r
277 {\r
278         /* Queue the byte to be sent.  The USB task will send it. */\r
279         xQueueSend( xTxCDC, &cByte, usbNO_BLOCK );\r
280 }\r
281 /*------------------------------------------------------------*/\r
282 \r
283 static void prvSendZLP( void )\r
284 {\r
285 unsigned long ulStatus;\r
286 \r
287         /* Wait until the FIFO is free - even though we are not going to use it.\r
288         THERE IS NO TIMEOUT HERE! */\r
289         while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )\r
290         {\r
291                 vTaskDelay( usbSHORTEST_DELAY );\r
292         }\r
293 \r
294         portENTER_CRITICAL();\r
295         {\r
296                 /* Cancel any further pending data */\r
297                 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex;\r
298 \r
299                 /* Set the TXPKTRDY bit to cause a transmission with no data. */\r
300                 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
301                 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY );\r
302                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;\r
303         }\r
304         portEXIT_CRITICAL();\r
305 }\r
306 /*------------------------------------------------------------*/\r
307 \r
308 static void prvSendStall( void )\r
309 {\r
310         unsigned long ulStatus;\r
311 \r
312         portENTER_CRITICAL();\r
313         {\r
314                 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */\r
315                 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
316                 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );\r
317                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;\r
318         }\r
319         portEXIT_CRITICAL();\r
320 }\r
321 /*------------------------------------------------------------*/\r
322 \r
323 static void prvResetEndPoints( void )\r
324 {\r
325 unsigned long ulTemp;\r
326 \r
327         eDriverState = eJUST_RESET;\r
328         ucControlState = 0;\r
329 \r
330         /* Reset all the end points. */\r
331         AT91C_BASE_UDP->UDP_RSTEP  = usbEND_POINT_RESET_MASK;\r
332         AT91C_BASE_UDP->UDP_RSTEP  = ( unsigned long ) 0x00;\r
333 \r
334         /* Enable data to be sent and received. */\r
335         AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;\r
336 \r
337         /* Repair the configuration end point. */\r
338         portENTER_CRITICAL();\r
339         {\r
340                 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
341                 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );\r
342                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;\r
343                 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;\r
344         }\r
345         portEXIT_CRITICAL();\r
346         uiCurrentBank = AT91C_UDP_RX_DATA_BK0;\r
347 }\r
348 /*------------------------------------------------------------*/\r
349 \r
350 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )\r
351 {\r
352 static xUSB_REQUEST xRequest;\r
353 unsigned long ulRxBytes;\r
354 \r
355         /* Get number of bytes received, if any */\r
356         ulRxBytes = pxMessage->ulCSR0 >> 16;\r
357         ulRxBytes &= usbRX_COUNT_MASK;\r
358 \r
359         if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )\r
360         {\r
361                 /* We received a TX complete interrupt.  What we do depends on\r
362                 what we sent to get this interrupt. */\r
363 \r
364                 if( eDriverState == eJUST_GOT_CONFIG )\r
365                 {\r
366                         /* We sent an acknowledgement of a SET_CONFIG request.  We\r
367                         are now at the end of the enumeration.\r
368                         \r
369                         TODO: Config 0 sets unconfigured state, should enter Address state.\r
370                         Request for unsupported config should stall. */\r
371                         AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;\r
372                         \r
373                         /* Set up endpoints */\r
374                         portENTER_CRITICAL();\r
375                         {\r
376                                 unsigned long ulTemp;\r
377 \r
378                                 /* Set endpoint 1 to bulk-out */\r
379                                 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];                                     \r
380                                 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT );\r
381                                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;             \r
382                                 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;\r
383                                 /* Set endpoint 2 to bulk-in */\r
384                                 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ];                                     \r
385                                 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN );\r
386                                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp;             \r
387                                 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2;\r
388                                         /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */\r
389                                 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ];                                     \r
390                                 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );\r
391                                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp;             \r
392                                 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 );                                */\r
393                         }\r
394                         portEXIT_CRITICAL();\r
395 \r
396                         eDriverState = eREADY_TO_SEND;\r
397                 }               \r
398                 else if( eDriverState == eJUST_GOT_ADDRESS )\r
399                 {\r
400                         /* We sent an acknowledgement of a SET_ADDRESS request.  Move\r
401                         to the addressed state. */\r
402                         if( ulReceivedAddress != ( unsigned long ) 0 )\r
403                         {                       \r
404                                 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;\r
405                         }\r
406                         else\r
407                         {\r
408                                 AT91C_BASE_UDP->UDP_GLBSTATE = 0;\r
409                         }                       \r
410 \r
411                         AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );              \r
412                         eDriverState = eNOTHING;\r
413                 }\r
414                 else\r
415                 {               \r
416                         /* The TXCOMP was not for any special type of transmission.  See\r
417                         if there is any more data to send. */\r
418                         prvSendNextSegment();\r
419                 }\r
420         }\r
421 \r
422         if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )\r
423         {\r
424                 /* Received a control data packet.  May be a 0-length ACK or a data stage. */\r
425                 unsigned char ucBytesToGet;\r
426          \r
427                 /* Got data.  Cancel any outgoing data. */\r
428                 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength;\r
429                 \r
430                  /* Determine how many bytes we need to receive. */\r
431                 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex;\r
432                 if( ucBytesToGet > ulRxBytes ) \r
433                 {       \r
434                         ucBytesToGet = ulRxBytes;\r
435                 }\r
436 \r
437                 /* If we're not expecting any data, it's an ack - just quit now. */\r
438                 if( !ucBytesToGet )\r
439                 {\r
440                          return;\r
441                 }\r
442 \r
443                 /* Get the required data and update the index. */\r
444                 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet );\r
445                 pxControlRx.ulNextCharIndex += ucBytesToGet;    \r
446         }\r
447 \r
448         if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )\r
449         {\r
450                 /* Received a SETUP packet.  May be followed by data packets. */\r
451 \r
452                 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )\r
453                 {                               \r
454                         /* Create an xUSB_REQUEST variable from the raw bytes array. */\r
455 \r
456                         xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];\r
457                         xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];\r
458 \r
459                         xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];\r
460                         xRequest.usValue <<= 8;\r
461                         xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];\r
462                                                 \r
463                         xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];\r
464                         xRequest.usIndex <<= 8;\r
465                         xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];\r
466                         \r
467                         xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];\r
468                         xRequest.usLength <<= 8;\r
469                         xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];\r
470 \r
471                         pxControlRx.ulNextCharIndex = 0;\r
472                         if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */\r
473                         {\r
474                                 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE )\r
475                                 {       \r
476                                         /* Too big!  No space for control data, stall and abort. */\r
477                                         prvSendStall();\r
478                                         return;\r
479                                 }\r
480 \r
481                                 pxControlRx.ulTotalDataLength = xRequest.usLength;\r
482                         }\r
483                         else\r
484                         {\r
485                                 /* We're sending the data, don't wait for any. */\r
486                                 pxControlRx.ulTotalDataLength = 0; \r
487                         }\r
488                 }\r
489         }\r
490 \r
491         /* See if we've got a pending request and all its associated data ready */\r
492         if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) ) \r
493                 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) )\r
494         {\r
495                 unsigned char ucRequest;\r
496 \r
497                 /* Manipulate the ucRequestType and the ucRequest parameters to \r
498                 generate a zero based request selection.  This is just done to \r
499                 break up the requests into subsections for clarity.  The \r
500                 alternative would be to have more huge switch statement that would\r
501                 be difficult to optimise. */\r
502                 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );\r
503                 ucRequest |= ( xRequest.ucReqType & 0x03 );\r
504                         \r
505                 switch( ucRequest )\r
506                 {\r
507                         case usbSTANDARD_DEVICE_REQUEST:        \r
508                                 /* Standard Device request */\r
509                                 prvHandleStandardDeviceRequest( &xRequest );\r
510                                 break;\r
511 \r
512                         case usbSTANDARD_INTERFACE_REQUEST:     \r
513                                 /* Standard Interface request */\r
514                                 prvHandleStandardInterfaceRequest( &xRequest );\r
515                                 break;\r
516 \r
517                         case usbSTANDARD_END_POINT_REQUEST:     \r
518                                 /* Standard Endpoint request */\r
519                                 prvHandleStandardEndPointRequest( &xRequest );\r
520                                 break;\r
521 \r
522                         case usbCLASS_INTERFACE_REQUEST:        \r
523                                 /* Class Interface request */\r
524                                 prvHandleClassInterfaceRequest( &xRequest );\r
525                                 break;\r
526 \r
527                         default:        /* This is not something we want to respond to. */\r
528                                 prvSendStall(); \r
529                 }\r
530         }\r
531 }\r
532 /*------------------------------------------------------------*/\r
533 \r
534 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )\r
535 {\r
536         /* The type is in the high byte.  Return whatever has been requested. */\r
537         switch( ( pxRequest->usValue & 0xff00 ) >> 8 )\r
538         {\r
539                 case usbDESCRIPTOR_TYPE_DEVICE:\r
540                         prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );\r
541                         break;\r
542 \r
543                 case usbDESCRIPTOR_TYPE_CONFIGURATION:\r
544                         prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );\r
545                         break;\r
546 \r
547                 case usbDESCRIPTOR_TYPE_STRING:\r
548 \r
549                         /* The index to the string descriptor is the lower byte. */\r
550                         switch( pxRequest->usValue & 0xff )\r
551                         {                       \r
552                                 case usbLANGUAGE_STRING:\r
553                                         prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );\r
554                                         break;\r
555 \r
556                                 case usbMANUFACTURER_STRING:\r
557                                         prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );\r
558                                         break;\r
559 \r
560                                 case usbPRODUCT_STRING:\r
561                                         prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );\r
562                                         break;\r
563 \r
564                                 case usbCONFIGURATION_STRING:\r
565                                         prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );\r
566                                         break;\r
567 \r
568                                 case usbINTERFACE_STRING:\r
569                                         prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );\r
570                                         break;\r
571 \r
572                                 default:\r
573                                         prvSendStall();\r
574                                         break;\r
575                         }\r
576                         break;\r
577 \r
578                 default:\r
579                         prvSendStall();\r
580                         break;\r
581         }\r
582 }\r
583 /*------------------------------------------------------------*/\r
584 \r
585 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )\r
586 {\r
587 unsigned short usStatus = 0;\r
588 \r
589         switch( pxRequest->ucRequest )\r
590         {\r
591                 case usbGET_STATUS_REQUEST:\r
592                         /* Just send two byte dummy status. */\r
593                         prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );\r
594                         break;\r
595 \r
596                 case usbGET_DESCRIPTOR_REQUEST:\r
597                         /* Send device descriptor */\r
598                         prvGetStandardDeviceDescriptor( pxRequest );\r
599                         break;\r
600 \r
601                 case usbGET_CONFIGURATION_REQUEST:\r
602                         /* Send selected device configuration */\r
603                         prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );\r
604                         break;\r
605 \r
606                 case usbSET_FEATURE_REQUEST:\r
607                         prvSendZLP();\r
608                         break;\r
609 \r
610                 case usbSET_ADDRESS_REQUEST:                    \r
611                         /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */\r
612                         prvSendZLP();                   \r
613                         eDriverState = eJUST_GOT_ADDRESS;                       \r
614                         ulReceivedAddress = ( unsigned long ) pxRequest->usValue;\r
615                         break;\r
616 \r
617                 case usbSET_CONFIGURATION_REQUEST:\r
618                         /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */\r
619                         ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );\r
620                         eDriverState = eJUST_GOT_CONFIG;\r
621                         prvSendZLP();\r
622                         break;\r
623 \r
624                 default:\r
625                         /* Any unsupported request results in a STALL response. */\r
626                         prvSendStall();\r
627                         break;\r
628         }\r
629 }\r
630 /*------------------------------------------------------------*/\r
631 \r
632 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )\r
633 {\r
634         switch( pxRequest->ucRequest )\r
635         {\r
636                 case usbSEND_ENCAPSULATED_COMMAND:\r
637                         prvSendStall();\r
638                         break;\r
639 \r
640                 case usbGET_ENCAPSULATED_RESPONSE:\r
641                         prvSendStall();\r
642                         break;\r
643 \r
644                 case usbSET_LINE_CODING:\r
645                         /* Set line coding - baud rate, data bits, parity, stop bits */\r
646                         prvSendZLP();\r
647                         memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) );\r
648                         break;\r
649 \r
650                 case usbGET_LINE_CODING:\r
651                         /* Get line coding */\r
652                         prvSendControlData( (unsigned char *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE );\r
653                         break;\r
654 \r
655                 case usbSET_CONTROL_LINE_STATE:\r
656                         /* D0: 1=DTR, 0=No DTR,  D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */\r
657                         prvSendZLP();\r
658                         ucControlState = pxRequest->usValue;\r
659                         break;\r
660 \r
661                 default:\r
662                         prvSendStall();\r
663                         break;\r
664         }\r
665 }\r
666 /*------------------------------------------------------------*/\r
667 \r
668 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )\r
669 {\r
670         switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )\r
671         {\r
672                 default:\r
673                         prvSendStall();\r
674                         break;\r
675         }\r
676 }\r
677 /*-----------------------------------------------------------*/\r
678 \r
679 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )\r
680 {\r
681 unsigned short usStatus = 0;\r
682 \r
683         switch( pxRequest->ucRequest )\r
684         {\r
685                 case usbGET_STATUS_REQUEST:\r
686                         /* Send dummy 2 bytes. */\r
687                         prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );\r
688                         break;\r
689 \r
690                 case usbGET_DESCRIPTOR_REQUEST:\r
691                         prvGetStandardInterfaceDescriptor( pxRequest ); \r
692                         break;\r
693 \r
694                 /* This minimal implementation does not respond to these. */\r
695                 case usbGET_INTERFACE_REQUEST:\r
696                 case usbSET_FEATURE_REQUEST:\r
697                 case usbSET_INTERFACE_REQUEST:  \r
698 \r
699                 default:\r
700                         prvSendStall();\r
701                         break;\r
702         }\r
703 }\r
704 /*-----------------------------------------------------------*/\r
705 \r
706 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )\r
707 {\r
708         switch( pxRequest->ucRequest )\r
709         {\r
710                 /* This minimal implementation does not expect to respond to these. */\r
711                 case usbGET_STATUS_REQUEST:\r
712                 case usbCLEAR_FEATURE_REQUEST: \r
713                 case usbSET_FEATURE_REQUEST:\r
714 \r
715                 default:                        \r
716                         prvSendStall();\r
717                         break;\r
718         }\r
719 }\r
720 /*-----------------------------------------------------------*/\r
721 \r
722 static void vDetachUSBInterface( void)\r
723 {\r
724         /* Setup the PIO for the USB pull up resistor. */\r
725         AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;\r
726         AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;\r
727 \r
728 \r
729         /* Disable pull up */\r
730         AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;\r
731\r
732 /*-----------------------------------------------------------*/\r
733 \r
734 static void vInitUSBInterface( void )\r
735 {\r
736 extern void ( vUSB_ISR_Wrapper )( void );\r
737 \r
738         /* Create the queue used to communicate between the USB ISR and task. */\r
739         xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );\r
740         \r
741         /* Create the queues used to hold Rx and Tx characters. */\r
742         xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned char ) sizeof( signed char ) );\r
743         xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned char ) sizeof( signed char ) );\r
744 \r
745         if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) )\r
746         {       \r
747                 /* Not enough RAM to create queues!. */\r
748                 return;\r
749         }\r
750         \r
751         /* Initialise a few state variables. */\r
752         pxControlTx.ulNextCharIndex = ( unsigned long ) 0;\r
753         pxControlRx.ulNextCharIndex = ( unsigned long ) 0;\r
754         ucUSBConfig = ( unsigned char ) 0;\r
755         eDriverState = eNOTHING;\r
756         ucControlState = 0;\r
757         uiCurrentBank = AT91C_UDP_RX_DATA_BK0;\r
758 \r
759 \r
760         /* HARDWARE SETUP */\r
761 \r
762         /* Set the PLL USB Divider */\r
763         AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;\r
764 \r
765         /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */\r
766         AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
767         AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
768 \r
769         /* Setup the PIO for the USB pull up resistor. */\r
770         AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;\r
771         AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;\r
772 \r
773 \r
774         /* Start without the pullup - this will get set at the end of this \r
775         function. */\r
776         AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;\r
777 \r
778 \r
779         /* When using the USB debugger the peripheral registers do not always get\r
780         set to the correct default values.  To make sure set the relevant registers\r
781         manually here. */\r
782         AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;\r
783         AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;\r
784         AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;\r
785         AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;\r
786         AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned long ) 0x00;\r
787         AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned long ) 0x00;\r
788         AT91C_BASE_UDP->UDP_GLBSTATE = 0;\r
789         AT91C_BASE_UDP->UDP_FADDR = 0;\r
790 \r
791         /* Enable the transceiver. */\r
792         AT91C_UDP_TRANSCEIVER_ENABLE = 0;\r
793 \r
794         /* Enable the USB interrupts - other interrupts get enabled as the \r
795         enumeration process progresses. */\r
796         AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );\r
797         AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;\r
798 \r
799 \r
800         /* Wait a short while before making our presence known. */\r
801         vTaskDelay( usbINIT_DELAY );\r
802         AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;\r
803 }\r
804 /*-----------------------------------------------------------*/\r
805 \r
806 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )\r
807 {\r
808         if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )\r
809         {\r
810                 /* Cap the data length to that requested. */\r
811                 ulLengthToSend = ( unsigned short ) usRequestedLength;\r
812         }\r
813         else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )\r
814         {\r
815                 /* We are sending a descriptor.  If the descriptor is an exact \r
816                 multiple of the FIFO length then it will have to be terminated\r
817                 with a NULL packet.  Set the state to indicate this if\r
818                 necessary. */\r
819                 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )\r
820                 {\r
821                         eDriverState = eSENDING_EVEN_DESCRIPTOR;\r
822                 }\r
823         }\r
824 \r
825         /* Here we assume that the previous message has been sent.  THERE IS NO\r
826         BUFFER OVERFLOW PROTECTION HERE.\r
827 \r
828         Copy the data to send into the buffer as we cannot send it all at once\r
829         (if it is greater than 8 bytes in length). */\r
830         memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend );\r
831 \r
832         /* Reinitialise the buffer index so we start sending from the start of \r
833         the data. */\r
834         pxControlTx.ulTotalDataLength = ulLengthToSend;\r
835         pxControlTx.ulNextCharIndex = ( unsigned long ) 0;\r
836 \r
837         /* Send the first 8 bytes now.  The rest will get sent in response to \r
838         TXCOMP interrupts. */\r
839         prvSendNextSegment();\r
840 }\r
841 /*-----------------------------------------------------------*/\r
842 \r
843 static void prvSendNextSegment( void )\r
844 {\r
845 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;\r
846 \r
847         /* Is there any data to send? */\r
848         if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex )\r
849         {\r
850                 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex;\r
851         \r
852                 /* We can only send 8 bytes to the fifo at a time. */\r
853                 if( ulLengthLeftToSend > usbFIFO_LENGTH )\r
854                 {\r
855                         ulNextLength = usbFIFO_LENGTH;\r
856                 }\r
857                 else\r
858                 {\r
859                         ulNextLength = ulLengthLeftToSend;\r
860                 }\r
861 \r
862                 /* Wait until we can place data in the fifo.  THERE IS NO TIMEOUT\r
863                 HERE! */\r
864                 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )\r
865                 {\r
866                         vTaskDelay( usbSHORTEST_DELAY );\r
867                 }\r
868 \r
869                 /* Write the data to the FIFO. */\r
870                 while( ulNextLength > ( unsigned long ) 0 )\r
871                 {\r
872                         AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ];\r
873         \r
874                         ulNextLength--;\r
875                         pxControlTx.ulNextCharIndex++;\r
876                 }\r
877         \r
878                 /* Start the transmission. */\r
879                 portENTER_CRITICAL();\r
880                 {\r
881                         ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
882                         usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );\r
883                         AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;\r
884                 }\r
885                 portEXIT_CRITICAL();\r
886         }\r
887         else\r
888         {\r
889                 /* There is no data to send.  If we were sending a descriptor and the \r
890                 descriptor was an exact multiple of the max packet size then we need\r
891                 to send a null to terminate the transmission. */\r
892                 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )\r
893                 {\r
894                         prvSendZLP();\r
895                         eDriverState = eNOTHING;\r
896                 }\r
897         }\r
898 }\r
899 \r
900 \r