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