Multiple USB-CDC changes (attempt 6) (#439)
[proxmark3-svn] / common / usb_cdc.c
CommitLineData
5bcc76c4 1/*\r
2 * at91sam7s USB CDC device implementation\r
3 *\r
4 * Copyright (c) 2012, Roel Verdult\r
5 * All rights reserved.\r
6 *\r
7 * Redistribution and use in source and binary forms, with or without\r
8 * modification, are permitted provided that the following conditions are met:\r
9 * 1. Redistributions of source code must retain the above copyright\r
10 * notice, this list of conditions and the following disclaimer.\r
11 * 2. Redistributions in binary form must reproduce the above copyright\r
12 * notice, this list of conditions and the following disclaimer in the\r
13 * documentation and/or other materials provided with the distribution.\r
14 * 3. Neither the name of the copyright holders nor the\r
15 * names of its contributors may be used to endorse or promote products\r
16 * derived from this software without specific prior written permission.\r
17 *\r
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY\r
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY\r
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 *\r
29 * based on the "Basic USB Example" from ATMEL (doc6123.pdf)\r
30 *\r
31 * @file usb_cdc.c\r
32 * @brief\r
33 */\r
34\r
35#include "usb_cdc.h"\r
1f42ccdd 36#include "at91sam7s512.h"\r
79a73ab2 37#include "config_gpio.h"\r
5bcc76c4 38\r
3a89d04c 39\r
40#define AT91C_EP_CONTROL 0\r
5bcc76c4 41#define AT91C_EP_OUT 1\r
5bcc76c4 42#define AT91C_EP_IN 2\r
f194e429 43#define AT91C_EP_NOTIFY 3\r
44#define AT91C_EP_OUT_SIZE 0x40\r
45#define AT91C_EP_IN_SIZE 0x40\r
5bcc76c4 46\r
05b6b117
MF
47// Language must always be 0.\r
48#define STR_LANGUAGE_CODES 0x00\r
49#define STR_MANUFACTURER 0x01\r
50#define STR_PRODUCT 0x02\r
51\r
1f42ccdd 52static const char devDescriptor[] = {\r
5bcc76c4 53 /* Device descriptor */\r
54 0x12, // bLength\r
55 0x01, // bDescriptorType\r
1f42ccdd 56 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)\r
f194e429 57 0x02, // bDeviceClass: (Communication Device Class)\r
58 0x00, // bDeviceSubclass: (unused at this time)\r
59 0x00, // bDeviceProtocol: (unused at this time)\r
5bcc76c4 60 0x08, // bMaxPacketSize0\r
1f42ccdd 61 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)\r
62 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)\r
5bcc76c4 63 0x01,0x00, // Device release number (0001)\r
05b6b117
MF
64 STR_MANUFACTURER, // iManufacturer\r
65 STR_PRODUCT, // iProduct\r
1f42ccdd 66 0x00, // iSerialNumber\r
5bcc76c4 67 0x01 // bNumConfigs\r
68};\r
69\r
1f42ccdd 70static const char cfgDescriptor[] = {\r
5bcc76c4 71 /* ============== CONFIGURATION 1 =========== */\r
72 /* Configuration 1 descriptor */\r
73 0x09, // CbLength\r
74 0x02, // CbDescriptorType\r
75 0x43, // CwTotalLength 2 EP + Control\r
76 0x00,\r
77 0x02, // CbNumInterfaces\r
78 0x01, // CbConfigurationValue\r
79 0x00, // CiConfiguration\r
80 0xC0, // CbmAttributes 0xA0\r
1f42ccdd 81 0xFA, // CMaxPower\r
5bcc76c4 82\r
f194e429 83 /* Interface 0 Descriptor: Communication Class Interface */\r
5bcc76c4 84 0x09, // bLength\r
85 0x04, // bDescriptorType\r
86 0x00, // bInterfaceNumber\r
87 0x00, // bAlternateSetting\r
88 0x01, // bNumEndpoints\r
f194e429 89 0x02, // bInterfaceClass: Communication Interface Class\r
90 0x02, // bInterfaceSubclass: Abstract Control Model\r
91 0x01, // bInterfaceProtocol: Common AT Commands, V.25ter\r
5bcc76c4 92 0x00, // iInterface\r
93\r
94 /* Header Functional Descriptor */\r
95 0x05, // bFunction Length\r
f194e429 96 0x24, // bDescriptor type: CS_INTERFACE\r
97 0x00, // bDescriptor subtype: Header Functional Descriptor\r
5bcc76c4 98 0x10, // bcdCDC:1.1\r
99 0x01,\r
100\r
101 /* ACM Functional Descriptor */\r
102 0x04, // bFunctionLength\r
f194e429 103 0x24, // bDescriptor Type: CS_INTERFACE\r
104 0x02, // bDescriptor Subtype: Abstract Control Management Functional Descriptor\r
105 0x02, // bmCapabilities: D1: Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State\r
5bcc76c4 106\r
107 /* Union Functional Descriptor */\r
108 0x05, // bFunctionLength\r
f194e429 109 0x24, // bDescriptorType: CS_INTERFACE\r
110 0x06, // bDescriptor Subtype: Union Functional Descriptor\r
111 0x00, // bMasterInterface: Communication Class Interface\r
112 0x01, // bSlaveInterface0: Data Class Interface\r
5bcc76c4 113\r
114 /* Call Management Functional Descriptor */\r
115 0x05, // bFunctionLength\r
f194e429 116 0x24, // bDescriptor Type: CS_INTERFACE\r
117 0x01, // bDescriptor Subtype: Call Management Functional Descriptor\r
118 0x00, // bmCapabilities: Device sends/receives call management information only over the Communication Class interface. Device does not handle call management itself\r
119 0x01, // bDataInterface: Data Class Interface 1\r
5bcc76c4 120\r
121 /* Endpoint 1 descriptor */\r
122 0x07, // bLength\r
123 0x05, // bDescriptorType\r
f194e429 124 0x83, // bEndpointAddress: Endpoint 03 - IN\r
125 0x03, // bmAttributes: INT\r
126 0x08, // wMaxPacketSize: 8\r
5bcc76c4 127 0x00,\r
128 0xFF, // bInterval\r
129\r
f194e429 130 /* Interface 1 Descriptor: Data Class Interface */\r
5bcc76c4 131 0x09, // bLength\r
132 0x04, // bDescriptorType\r
133 0x01, // bInterfaceNumber\r
134 0x00, // bAlternateSetting\r
135 0x02, // bNumEndpoints\r
f194e429 136 0x0A, // bInterfaceClass: Data Interface Class\r
137 0x00, // bInterfaceSubclass: not used\r
138 0x00, // bInterfaceProtocol: No class specific protocol required)\r
5bcc76c4 139 0x00, // iInterface\r
140\r
5bcc76c4 141 /* Endpoint 1 descriptor */\r
142 0x07, // bLength\r
143 0x05, // bDescriptorType\r
f194e429 144 0x01, // bEndpointAddress: Endpoint 01 - OUT\r
145 0x02, // bmAttributes: BULK\r
146 AT91C_EP_OUT_SIZE, // wMaxPacketSize\r
5bcc76c4 147 0x00,\r
148 0x00, // bInterval\r
149\r
150 /* Endpoint 2 descriptor */\r
151 0x07, // bLength\r
152 0x05, // bDescriptorType\r
f194e429 153 0x82, // bEndpointAddress: Endpoint 02 - IN\r
154 0x02, // bmAttributes: BULK\r
5bcc76c4 155 AT91C_EP_IN_SIZE, // wMaxPacketSize\r
156 0x00,\r
157 0x00 // bInterval\r
158};\r
159\r
1f42ccdd 160static const char StrDescLanguageCodes[] = {\r
161 4, // Length\r
162 0x03, // Type is string\r
163 0x09, 0x04 // supported language Code 0 = 0x0409 (English)\r
164};\r
05b6b117
MF
165\r
166// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the\r
167// manufacturer string "proxmark.org". Don't change this.\r
1f42ccdd 168static const char StrDescManufacturer[] = {\r
169 26, // Length\r
5bcc76c4 170 0x03, // Type is string\r
171 'p', 0x00,\r
172 'r', 0x00,\r
173 'o', 0x00,\r
174 'x', 0x00,\r
175 'm', 0x00,\r
176 'a', 0x00,\r
177 'r', 0x00,\r
178 'k', 0x00,\r
179 '.', 0x00,\r
180 'o', 0x00,\r
181 'r', 0x00,\r
1f42ccdd 182 'g', 0x00\r
183};\r
184\r
185static const char StrDescProduct[] = {\r
186 8, // Length\r
187 0x03, // Type is string\r
188 'P', 0x00,\r
189 'M', 0x00,\r
190 '3', 0x00\r
191};\r
5bcc76c4 192\r
1f42ccdd 193const char* getStringDescriptor(uint8_t idx)\r
194{\r
05b6b117
MF
195 switch (idx) {\r
196 case STR_LANGUAGE_CODES:\r
197 return StrDescLanguageCodes;\r
198 case STR_MANUFACTURER:\r
199 return StrDescManufacturer;\r
200 case STR_PRODUCT:\r
201 return StrDescProduct;\r
202 default:\r
203 return NULL;\r
1f42ccdd 204 }\r
205}\r
5bcc76c4 206\r
3a89d04c 207// Bitmap for all status bits in CSR which must be written as 1 to cause no effect\r
208#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \\r
209 |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \\r
210 |AT91C_UDP_TXCOMP\r
211\r
212// Clear flags in the UDP_CSR register\r
213#define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \\r
214 volatile unsigned int reg; \\r
215 reg = pUdp->UDP_CSR[(endpoint)]; \\r
216 reg |= REG_NO_EFFECT_1_ALL; \\r
217 reg &= ~(flags); \\r
218 pUdp->UDP_CSR[(endpoint)] = reg; \\r
219} \r
220\r
221// Set flags in the UDP_CSR register\r
222#define UDP_SET_EP_FLAGS(endpoint, flags) { \\r
223 volatile unsigned int reg; \\r
224 reg = pUdp->UDP_CSR[(endpoint)]; \\r
225 reg |= REG_NO_EFFECT_1_ALL; \\r
226 reg |= (flags); \\r
227 pUdp->UDP_CSR[(endpoint)] = reg; \\r
228}\r
229\r
230/* USB standard request codes */\r
5bcc76c4 231#define STD_GET_STATUS_ZERO 0x0080\r
232#define STD_GET_STATUS_INTERFACE 0x0081\r
233#define STD_GET_STATUS_ENDPOINT 0x0082\r
234\r
235#define STD_CLEAR_FEATURE_ZERO 0x0100\r
236#define STD_CLEAR_FEATURE_INTERFACE 0x0101\r
237#define STD_CLEAR_FEATURE_ENDPOINT 0x0102\r
238\r
239#define STD_SET_FEATURE_ZERO 0x0300\r
240#define STD_SET_FEATURE_INTERFACE 0x0301\r
241#define STD_SET_FEATURE_ENDPOINT 0x0302\r
242\r
243#define STD_SET_ADDRESS 0x0500\r
244#define STD_GET_DESCRIPTOR 0x0680\r
245#define STD_SET_DESCRIPTOR 0x0700\r
246#define STD_GET_CONFIGURATION 0x0880\r
247#define STD_SET_CONFIGURATION 0x0900\r
248#define STD_GET_INTERFACE 0x0A81\r
249#define STD_SET_INTERFACE 0x0B01\r
250#define STD_SYNCH_FRAME 0x0C82\r
251\r
252/* CDC Class Specific Request Code */\r
253#define GET_LINE_CODING 0x21A1\r
254#define SET_LINE_CODING 0x2021\r
255#define SET_CONTROL_LINE_STATE 0x2221\r
256\r
257typedef struct {\r
258 unsigned int dwDTERRate;\r
259 char bCharFormat;\r
260 char bParityType;\r
261 char bDataBits;\r
262} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;\r
263\r
264AT91S_CDC_LINE_CODING line = {\r
265 115200, // baudrate\r
266 0, // 1 Stop Bit\r
267 0, // None Parity\r
268 8}; // 8 Data bits\r
269\r
f194e429 270\r
5bcc76c4 271void AT91F_CDC_Enumerate();\r
272\r
273AT91PS_UDP pUdp = AT91C_BASE_UDP;\r
274byte_t btConfiguration = 0;\r
275byte_t btConnection = 0;\r
276byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;\r
277\r
f194e429 278\r
6e82300d 279//*----------------------------------------------------------------------------\r
79a73ab2 280//* \fn usb_disable\r
6e82300d 281//* \brief This function deactivates the USB device\r
282//*----------------------------------------------------------------------------\r
283void usb_disable() {\r
f194e429 284 // Disconnect the USB device\r
285 AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;\r
286\r
287 // Clear all lingering interrupts\r
288 if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {\r
289 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
290 }\r
6e82300d 291}\r
292\r
f194e429 293\r
5bcc76c4 294//*----------------------------------------------------------------------------\r
79a73ab2 295//* \fn usb_enable\r
5bcc76c4 296//* \brief This function Activates the USB device\r
297//*----------------------------------------------------------------------------\r
6e82300d 298void usb_enable() {\r
f194e429 299 // Set the PLL USB Divider\r
300 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;\r
301\r
302 // Specific Chip USB Initialisation\r
303 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock\r
304 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
305 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
306\r
307 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO\r
308 // Set in PIO mode and Configure in Output\r
309 AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode\r
79a73ab2 310 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output\r
f194e429 311\r
312 // Clear for set the Pullup resistor\r
79a73ab2 313 AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;\r
6e82300d 314\r
f194e429 315 // Disconnect and reconnect USB controller for 100ms\r
316 usb_disable();\r
317\r
318 // Wait for a short while\r
319 for (volatile size_t i=0; i<0x100000; i++);\r
320\r
321 // Reconnect USB reconnect\r
322 AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;\r
323 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;\r
5bcc76c4 324}\r
325\r
f194e429 326\r
5bcc76c4 327//*----------------------------------------------------------------------------\r
79a73ab2 328//* \fn usb_check\r
5bcc76c4 329//* \brief Test if the device is configured and handle enumeration\r
330//*----------------------------------------------------------------------------\r
6e82300d 331bool usb_check() {\r
5bcc76c4 332 AT91_REG isr = pUdp->UDP_ISR;\r
333\r
334 if (isr & AT91C_UDP_ENDBUSRES) {\r
335 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
336 // reset all endpoints\r
337 pUdp->UDP_RSTEP = (unsigned int)-1;\r
338 pUdp->UDP_RSTEP = 0;\r
339 // Enable the function\r
340 pUdp->UDP_FADDR = AT91C_UDP_FEN;\r
341 // Configure endpoint 0\r
3a89d04c 342 pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);\r
f194e429 343 } else if (isr & AT91C_UDP_EPINT0) {\r
5bcc76c4 344 pUdp->UDP_ICR = AT91C_UDP_EPINT0;\r
345 AT91F_CDC_Enumerate();\r
346 }\r
347 return (btConfiguration) ? true : false;\r
348}\r
349\r
350\r
351bool usb_poll()\r
352{\r
f194e429 353 if (!usb_check()) return false;\r
354 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
5bcc76c4 355}\r
356\r
f194e429 357\r
83f3f8ac
MHS
358/**\r
359 In github PR #129, some users appears to get a false positive from\r
360 usb_poll, which returns true, but the usb_read operation\r
361 still returns 0.\r
362 This check is basically the same as above, but also checks\r
363 that the length available to read is non-zero, thus hopefully fixes the\r
364 bug.\r
365**/\r
366bool usb_poll_validate_length()\r
367{\r
83f3f8ac
MHS
368 if (!usb_check()) return false;\r
369 if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;\r
370 return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;\r
371}\r
372\r
5bcc76c4 373//*----------------------------------------------------------------------------\r
79a73ab2 374//* \fn usb_read\r
5bcc76c4 375//* \brief Read available data from Endpoint OUT\r
376//*----------------------------------------------------------------------------\r
6e82300d 377uint32_t usb_read(byte_t* data, size_t len) {\r
d2deaf7b 378 byte_t bank = btReceiveBank;\r
5bcc76c4 379 uint32_t packetSize, nbBytesRcv = 0;\r
d2deaf7b 380 uint32_t time_out = 0;\r
5bcc76c4 381 \r
23b598ee 382 while (len) {\r
5bcc76c4 383 if (!usb_check()) break;\r
384\r
385 if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) {\r
386 packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len);\r
d2deaf7b 387 len -= packetSize;\r
5bcc76c4 388 while(packetSize--)\r
389 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
3a89d04c 390 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
23b598ee 391 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
5bcc76c4 392 bank = AT91C_UDP_RX_DATA_BK1;\r
d2deaf7b 393 } else {\r
5bcc76c4 394 bank = AT91C_UDP_RX_DATA_BK0;\r
d2deaf7b 395 }\r
5bcc76c4 396 }\r
d2deaf7b 397 if (time_out++ == 0x1fff) break;\r
5bcc76c4 398 }\r
399\r
400 btReceiveBank = bank;\r
401 return nbBytesRcv;\r
402}\r
403\r
f194e429 404\r
5bcc76c4 405//*----------------------------------------------------------------------------\r
79a73ab2 406//* \fn usb_write\r
5bcc76c4 407//* \brief Send through endpoint 2\r
408//*----------------------------------------------------------------------------\r
6e82300d 409uint32_t usb_write(const byte_t* data, const size_t len) {\r
f194e429 410 size_t length = len;\r
5bcc76c4 411 uint32_t cpt = 0;\r
412\r
f194e429 413 if (!length) return 0;\r
414 if (!usb_check()) return 0;\r
415\r
5bcc76c4 416 // Send the first packet\r
f194e429 417 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 418 length -= cpt;\r
f194e429 419 while (cpt--) {\r
420 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
421 }\r
3a89d04c 422 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 423\r
424 while (length) {\r
f194e429 425 // Fill the next bank\r
426 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 427 length -= cpt;\r
f194e429 428 while (cpt--) {\r
429 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
430 }\r
431 // Wait for the previous bank to be sent\r
5bcc76c4 432 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
433 if (!usb_check()) return length;\r
f194e429 434 }\r
3a89d04c 435 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 436 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
3a89d04c 437 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 438 }\r
f194e429 439\r
5bcc76c4 440 // Wait for the end of transfer\r
441 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
442 if (!usb_check()) return length;\r
f194e429 443 }\r
444\r
3a89d04c 445 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 446 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
447\r
448 return length;\r
449}\r
450\r
f194e429 451\r
5bcc76c4 452//*----------------------------------------------------------------------------\r
453//* \fn AT91F_USB_SendData\r
454//* \brief Send Data through the control endpoint\r
455//*----------------------------------------------------------------------------\r
5ee70129 456unsigned int csrTab[100] = {0x00};\r
5bcc76c4 457unsigned char csrIdx = 0;\r
458\r
6e82300d 459static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
5bcc76c4 460 uint32_t cpt = 0;\r
461 AT91_REG csr;\r
462\r
463 do {\r
464 cpt = MIN(length, 8);\r
465 length -= cpt;\r
466\r
467 while (cpt--)\r
468 pUdp->UDP_FDR[0] = *pData++;\r
469\r
3a89d04c 470 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
471 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
472 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 473 }\r
474\r
3a89d04c 475 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 476 do {\r
3a89d04c 477 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
5bcc76c4 478\r
479 // Data IN stage has been stopped by a status OUT\r
480 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
3a89d04c 481 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 482 return;\r
483 }\r
484 } while ( !(csr & AT91C_UDP_TXCOMP) );\r
485\r
486 } while (length);\r
487\r
3a89d04c 488 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
489 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
490 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 491 }\r
492}\r
493\r
f194e429 494\r
5bcc76c4 495//*----------------------------------------------------------------------------\r
496//* \fn AT91F_USB_SendZlp\r
497//* \brief Send zero length packet through the control endpoint\r
498//*----------------------------------------------------------------------------\r
6e82300d 499void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
3a89d04c 500 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
501 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) );\r
502 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
503 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 504}\r
505\r
f194e429 506\r
5bcc76c4 507//*----------------------------------------------------------------------------\r
508//* \fn AT91F_USB_SendStall\r
509//* \brief Stall the control endpoint\r
510//*----------------------------------------------------------------------------\r
6e82300d 511void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
3a89d04c 512 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
513 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR) );\r
514 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
515 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));\r
5bcc76c4 516}\r
517\r
f194e429 518\r
5bcc76c4 519//*----------------------------------------------------------------------------\r
520//* \fn AT91F_CDC_Enumerate\r
521//* \brief This function is a callback invoked when a SETUP packet is received\r
522//*----------------------------------------------------------------------------\r
6e82300d 523void AT91F_CDC_Enumerate() {\r
5bcc76c4 524 byte_t bmRequestType, bRequest;\r
525 uint16_t wValue, wIndex, wLength, wStatus;\r
526\r
3a89d04c 527 if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) )\r
5bcc76c4 528 return;\r
529\r
f194e429 530 bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
531 bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
532 wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
533 wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
534 wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
535 wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
536 wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
537 wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
5bcc76c4 538\r
f194e429 539 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
3a89d04c 540 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
541 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) );\r
5bcc76c4 542 }\r
3a89d04c 543 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
544 while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) );\r
5bcc76c4 545\r
546 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
547 switch ((bRequest << 8) | bmRequestType) {\r
548 case STD_GET_DESCRIPTOR:\r
549 if (wValue == 0x100) // Return Device Descriptor\r
550 AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
551 else if (wValue == 0x200) // Return Configuration Descriptor\r
552 AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
1f42ccdd 553 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
554 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
555 if (strDescriptor != NULL) {\r
556 AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength));\r
557 } else {\r
558 AT91F_USB_SendStall(pUdp);\r
559 }\r
560 }\r
5bcc76c4 561 else\r
562 AT91F_USB_SendStall(pUdp);\r
563 break;\r
564 case STD_SET_ADDRESS:\r
565 AT91F_USB_SendZlp(pUdp);\r
566 pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
567 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
568 break;\r
569 case STD_SET_CONFIGURATION:\r
570 btConfiguration = wValue;\r
571 AT91F_USB_SendZlp(pUdp);\r
572 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
f194e429 573 pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
574 pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
575 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
5bcc76c4 576 break;\r
577 case STD_GET_CONFIGURATION:\r
578 AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));\r
579 break;\r
580 case STD_GET_STATUS_ZERO:\r
f194e429 581 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
5bcc76c4 582 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
583 break;\r
584 case STD_GET_STATUS_INTERFACE:\r
f194e429 585 wStatus = 0; // reserved for future use\r
5bcc76c4 586 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
587 break;\r
588 case STD_GET_STATUS_ENDPOINT:\r
589 wStatus = 0;\r
590 wIndex &= 0x0F;\r
f194e429 591 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 592 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
593 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
594 }\r
f194e429 595 else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
5bcc76c4 596 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
597 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
598 }\r
599 else\r
600 AT91F_USB_SendStall(pUdp);\r
601 break;\r
602 case STD_SET_FEATURE_ZERO:\r
603 AT91F_USB_SendStall(pUdp);\r
604 break;\r
605 case STD_SET_FEATURE_INTERFACE:\r
606 AT91F_USB_SendZlp(pUdp);\r
607 break;\r
608 case STD_SET_FEATURE_ENDPOINT:\r
609 wIndex &= 0x0F;\r
f194e429 610 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 611 pUdp->UDP_CSR[wIndex] = 0;\r
612 AT91F_USB_SendZlp(pUdp);\r
613 }\r
614 else\r
615 AT91F_USB_SendStall(pUdp);\r
616 break;\r
617 case STD_CLEAR_FEATURE_ZERO:\r
618 AT91F_USB_SendStall(pUdp);\r
619 break;\r
620 case STD_CLEAR_FEATURE_INTERFACE:\r
621 AT91F_USB_SendZlp(pUdp);\r
622 break;\r
623 case STD_CLEAR_FEATURE_ENDPOINT:\r
624 wIndex &= 0x0F;\r
f194e429 625 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
626 if (wIndex == AT91C_EP_OUT)\r
627 pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
628 else if (wIndex == AT91C_EP_IN)\r
629 pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
630 else if (wIndex == AT91C_EP_NOTIFY)\r
631 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);\r
5bcc76c4 632 AT91F_USB_SendZlp(pUdp);\r
633 }\r
634 else\r
635 AT91F_USB_SendStall(pUdp);\r
636 break;\r
637\r
638 // handle CDC class requests\r
639 case SET_LINE_CODING:\r
3a89d04c 640 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0) );\r
641 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 642 AT91F_USB_SendZlp(pUdp);\r
643 break;\r
644 case GET_LINE_CODING:\r
645 AT91F_USB_SendData(pUdp, (char *) &line, MIN(sizeof(line), wLength));\r
646 break;\r
647 case SET_CONTROL_LINE_STATE:\r
648 btConnection = wValue;\r
649 AT91F_USB_SendZlp(pUdp);\r
650 break;\r
651 default:\r
652 AT91F_USB_SendStall(pUdp);\r
653 break;\r
654 }\r
655}\r
Impressum, Datenschutz