]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/ARM7_AT91SAM7X256_Eclipse/RTOSDemo/USB/USBSample.c
Update version numbers in preparation for new release.
[freertos] / FreeRTOS / Demo / ARM7_AT91SAM7X256_Eclipse / RTOSDemo / USB / USBSample.c
1 /*\r
2     FreeRTOS V8.2.2 - 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         Sample interrupt driven mouse device driver.  This is a minimal implementation \r
72         for demonstration only.  Although functional, it may not be a fully and \r
73         compliant implementation.  The small joystick on the SAM7X EK can be used to\r
74         move the mouse cursor, pressing the joystick transmits mouse clicks.  Note\r
75         that it might be necessary to run the demo stand along (without the \r
76         debugger) in order for the USB device to be recognised by the host computer.\r
77 \r
78         The interrupt handler itself is contained within USB_ISR.c.\r
79         \r
80         See the FreeRTOS.org online documentation for more information.\r
81 */\r
82 \r
83 /* Standard includes. */\r
84 #include <string.h>\r
85 \r
86 /* Scheduler includes. */\r
87 #include "FreeRTOS.h"\r
88 #include "task.h"\r
89 #include "queue.h"\r
90 \r
91 /* Demo application includes. */\r
92 #include "USBSample.h"\r
93 \r
94 /* Joystick inputs used to move the 'mouse' cursor. */\r
95 #define usbSW1  ( 1 << 21 )     /* PA21 */\r
96 #define usbSW2  ( 1 << 22 )     /* PA22 */\r
97 #define usbSW3  ( 1 << 23 )     /* PA23 */\r
98 #define usbSW4  ( 1 << 24 )     /* PA24 */\r
99 #define usbSW_CLICK     ( 1 << 25 ) /* PA25 */\r
100 \r
101 /* Descriptor type definitions. */\r
102 #define usbDESCRIPTOR_TYPE_DEVICE                       ( 0x01 )\r
103 #define usbDESCRIPTOR_TYPE_CONFIGURATION        ( 0x02 )\r
104 #define usbDESCRIPTOR_TYPE_STRING                       ( 0x03 )\r
105 \r
106 /* USB request type definitions. */\r
107 #define usbGET_REPORT_REQUEST                           ( 0x01 )\r
108 #define usbGET_IDLE_REQUEST                                     ( 0x02 )\r
109 #define usbGET_PROTOCOL_REQUEST                         ( 0x03 )\r
110 #define usbSET_REPORT_REQUEST                           ( 0x09 )\r
111 #define usbSET_IDLE_REQUEST                                     ( 0x0A )\r
112 #define usbSET_PROTOCOL_REQUEST                         ( 0x0B )\r
113 #define usbGET_CONFIGURATION_REQUEST            ( 0x08 )\r
114 #define usbGET_STATUS_REQUEST                           ( 0x00 )\r
115 #define usbCLEAR_FEATURE_REQUEST                        ( 0x01 )\r
116 #define usbSET_FEATURE_REQUEST                          ( 0x03 )\r
117 #define usbSET_ADDRESS_REQUEST                          ( 0x05 )\r
118 #define usbGET_DESCRIPTOR_REQUEST                       ( 0x06 )\r
119 #define usbSET_CONFIGURATION_REQUEST            ( 0x09 )\r
120 #define usbGET_INTERFACE_REQUEST                        ( 0x0A )\r
121 #define usbSET_INTERFACE_REQUEST                        ( 0x0B )\r
122 \r
123 \r
124 /* Misc USB definitions. */\r
125 #define usbDEVICE_CLASS_VENDOR_SPECIFIC         ( 0xFF )\r
126 #define usbBUS_POWERED                                          ( 0x80 )\r
127 #define usbHID_REPORT_DESCRIPTOR                        ( 0x22 )\r
128 #define AT91C_UDP_TRANSCEIVER_ENABLE                    ( *( ( unsigned long * ) 0xfffb0074 ) )\r
129 \r
130 /* Index to the various string. */\r
131 #define usbLANGUAGE_STRING                                      ( 0 )\r
132 #define usbMANUFACTURER_STRING                          ( 1 )\r
133 #define usbPRODUCT_STRING                                       ( 2 )\r
134 #define usbCONFIGURATION_STRING                         ( 3 )\r
135 #define usbINTERFACE_STRING                                     ( 4 )\r
136 \r
137 /* Data indexes for reading the request from the xISRStatus.ucFifoData[]\r
138 into xUSB_REQUEST.  The data order is designed for speed - so looks a \r
139 little odd. */\r
140 #define usbREQUEST_TYPE_INDEX                           ( 7 )\r
141 #define usbREQUEST_INDEX                                        ( 6 )\r
142 #define usbVALUE_HIGH_BYTE                                      ( 4 )\r
143 #define usbVALUE_LOW_BYTE                                       ( 5 )\r
144 #define usbINDEX_HIGH_BYTE                                      ( 2 )\r
145 #define usbINDEX_LOW_BYTE                                       ( 3 )\r
146 #define usbLENGTH_HIGH_BYTE                                     ( 0 )\r
147 #define usbLENGTH_LOW_BYTE                                      ( 1 )\r
148 \r
149 /* Misc application definitions. */\r
150 #define usbINTERRUPT_PRIORITY                           ( 3 )\r
151 #define usbFIFO_LENGTH                                          ( ( unsigned long ) 8 )\r
152 #define usbXUP                                                          ( 1 )\r
153 #define usbXDOWN                                                        ( 2 )\r
154 #define usbYUP                                                          ( 3 )\r
155 #define usbYDOWN                                                        ( 4 )\r
156 #define usbMAX_COORD                                            ( 120 )\r
157 #define usbMAX_TX_MESSAGE_SIZE                          ( 128 )\r
158 #define usbSHORTEST_DELAY                                       ( ( TickType_t ) 1 )\r
159 #define usbINIT_DELAY                                           ( ( TickType_t ) 1000 / portTICK_PERIOD_MS )\r
160 #define usbSHORT_DELAY                                          ( ( TickType_t ) 50 / portTICK_PERIOD_MS )\r
161 #define usbEND_POINT_RESET_MASK                         ( ( unsigned long ) 0x0f )\r
162 #define usbDATA_INC                                                     ( ( char ) 5 )\r
163 #define usbEXPECTED_NUMBER_OF_BYTES                     ( ( unsigned long ) 8 )\r
164 \r
165 /* Control request types. */\r
166 #define usbSTANDARD_DEVICE_REQUEST                      ( 0 )\r
167 #define usbSTANDARD_INTERFACE_REQUEST           ( 1 )\r
168 #define usbSTANDARD_END_POINT_REQUEST           ( 2 )\r
169 #define usbCLASS_INTERFACE_REQUEST                      ( 5 )\r
170 \r
171 /* Structure used to hold the received requests. */\r
172 typedef struct \r
173 {\r
174         unsigned char ucReqType;\r
175         unsigned char ucRequest;\r
176         unsigned short usValue;\r
177         unsigned short usIndex;\r
178         unsigned short usLength;\r
179 } xUSB_REQUEST;\r
180 \r
181 typedef enum\r
182 {\r
183         eNOTHING,\r
184         eJUST_RESET,\r
185         eJUST_GOT_CONFIG,\r
186         eJUST_GOT_ADDRESS,\r
187         eSENDING_EVEN_DESCRIPTOR,\r
188         eREADY_TO_SEND\r
189 } eDRIVER_STATE;\r
190 \r
191 /* Structure used to control the data being sent to the host. */\r
192 typedef struct\r
193 {\r
194         unsigned char ucTxBuffer[ usbMAX_TX_MESSAGE_SIZE ];\r
195         unsigned long ulNextCharIndex;\r
196         unsigned long ulTotalDataLength;\r
197 } xTX_MESSAGE;\r
198 \r
199 /*-----------------------------------------------------------*/\r
200 \r
201 /* \r
202  * The USB interrupt service routine.  This takes a snapshot of the USB\r
203  * device at the time of the interrupt, clears the interrupts, and posts\r
204  * the data to the USB processing task.  This is implemented in USB_ISR.c.\r
205  */\r
206 extern void vUSB_ISR_Wrapper( void );\r
207 \r
208 /*\r
209  * Called after the bus reset interrupt - this function readies all the\r
210  * end points for communication.\r
211  */\r
212 static void prvResetEndPoints( void );\r
213 \r
214 /*\r
215  * Setup the USB hardware, install the interrupt service routine and \r
216  * initialise all the state variables.\r
217  */\r
218 static void vInitUSBInterface( void );\r
219 \r
220 /*\r
221  * Decode and act upon an interrupt generated by the control end point.\r
222  */\r
223 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );\r
224 \r
225 /* \r
226  * For simplicity requests are separated into device, interface, class \r
227  * interface and end point requests.\r
228  *\r
229  * Decode and handle standard device requests originating on the control\r
230  * end point. \r
231  */\r
232 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );\r
233 \r
234 /*\r
235  * For simplicity requests are separated into device, interface, class \r
236  * interface and end point requests.\r
237  *\r
238  * Decode and handle standard interface requests originating on the control\r
239  * end point.\r
240  */\r
241 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );\r
242 \r
243 /*\r
244  * For simplicity requests are separated into device, interface, class \r
245  * interface and end point requests.\r
246  *\r
247  * Decode and handle standard end point requests originating on the control\r
248  * end point.\r
249  */\r
250 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );\r
251 \r
252 /*\r
253  * For simplicity requests are separated into device, interface, class \r
254  * interface and end point requests.\r
255  *\r
256  * Decode and handle the class interface requests.\r
257  */\r
258 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );\r
259 \r
260 /*\r
261  * Setup the Tx buffer to send data in response to a control request.\r
262  *\r
263  * The data to be transmitted is buffered, the state variables are updated,\r
264  * then prvSendNextSegment() is called to start the transmission off.  Once\r
265  * the first segment has been sent the remaining segments are transmitted\r
266  * in response to TXCOMP interrupts until the entire buffer has been\r
267  * sent.\r
268  */\r
269 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );\r
270 \r
271 /*\r
272  * Examine the Tx buffer to see if there is any more data to be transmitted.\r
273  * \r
274  * If there is data to be transmitted then send the next segment.  A segment\r
275  * can have a maximum of 8 bytes (this is defined as the maximum for the end\r
276  * point by the descriptor).  The final segment may be less than 8 bytes if\r
277  * the total data length was not an exact multiple of 8.\r
278  */\r
279 static void prvSendNextSegment( void );\r
280 \r
281 /*\r
282  * A stall condition is forced each time the host makes a request that is not\r
283  * supported by this minimal implementation.\r
284  * \r
285  * A stall is forced by setting the appropriate bit in the end points control\r
286  * and status register. \r
287  */\r
288 static void prvSendStall( void );\r
289 \r
290 /*\r
291  * A NULL (or zero length packet) is transmitted in acknowledge the reception \r
292  * of certain events from the host.\r
293  */\r
294 static void prvUSBTransmitNull( void );\r
295 \r
296 /* \r
297  * When the host requests a descriptor this function is called to determine \r
298  * which descriptor is being requested and start its transmission.\r
299  */\r
300 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );\r
301 \r
302 /*\r
303  * Transmit movement and clicks on the EK joystick as mouse inputs.\r
304  */\r
305 static void prvTransmitSampleValues( void );\r
306 \r
307 /*\r
308  * The created task to handle the USB demo functionality. \r
309  */\r
310 static void vUSBDemoTask( void *pvParameters );\r
311 \r
312 /*\r
313  * Simple algorithm to ramp up the mouse cursor speed to make it easier to\r
314  * use.\r
315  */\r
316 static void prvControlCursorSpeed( signed char *cVal, unsigned long ulInput, unsigned long ulSwitch1, unsigned long ulSwitch2 );\r
317 /*-----------------------------------------------------------*/\r
318 \r
319 /*\r
320         - DESCRIPTOR DEFINITIONS -\r
321 */\r
322 \r
323 /* String descriptors used during the enumeration process.\r
324 These take the form:\r
325 \r
326 {\r
327         Length of descriptor,\r
328         Descriptor type,\r
329         Data\r
330 }\r
331 */\r
332 const char pxLanguageStringDescriptor[] =\r
333 {\r
334         4,\r
335         usbDESCRIPTOR_TYPE_STRING,\r
336         0x09, 0x04\r
337 };\r
338 \r
339 const char pxManufacturerStringDescriptor[] = \r
340 {\r
341         18,\r
342         usbDESCRIPTOR_TYPE_STRING,\r
343 \r
344         'F', 0x00,\r
345         'r', 0x00,\r
346         'e', 0x00,\r
347         'e', 0x00,\r
348         'R', 0x00,\r
349         'T', 0x00,\r
350         'O', 0x00,\r
351         'S', 0x00       \r
352 };\r
353 \r
354 const char pxProductStringDescriptor[] = \r
355 {\r
356         38,\r
357         usbDESCRIPTOR_TYPE_STRING,\r
358 \r
359         'F', 0x00,\r
360         'r', 0x00,\r
361         'e', 0x00,\r
362         'e', 0x00,\r
363         'R', 0x00,\r
364         'T', 0x00,\r
365         'O', 0x00,\r
366         'S', 0x00,\r
367         '.', 0x00,\r
368         'o', 0x00,\r
369         'r', 0x00,\r
370         'g', 0x00,\r
371         ' ', 0x00,\r
372         'M', 0x00,\r
373         'o', 0x00,\r
374         'u', 0x00,\r
375         's', 0x00,\r
376         'e', 0x00\r
377 };\r
378 \r
379 const char pxConfigurationStringDescriptor[] = \r
380 {\r
381         38,\r
382         usbDESCRIPTOR_TYPE_STRING,\r
383 \r
384         'C', 0x00,\r
385         'o', 0x00,\r
386         'n', 0x00,\r
387         'f', 0x00,\r
388         'i', 0x00,\r
389         'g', 0x00,\r
390         'u', 0x00,\r
391         'r', 0x00,\r
392         'a', 0x00,\r
393         't', 0x00,\r
394         'i', 0x00,\r
395         'o', 0x00,\r
396         'n', 0x00,\r
397         ' ', 0x00,\r
398         'N', 0x00,\r
399         'a', 0x00,\r
400         'm', 0x00,\r
401         'e', 0x00\r
402 };\r
403 \r
404 const char pxInterfaceStringDescriptor[] = \r
405 {\r
406         30,\r
407         usbDESCRIPTOR_TYPE_STRING,\r
408 \r
409         'I', 0x00,\r
410         'n', 0x00,\r
411         't', 0x00,\r
412         'e', 0x00,\r
413         'r', 0x00,\r
414         'f', 0x00,\r
415         'a', 0x00,\r
416         'c', 0x00,\r
417         'e', 0x00,\r
418         ' ', 0x00,\r
419         'N', 0x00,\r
420         'a', 0x00,\r
421         'm', 0x00,\r
422         'e', 0x00\r
423 };\r
424 \r
425 /* Enumeration descriptors. */\r
426 const char pxReportDescriptor[] =\r
427 {\r
428         0x05, 0x01,                                             /* USAGE_PAGE (Generic Desktop)                 */\r
429         0x09, 0x02,                                             /* USAGE (Mouse)                                                */\r
430         0xa1, 0x01,                                             /* COLLECTION (Application)                             */\r
431         0x09, 0x01,                                             /*   USAGE (Pointer)                                    */\r
432         0xa1, 0x00,                                             /*   COLLECTION (Physical)                              */\r
433         0x95, 0x03,                                             /*     REPORT_COUNT (3)                                 */\r
434         0x75, 0x01,                                             /*     REPORT_SIZE (1)                                  */\r
435         0x05, 0x09,                                             /*     USAGE_PAGE (Button)                              */\r
436         0x19, 0x01,                                             /*     USAGE_MINIMUM (Button 1)                 */\r
437         0x29, 0x03,                                             /*     USAGE_MAXIMUM (Button 3)                 */\r
438         0x15, 0x00,                                             /*     LOGICAL_MINIMUM (0)                              */\r
439         0x25, 0x01,                                             /*     LOGICAL_MAXIMUM (1)                              */\r
440         0x81, 0x02,                                             /*     INPUT (Data,Var,Abs)                             */\r
441         0x95, 0x01,                                             /*     REPORT_COUNT (1)                                 */\r
442         0x75, 0x05,                                             /*     REPORT_SIZE (5)                                  */\r
443         0x81, 0x01,                                             /*     INPUT (Cnst,Ary,Abs)                             */\r
444         0x75, 0x08,                                             /*     REPORT_SIZE (8)                                  */\r
445         0x95, 0x02,                                             /*     REPORT_COUNT (2)                                 */\r
446         0x05, 0x01,                                             /*     USAGE_PAGE (Generic Desktop)             */\r
447         0x09, 0x30,                                             /*     USAGE (X)                                                */\r
448         0x09, 0x31,                                             /*     USAGE (Y)                                                */\r
449         0x15, 0x81,                                             /*     LOGICAL_MINIMUM (-127)                   */\r
450         0x25, 0x7f,                                             /*     LOGICAL_MAXIMUM (127)                    */\r
451         0x81, 0x06,                                             /*     INPUT (Data,Var,Rel)                             */\r
452         0xc0,                                                   /*   END_COLLECTION                                             */\r
453         0xc0                                                    /* END_COLLECTION                                               */\r
454 };\r
455 \r
456 \r
457 \r
458 const char pxDeviceDescriptor[] = \r
459 {\r
460         /* Device descriptor */\r
461         0x12,                                                           /* bLength                              */\r
462         0x01,                                                           /* bDescriptorType              */\r
463         0x10, 0x01,                                                     /* bcdUSBL                              */\r
464         usbDEVICE_CLASS_VENDOR_SPECIFIC,        /* bDeviceClass:                */\r
465         0x00,                                                           /* bDeviceSubclass:             */\r
466         0x00,                                                           /* bDeviceProtocol:             */\r
467         0x08,                                                           /* bMaxPacketSize0              */\r
468         0xFF, 0xFF,                                                     /* idVendorL                    */\r
469         0x02, 0x00,                                                     /* idProductL                   */\r
470         0x00, 0x01,                                                     /* bcdDeviceL                   */\r
471         usbMANUFACTURER_STRING,                         /* iManufacturer                */\r
472         usbPRODUCT_STRING,                                      /* iProduct                             */\r
473         0x00,                                                           /* SerialNumber                 */\r
474         0x01                                                            /* bNumConfigs                  */\r
475 };\r
476 \r
477 \r
478 const char pxConfigDescriptor[] = {\r
479         /* Configuration 1 descriptor */\r
480         0x09,                   /* CbLength                                                                     */\r
481         0x02,                   /* CbDescriptorType                                                     */\r
482         0x22, 0x00,             /* CwTotalLength 2 EP + Control                         */\r
483         0x01,                   /* CbNumInterfaces                                                      */\r
484         0x01,                   /* CbConfigurationValue                                         */\r
485         usbCONFIGURATION_STRING,/* CiConfiguration                                      */\r
486         usbBUS_POWERED, /* CbmAttributes Bus powered + Remote Wakeup*/\r
487         0x32,                   /* CMaxPower: 100mA                                                     */\r
488 \r
489         /* Mouse Interface Descriptor Requirement */\r
490         0x09,                   /* bLength                                                                      */\r
491         0x04,                   /* bDescriptorType                                                      */\r
492         0x00,                   /* bInterfaceNumber                                                     */\r
493         0x00,                   /* bAlternateSetting                                            */\r
494         0x01,                   /* bNumEndpoints                                                        */\r
495         0x03,                   /* bInterfaceClass: HID code                            */\r
496         0x01,                   /* bInterfaceSubclass boot                                      */\r
497         0x02,                   /* bInterfaceProtocol mouse boot                        */\r
498         usbINTERFACE_STRING,/* iInterface                                                       */\r
499 \r
500         /* HID Descriptor */\r
501         0x09,                   /* bLength                                                                      */\r
502         0x21,                   /* bDescriptor type: HID Descriptor Type        */\r
503         0x00, 0x01,             /* bcdHID                                                                       */\r
504         0x00,                   /* bCountryCode                                                         */\r
505         0x01,                   /* bNumDescriptors                                                      */\r
506         usbHID_REPORT_DESCRIPTOR,         /* bDescriptorType                    */\r
507         sizeof( pxReportDescriptor ), 0x00, /* wItemLength                      */\r
508 \r
509         /* Endpoint 1 descriptor */\r
510         0x07,                   /* bLength                                                                      */\r
511         0x05,                   /* bDescriptorType                                                      */\r
512         0x81,                   /* bEndpointAddress, Endpoint 01 - IN           */\r
513         0x03,                   /* bmAttributes      INT                                        */\r
514         0x08, 0x00,             /* wMaxPacketSize: 8?                                           */\r
515         0x0A                    /* bInterval                                                            */\r
516 };\r
517 \r
518 /*-----------------------------------------------------------*/\r
519 \r
520 /* File scope state variables. */\r
521 static unsigned char ucUSBConfig = ( unsigned char ) 0;\r
522 static unsigned long ulReceivedAddress = ( unsigned long ) 0;\r
523 static eDRIVER_STATE eDriverState = eNOTHING;\r
524 \r
525 /* Structure used to control the characters being sent to the host. */\r
526 static xTX_MESSAGE pxCharsForTx;\r
527 \r
528 /* Queue used to pass messages between the ISR and the task. */\r
529 QueueHandle_t xUSBInterruptQueue; \r
530 \r
531 /*-----------------------------------------------------------*/\r
532 \r
533 void vStartUSBTask( unsigned portBASE_TYPE uxPriority )\r
534 {\r
535         /* Create the queue used to communicate between the USB ISR and task. */\r
536         xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );\r
537 \r
538         /* Create the task itself. */\r
539         xTaskCreate( vUSBDemoTask, "USB", configMINIMAL_STACK_SIZE, NULL, uxPriority, NULL );\r
540 }\r
541 /*-----------------------------------------------------------*/\r
542 \r
543 static void vUSBDemoTask( void *pvParameters )\r
544 {\r
545 xISRStatus *pxMessage;\r
546 \r
547         /* The parameters are not used in this task. */\r
548         ( void ) pvParameters;\r
549 \r
550     /* Init USB device */\r
551     portENTER_CRITICAL();\r
552             vInitUSBInterface();\r
553     portEXIT_CRITICAL();\r
554 \r
555         /* Process interrupts as they arrive.   The ISR takes a snapshot of the \r
556         interrupt status then posts the information on this queue for processing\r
557         at the task level.  This simple demo implementation only processes\r
558         a few interrupt sources. */\r
559         for( ;; )\r
560         {\r
561                 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORT_DELAY ) )\r
562                 {\r
563                         if( pxMessage->ulISR & AT91C_UDP_EPINT0 )\r
564                         {\r
565                                 /* Process end point 0 interrupt. */\r
566                                 prvProcessEndPoint0Interrupt( pxMessage );\r
567                         }\r
568 \r
569                         if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )\r
570                         {\r
571                                 /* Process an end of bus reset interrupt. */\r
572                                 prvResetEndPoints();            \r
573                         }\r
574                 }\r
575                 else\r
576                 {\r
577                         /* The ISR did not post any data for us to process on the queue, so\r
578                         just generate and send some sample data. */\r
579                         if( eDriverState == eREADY_TO_SEND )\r
580                         {\r
581                                 prvTransmitSampleValues();\r
582                         }\r
583                 }\r
584         }\r
585 }\r
586 /*-----------------------------------------------------------*/\r
587 \r
588 static void prvControlCursorSpeed( signed char *cVal, unsigned long ulInput, unsigned long ulSwitch1, unsigned long ulSwitch2 )\r
589 {\r
590 const char cSpeed = 20;\r
591 \r
592         if( !( ulInput & ulSwitch1 ) )\r
593         {\r
594                 /* We are going in the decreasing y direction. */\r
595                 if( *cVal > 0 )\r
596                 {\r
597                         /* We have changed direction since last time so start from\r
598                         0 again. */\r
599                         *cVal = 0;\r
600                 }\r
601                 \r
602                 if( *cVal > -cSpeed )\r
603                 {\r
604                         /* Ramp y down to the max speed. */\r
605                         (*cVal)--;\r
606                 }\r
607         }\r
608         else if( !( ulInput & ulSwitch2 ) )\r
609         {\r
610                 /* We are going in the increasing y direction. */\r
611                 if( *cVal < 0 )\r
612                 {\r
613                         /* We have changed direction since last time, so start from\r
614                         0 again. */\r
615                         *cVal = 0;\r
616                 }\r
617                 \r
618                 if( *cVal < cSpeed )\r
619                 {\r
620                         /* Ramp y up to the max speed again. */\r
621                         (*cVal)++;\r
622                 }\r
623         }\r
624         else\r
625         {\r
626                 *cVal = 0;\r
627         }\r
628 }\r
629 /*-----------------------------------------------------------*/\r
630 \r
631 static void prvTransmitSampleValues( void )\r
632 {\r
633 /* Variables to hold dummy x, y and z joystick axis data. */\r
634 static signed char x = 0, y = 0, z = 0;\r
635 unsigned long ulStatus;\r
636 \r
637         ulStatus =      AT91C_BASE_PIOA->PIO_PDSR;\r
638 \r
639         prvControlCursorSpeed( &y, ulStatus, ( unsigned long ) usbSW1, ( unsigned long ) usbSW2 );\r
640         prvControlCursorSpeed( &x, ulStatus, ( unsigned long ) usbSW3, ( unsigned long ) usbSW4 );\r
641         \r
642         /* Just make the z axis go up and down. */\r
643         z = ( ( ulStatus & usbSW_CLICK ) == 0 );\r
644 \r
645         /* Can we place data in the fifo? */\r
646         if( !( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & AT91C_UDP_TXPKTRDY ) )\r
647         {\r
648                 /* Write our sample data to the fifo. */\r
649                 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = z;\r
650                 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = x;\r
651                 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = y;\r
652                 \r
653                 /* Send the data. */\r
654                 portENTER_CRITICAL();\r
655                 {\r
656                         ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];\r
657                         usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );\r
658                         AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;\r
659                 }\r
660                 portEXIT_CRITICAL();\r
661         }\r
662 }\r
663 /*-----------------------------------------------------------*/\r
664 \r
665 static void prvUSBTransmitNull( void )\r
666 {\r
667 unsigned long ulStatus;\r
668 \r
669         /* Wait until the FIFO is free - even though we are not going to use it.\r
670         THERE IS NO TIMEOUT HERE! */\r
671         while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )\r
672         {\r
673                 vTaskDelay( usbSHORTEST_DELAY );\r
674         }\r
675 \r
676         portENTER_CRITICAL();\r
677         {\r
678                 /* Set the length of data to send to equal the index of the next byte\r
679                 to send.  This will prevent the ACK to this NULL packet causing any\r
680                 further data transmissions. */\r
681                 pxCharsForTx.ulTotalDataLength = pxCharsForTx.ulNextCharIndex;\r
682 \r
683                 /* Set the TXPKTRDY bit to cause a transmission with no data. */\r
684                 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
685                 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );\r
686                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;\r
687         }\r
688         portEXIT_CRITICAL();\r
689 }\r
690 /*-----------------------------------------------------------*/\r
691 \r
692 static void prvSendStall( void )\r
693 {\r
694 unsigned long ulStatus;\r
695 \r
696         portENTER_CRITICAL();\r
697         {\r
698                 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */\r
699                 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
700                 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );\r
701                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;\r
702         }\r
703         portEXIT_CRITICAL();\r
704 }\r
705 /*-----------------------------------------------------------*/\r
706 \r
707 static void prvResetEndPoints( void )\r
708 {\r
709 unsigned long ulTemp;\r
710 \r
711         eDriverState = eJUST_RESET;\r
712 \r
713         /* Reset all the end points. */\r
714         AT91C_BASE_UDP->UDP_RSTEP  = usbEND_POINT_RESET_MASK;\r
715         AT91C_BASE_UDP->UDP_RSTEP  = ( unsigned long ) 0x00;\r
716 \r
717         /* Enable data to be sent and received. */\r
718         AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;\r
719 \r
720         /* Repair the configuration end point. */\r
721         portENTER_CRITICAL();\r
722         {\r
723                 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
724                 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );\r
725                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;\r
726                 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;\r
727         }\r
728         portEXIT_CRITICAL();\r
729 }\r
730 /*-----------------------------------------------------------*/\r
731 \r
732 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )\r
733 {\r
734         if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )\r
735         {               \r
736                 /* We only expect to receive zero length data here as ACK's. \r
737                 Set the data pointer to the end of the current Tx packet to\r
738                 ensure we don't send out any more data. */      \r
739                 pxCharsForTx.ulNextCharIndex = pxCharsForTx.ulTotalDataLength;\r
740         }\r
741 \r
742         if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )\r
743         {\r
744                 /* We received a TX complete interrupt.  What we do depends on\r
745                 what we sent to get this interrupt. */\r
746 \r
747                 if( eDriverState == eJUST_GOT_CONFIG )\r
748                 {\r
749                         /* We sent an acknowledgement of a SET_CONFIG request.  We\r
750                         are now at the end of the enumeration. */\r
751                         AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;\r
752 \r
753                         /* Read the end point for data transfer. */\r
754                         portENTER_CRITICAL();\r
755                         {\r
756                                 unsigned long ulTemp;\r
757 \r
758                                 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];                                     \r
759                                 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );\r
760                                 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;             \r
761                                 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1;\r
762                         }\r
763                         portEXIT_CRITICAL();\r
764 \r
765                         eDriverState = eREADY_TO_SEND;\r
766                 }               \r
767                 else if( eDriverState == eJUST_GOT_ADDRESS )\r
768                 {\r
769                         /* We sent an acknowledgement of a SET_ADDRESS request.  Move\r
770                         to the addressed state. */\r
771                         if( ulReceivedAddress != ( unsigned long ) 0 )\r
772                         {                       \r
773                                 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;\r
774                         }\r
775                         else\r
776                         {\r
777                                 AT91C_BASE_UDP->UDP_GLBSTATE = 0;\r
778                         }                       \r
779 \r
780                         AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );              \r
781                         eDriverState = eNOTHING;\r
782                 }\r
783                 else\r
784                 {               \r
785                         /* The TXCOMP was not for any special type of transmission.  See\r
786                         if there is any more data to send. */\r
787                         prvSendNextSegment();\r
788                 }\r
789         }\r
790 \r
791         if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )\r
792         {\r
793                 xUSB_REQUEST xRequest;\r
794                 unsigned char ucRequest;\r
795                 unsigned long ulRxBytes;\r
796 \r
797                 /* A data packet is available. */       \r
798                 ulRxBytes = pxMessage->ulCSR0 >> 16;\r
799                 ulRxBytes &= usbRX_COUNT_MASK;\r
800 \r
801                 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )\r
802                 {\r
803                         /* Create an xUSB_REQUEST variable from the raw bytes array. */\r
804 \r
805                         xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];\r
806                         xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];\r
807 \r
808                         /* NOT PORTABLE CODE! */\r
809                         xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];\r
810                         xRequest.usValue <<= 8;\r
811                         xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];\r
812                                                 \r
813                         xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];\r
814                         xRequest.usIndex <<= 8;\r
815                         xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];\r
816                         \r
817                         xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];\r
818                         xRequest.usLength <<= 8;\r
819                         xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];\r
820         \r
821                         /* Manipulate the ucRequestType and the ucRequest parameters to \r
822                         generate a zero based request selection.  This is just done to \r
823                         break up the requests into subsections for clarity.  The \r
824                         alternative would be to have more huge switch statement that would\r
825                         be difficult to optimise. */\r
826                         ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );\r
827                         ucRequest |= ( xRequest.ucReqType & 0x03 );\r
828 \r
829                         switch( ucRequest )\r
830                         {\r
831                                 case usbSTANDARD_DEVICE_REQUEST:        \r
832                                                         /* Standard Device request */\r
833                                                         prvHandleStandardDeviceRequest( &xRequest );\r
834                                                         break;\r
835         \r
836                                 case usbSTANDARD_INTERFACE_REQUEST:     \r
837                                                         /* Standard Interface request */\r
838                                                         prvHandleStandardInterfaceRequest( &xRequest );\r
839                                                         break;\r
840         \r
841                                 case usbSTANDARD_END_POINT_REQUEST:     \r
842                                                         /* Standard Endpoint request */\r
843                                                         prvHandleStandardEndPointRequest( &xRequest );\r
844                                                         break;\r
845         \r
846                                 case usbCLASS_INTERFACE_REQUEST:        \r
847                                                         /* Class Interface request */\r
848                                                         prvHandleClassInterfaceRequest( &xRequest );\r
849                                                         break;\r
850         \r
851                                 default:        /* This is not something we want to respond to. */\r
852                                                         prvSendStall(); \r
853                         }\r
854                 }\r
855         }\r
856 }\r
857 /*-----------------------------------------------------------*/\r
858 \r
859 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )\r
860 {\r
861         /* The type is in the high byte.  Return whatever has been requested. */\r
862         switch( ( pxRequest->usValue & 0xff00 ) >> 8 )\r
863         {\r
864             case usbDESCRIPTOR_TYPE_DEVICE:\r
865                         prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );\r
866                     break;\r
867         \r
868             case usbDESCRIPTOR_TYPE_CONFIGURATION:\r
869                         prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );\r
870                     break;\r
871 \r
872             case usbDESCRIPTOR_TYPE_STRING:\r
873 \r
874                         /* The index to the string descriptor is the lower byte. */\r
875                     switch( pxRequest->usValue & 0xff )\r
876                         {                       \r
877                         case usbLANGUAGE_STRING:\r
878                                         prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );\r
879                                 break;\r
880 \r
881                         case usbMANUFACTURER_STRING:\r
882                                         prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );\r
883                                 break;\r
884 \r
885                         case usbPRODUCT_STRING:\r
886                                         prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );\r
887                                 break;\r
888 \r
889                         case usbCONFIGURATION_STRING:\r
890                                         prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );\r
891                                 break;\r
892 \r
893                         case usbINTERFACE_STRING:\r
894                                         prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );\r
895                                 break;\r
896 \r
897                         default:\r
898                                 /* Don't know what this string is. */\r
899                                         prvSendStall();\r
900                                         break;\r
901                         }\r
902 \r
903                         break;\r
904 \r
905             default:\r
906                         /* We are not responding to anything else. */\r
907                         prvSendStall();\r
908                     break;\r
909         }\r
910 }\r
911 /*-----------------------------------------------------------*/\r
912 \r
913 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )\r
914 {\r
915 unsigned short usStatus = 0;\r
916 \r
917         switch( pxRequest->ucRequest )\r
918         {\r
919             case usbGET_STATUS_REQUEST:\r
920                         /* Just send two byte dummy status. */\r
921                         prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );\r
922                     break;\r
923 \r
924             case usbGET_DESCRIPTOR_REQUEST:\r
925                         /* Send device descriptor */\r
926                     prvGetStandardDeviceDescriptor( pxRequest );\r
927                     break;\r
928 \r
929             case usbGET_CONFIGURATION_REQUEST:\r
930                         /* Send selected device configuration */\r
931                         prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );\r
932                     break;\r
933 \r
934                 case usbSET_FEATURE_REQUEST:\r
935                     prvUSBTransmitNull();\r
936                     break;\r
937 \r
938             case usbSET_ADDRESS_REQUEST:\r
939                 \r
940                         /* Acknowledge the SET_ADDRESS, but (according to the manual) we\r
941                         cannot actually move to the addressed state until we get a TXCOMP\r
942                         interrupt from this NULL packet.  Therefore we just remember the\r
943                         address and set our state so we know we have received the address. */\r
944                 prvUSBTransmitNull();                   \r
945                         eDriverState = eJUST_GOT_ADDRESS;               \r
946                         ulReceivedAddress = ( unsigned long ) pxRequest->usValue;\r
947                     break;\r
948 \r
949             case usbSET_CONFIGURATION_REQUEST:\r
950 \r
951                         /* Acknowledge the SET_CONFIGURATION, but (according to the manual) \r
952                         we cannot actually move to the configured state until we get a \r
953                         TXCOMP interrupt from this NULL packet.  Therefore we just remember the\r
954                         config and set our state so we know we have received the go ahead. */                   \r
955                         ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );\r
956                         eDriverState = eJUST_GOT_CONFIG;\r
957                         prvUSBTransmitNull();\r
958                     break;\r
959 \r
960             default:\r
961 \r
962                     /* We don't answer to anything else. */\r
963                         prvSendStall();\r
964                     break;\r
965         }\r
966 }\r
967 /*-----------------------------------------------------------*/\r
968 \r
969 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )\r
970 {\r
971         switch( pxRequest->ucRequest )\r
972         {\r
973             case usbSET_IDLE_REQUEST:\r
974                 prvUSBTransmitNull();\r
975                         break;\r
976 \r
977                 /* This minimal implementation ignores these. */\r
978             case usbGET_REPORT_REQUEST:\r
979             case usbGET_IDLE_REQUEST:\r
980             case usbGET_PROTOCOL_REQUEST:\r
981             case usbSET_REPORT_REQUEST:\r
982             case usbSET_PROTOCOL_REQUEST:       \r
983             default:\r
984 \r
985                         prvSendStall();\r
986                         break;\r
987         }\r
988 }\r
989 /*-----------------------------------------------------------*/\r
990 \r
991 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )\r
992 {\r
993         switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )\r
994         {\r
995             case usbHID_REPORT_DESCRIPTOR:\r
996                         prvSendControlData( ( unsigned char * ) pxReportDescriptor, pxRequest->usLength, sizeof( pxReportDescriptor ), pdTRUE );\r
997                     break;\r
998 \r
999             default:\r
1000 \r
1001                         /* Don't expect to send any others. */\r
1002                         prvSendStall();\r
1003                     break;\r
1004         }\r
1005 }\r
1006 /*-----------------------------------------------------------*/\r
1007 \r
1008 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )\r
1009 {\r
1010 unsigned short usStatus = 0;\r
1011 \r
1012         switch( pxRequest->ucRequest )\r
1013         {\r
1014             case usbGET_STATUS_REQUEST:\r
1015                         /* Send dummy 2 bytes. */\r
1016                         prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );\r
1017                         break;\r
1018 \r
1019             case usbGET_DESCRIPTOR_REQUEST:\r
1020                         prvGetStandardInterfaceDescriptor( pxRequest ); \r
1021                         break;\r
1022 \r
1023                 /* This minimal implementation does not respond to these. */\r
1024             case usbGET_INTERFACE_REQUEST:\r
1025             case usbSET_FEATURE_REQUEST:\r
1026             case usbSET_INTERFACE_REQUEST:      \r
1027 \r
1028             default:\r
1029                         prvSendStall();\r
1030                         break;\r
1031         }\r
1032 }\r
1033 /*-----------------------------------------------------------*/\r
1034 \r
1035 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )\r
1036 {\r
1037         switch( pxRequest->ucRequest )\r
1038         {\r
1039                 /* This minimal implementation does not expect to respond to these. */\r
1040             case usbGET_STATUS_REQUEST:\r
1041             case usbCLEAR_FEATURE_REQUEST: \r
1042             case usbSET_FEATURE_REQUEST:\r
1043 \r
1044             default:                    \r
1045                         prvSendStall();\r
1046                         break;\r
1047         }\r
1048 }\r
1049 /*-----------------------------------------------------------*/\r
1050 \r
1051 static void vInitUSBInterface( void )\r
1052 {\r
1053 volatile unsigned long ulTemp;\r
1054 \r
1055         /* Initialise a few state variables. */\r
1056         pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;\r
1057         ucUSBConfig = ( unsigned char ) 0;\r
1058         eDriverState = eNOTHING;\r
1059 \r
1060         /* HARDWARE SETUP */\r
1061 \r
1062     /* Set the PLL USB Divider */\r
1063     AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;\r
1064 \r
1065     /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */\r
1066     AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
1067     AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
1068 \r
1069     /* Setup the PIO for the USB pull up resistor. */\r
1070     AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16;\r
1071     AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16;\r
1072     \r
1073 \r
1074     /* Start without the pullup - this will get set at the end of this \r
1075         function. */\r
1076     AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16;\r
1077 \r
1078         /* When using the USB debugger the peripheral registers do not always get\r
1079         set to the correct default values.  To make sure set the relevant registers\r
1080         manually here. */\r
1081         AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;\r
1082         AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;\r
1083         AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;\r
1084         AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;\r
1085         AT91C_BASE_UDP->UDP_GLBSTATE = 0;\r
1086         AT91C_BASE_UDP->UDP_FADDR = 0;\r
1087 \r
1088         /* Enable the transceiver. */\r
1089         AT91C_UDP_TRANSCEIVER_ENABLE = 0;\r
1090 \r
1091         /* Enable the USB interrupts - other interrupts get enabled as the \r
1092         enumeration process progresses. */\r
1093         AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );\r
1094         AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;\r
1095 \r
1096         /* Wait a short while before making our presence known. */\r
1097         vTaskDelay( usbINIT_DELAY );\r
1098         AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16;\r
1099 }\r
1100 /*-----------------------------------------------------------*/\r
1101 \r
1102 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )\r
1103 {\r
1104         if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )\r
1105         {\r
1106                 /* Cap the data length to that requested. */\r
1107                 ulLengthToSend = ( unsigned short ) usRequestedLength;\r
1108         }\r
1109         else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )\r
1110         {\r
1111                 /* We are sending a descriptor.  If the descriptor is an exact \r
1112                 multiple of the FIFO length then it will have to be terminated\r
1113                 with a NULL packet.  Set the state to indicate this if\r
1114                 necessary. */\r
1115                 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )\r
1116                 {\r
1117                         eDriverState = eSENDING_EVEN_DESCRIPTOR;\r
1118                 }\r
1119         }\r
1120 \r
1121         /* Here we assume that the previous message has been sent.  THERE IS NO\r
1122         BUFFER OVERFLOW PROTECTION HERE.\r
1123 \r
1124         Copy the data to send into the buffer as we cannot send it all at once\r
1125         (if it is greater than 8 bytes in length). */\r
1126         memcpy( pxCharsForTx.ucTxBuffer, pucData, ulLengthToSend );\r
1127 \r
1128         /* Reinitialise the buffer index so we start sending from the start of \r
1129         the data. */\r
1130         pxCharsForTx.ulTotalDataLength = ulLengthToSend;\r
1131         pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;\r
1132 \r
1133         /* Send the first 8 bytes now.  The rest will get sent in response to \r
1134         TXCOMP interrupts. */\r
1135         prvSendNextSegment();\r
1136 }\r
1137 /*-----------------------------------------------------------*/\r
1138 \r
1139 static void prvSendNextSegment( void )\r
1140 {\r
1141 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;\r
1142 \r
1143         /* Is there any data to send? */\r
1144         if( pxCharsForTx.ulTotalDataLength > pxCharsForTx.ulNextCharIndex )\r
1145         {\r
1146                 ulLengthLeftToSend = pxCharsForTx.ulTotalDataLength - pxCharsForTx.ulNextCharIndex;\r
1147         \r
1148                 /* We can only send 8 bytes to the fifo at a time. */\r
1149                 if( ulLengthLeftToSend > usbFIFO_LENGTH )\r
1150                 {\r
1151                         ulNextLength = usbFIFO_LENGTH;\r
1152                 }\r
1153                 else\r
1154                 {\r
1155                         ulNextLength = ulLengthLeftToSend;\r
1156                 }\r
1157 \r
1158                 /* Wait until we can place data in the fifo.  THERE IS NO TIMEOUT\r
1159                 HERE! */\r
1160                 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )\r
1161                 {\r
1162                         vTaskDelay( usbSHORTEST_DELAY );\r
1163                 }\r
1164 \r
1165                 /* Write the data to the FIFO. */\r
1166                 while( ulNextLength > ( unsigned long ) 0 )\r
1167                 {\r
1168                         AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxCharsForTx.ucTxBuffer[ pxCharsForTx.ulNextCharIndex ];\r
1169         \r
1170                         ulNextLength--;\r
1171                         pxCharsForTx.ulNextCharIndex++;\r
1172                 }\r
1173         \r
1174                 /* Start the transmission. */\r
1175                 portENTER_CRITICAL();\r
1176                 {\r
1177                         ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];\r
1178                         usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );\r
1179                         AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;\r
1180                 }\r
1181                 portEXIT_CRITICAL();\r
1182         }\r
1183         else\r
1184         {\r
1185                 /* There is no data to send.  If we were sending a descriptor and the \r
1186                 descriptor was an exact multiple of the max packet size then we need\r
1187                 to send a null to terminate the transmission. */\r
1188                 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )\r
1189                 {\r
1190                         prvUSBTransmitNull();\r
1191                         eDriverState = eNOTHING;\r
1192                 }\r
1193         }\r
1194 }\r
1195 \r
1196 \r
1197 \r