]> git.zerfleddert.de Git - proxmark3-svn/blame - common/usb_cdc.c
Merge branch 'master' into fix_iclass_sim
[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
f3803172 80 0x80, // CbmAttributes (Bus Powered)\r
81 0x4B, // CMaxPower (150mA max current drawn from bus)\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
f3dc6d59 186 20, // Length\r
1f42ccdd 187 0x03, // Type is string\r
f3dc6d59
P
188 'p', 0x00,\r
189 'r', 0x00,\r
190 'o', 0x00,\r
191 'x', 0x00,\r
192 'm', 0x00,\r
193 'a', 0x00,\r
194 'r', 0x00,\r
195 'k', 0x00,\r
196 '3', 0x00\r
1f42ccdd 197};\r
5bcc76c4 198\r
1f42ccdd 199const char* getStringDescriptor(uint8_t idx)\r
200{\r
05b6b117
MF
201 switch (idx) {\r
202 case STR_LANGUAGE_CODES:\r
203 return StrDescLanguageCodes;\r
204 case STR_MANUFACTURER:\r
205 return StrDescManufacturer;\r
206 case STR_PRODUCT:\r
207 return StrDescProduct;\r
208 default:\r
209 return NULL;\r
1f42ccdd 210 }\r
211}\r
5bcc76c4 212\r
3a89d04c 213// Bitmap for all status bits in CSR which must be written as 1 to cause no effect\r
214#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \\r
215 |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \\r
216 |AT91C_UDP_TXCOMP\r
217\r
218// Clear flags in the UDP_CSR register\r
219#define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \\r
220 volatile unsigned int reg; \\r
221 reg = pUdp->UDP_CSR[(endpoint)]; \\r
222 reg |= REG_NO_EFFECT_1_ALL; \\r
223 reg &= ~(flags); \\r
224 pUdp->UDP_CSR[(endpoint)] = reg; \\r
225} \r
226\r
227// Set flags in the UDP_CSR register\r
228#define UDP_SET_EP_FLAGS(endpoint, flags) { \\r
229 volatile unsigned int reg; \\r
230 reg = pUdp->UDP_CSR[(endpoint)]; \\r
231 reg |= REG_NO_EFFECT_1_ALL; \\r
232 reg |= (flags); \\r
233 pUdp->UDP_CSR[(endpoint)] = reg; \\r
234}\r
235\r
236/* USB standard request codes */\r
5bcc76c4 237#define STD_GET_STATUS_ZERO 0x0080\r
238#define STD_GET_STATUS_INTERFACE 0x0081\r
239#define STD_GET_STATUS_ENDPOINT 0x0082\r
240\r
241#define STD_CLEAR_FEATURE_ZERO 0x0100\r
242#define STD_CLEAR_FEATURE_INTERFACE 0x0101\r
243#define STD_CLEAR_FEATURE_ENDPOINT 0x0102\r
244\r
245#define STD_SET_FEATURE_ZERO 0x0300\r
246#define STD_SET_FEATURE_INTERFACE 0x0301\r
247#define STD_SET_FEATURE_ENDPOINT 0x0302\r
248\r
249#define STD_SET_ADDRESS 0x0500\r
250#define STD_GET_DESCRIPTOR 0x0680\r
251#define STD_SET_DESCRIPTOR 0x0700\r
252#define STD_GET_CONFIGURATION 0x0880\r
253#define STD_SET_CONFIGURATION 0x0900\r
254#define STD_GET_INTERFACE 0x0A81\r
255#define STD_SET_INTERFACE 0x0B01\r
256#define STD_SYNCH_FRAME 0x0C82\r
257\r
258/* CDC Class Specific Request Code */\r
259#define GET_LINE_CODING 0x21A1\r
260#define SET_LINE_CODING 0x2021\r
261#define SET_CONTROL_LINE_STATE 0x2221\r
262\r
263typedef struct {\r
264 unsigned int dwDTERRate;\r
265 char bCharFormat;\r
266 char bParityType;\r
267 char bDataBits;\r
268} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;\r
269\r
270AT91S_CDC_LINE_CODING line = {\r
271 115200, // baudrate\r
272 0, // 1 Stop Bit\r
273 0, // None Parity\r
274 8}; // 8 Data bits\r
275\r
f194e429 276\r
5bcc76c4 277void AT91F_CDC_Enumerate();\r
278\r
279AT91PS_UDP pUdp = AT91C_BASE_UDP;\r
280byte_t btConfiguration = 0;\r
281byte_t btConnection = 0;\r
282byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;\r
283\r
f194e429 284\r
6e82300d 285//*----------------------------------------------------------------------------\r
79a73ab2 286//* \fn usb_disable\r
6e82300d 287//* \brief This function deactivates the USB device\r
288//*----------------------------------------------------------------------------\r
289void usb_disable() {\r
f194e429 290 // Disconnect the USB device\r
291 AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;\r
292\r
293 // Clear all lingering interrupts\r
294 if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {\r
295 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
296 }\r
6e82300d 297}\r
298\r
f194e429 299\r
5bcc76c4 300//*----------------------------------------------------------------------------\r
79a73ab2 301//* \fn usb_enable\r
5bcc76c4 302//* \brief This function Activates the USB device\r
303//*----------------------------------------------------------------------------\r
6e82300d 304void usb_enable() {\r
f194e429 305 // Set the PLL USB Divider\r
306 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;\r
307\r
308 // Specific Chip USB Initialisation\r
309 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock\r
310 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
311 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
312\r
313 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO\r
314 // Set in PIO mode and Configure in Output\r
315 AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode\r
79a73ab2 316 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output\r
f194e429 317\r
318 // Clear for set the Pullup resistor\r
79a73ab2 319 AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;\r
6e82300d 320\r
f194e429 321 // Disconnect and reconnect USB controller for 100ms\r
322 usb_disable();\r
323\r
324 // Wait for a short while\r
325 for (volatile size_t i=0; i<0x100000; i++);\r
326\r
327 // Reconnect USB reconnect\r
328 AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;\r
329 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;\r
5bcc76c4 330}\r
331\r
f194e429 332\r
5bcc76c4 333//*----------------------------------------------------------------------------\r
79a73ab2 334//* \fn usb_check\r
5bcc76c4 335//* \brief Test if the device is configured and handle enumeration\r
336//*----------------------------------------------------------------------------\r
6e82300d 337bool usb_check() {\r
5bcc76c4 338 AT91_REG isr = pUdp->UDP_ISR;\r
339\r
340 if (isr & AT91C_UDP_ENDBUSRES) {\r
341 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
342 // reset all endpoints\r
343 pUdp->UDP_RSTEP = (unsigned int)-1;\r
344 pUdp->UDP_RSTEP = 0;\r
345 // Enable the function\r
346 pUdp->UDP_FADDR = AT91C_UDP_FEN;\r
347 // Configure endpoint 0\r
3a89d04c 348 pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);\r
f194e429 349 } else if (isr & AT91C_UDP_EPINT0) {\r
5bcc76c4 350 pUdp->UDP_ICR = AT91C_UDP_EPINT0;\r
351 AT91F_CDC_Enumerate();\r
352 }\r
353 return (btConfiguration) ? true : false;\r
354}\r
355\r
356\r
357bool usb_poll()\r
358{\r
f194e429 359 if (!usb_check()) return false;\r
360 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
5bcc76c4 361}\r
362\r
f194e429 363\r
83f3f8ac
MHS
364/**\r
365 In github PR #129, some users appears to get a false positive from\r
366 usb_poll, which returns true, but the usb_read operation\r
367 still returns 0.\r
368 This check is basically the same as above, but also checks\r
369 that the length available to read is non-zero, thus hopefully fixes the\r
370 bug.\r
371**/\r
372bool usb_poll_validate_length()\r
373{\r
83f3f8ac
MHS
374 if (!usb_check()) return false;\r
375 if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;\r
376 return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;\r
377}\r
378\r
5bcc76c4 379//*----------------------------------------------------------------------------\r
79a73ab2 380//* \fn usb_read\r
5bcc76c4 381//* \brief Read available data from Endpoint OUT\r
382//*----------------------------------------------------------------------------\r
6e82300d 383uint32_t usb_read(byte_t* data, size_t len) {\r
d2deaf7b 384 byte_t bank = btReceiveBank;\r
5bcc76c4 385 uint32_t packetSize, nbBytesRcv = 0;\r
d2deaf7b 386 uint32_t time_out = 0;\r
5bcc76c4 387 \r
23b598ee 388 while (len) {\r
5bcc76c4 389 if (!usb_check()) break;\r
390\r
391 if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) {\r
392 packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len);\r
d2deaf7b 393 len -= packetSize;\r
5bcc76c4 394 while(packetSize--)\r
395 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
3a89d04c 396 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
23b598ee 397 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
5bcc76c4 398 bank = AT91C_UDP_RX_DATA_BK1;\r
d2deaf7b 399 } else {\r
5bcc76c4 400 bank = AT91C_UDP_RX_DATA_BK0;\r
d2deaf7b 401 }\r
5bcc76c4 402 }\r
d2deaf7b 403 if (time_out++ == 0x1fff) break;\r
5bcc76c4 404 }\r
405\r
406 btReceiveBank = bank;\r
407 return nbBytesRcv;\r
408}\r
409\r
f194e429 410\r
5bcc76c4 411//*----------------------------------------------------------------------------\r
79a73ab2 412//* \fn usb_write\r
5bcc76c4 413//* \brief Send through endpoint 2\r
414//*----------------------------------------------------------------------------\r
6e82300d 415uint32_t usb_write(const byte_t* data, const size_t len) {\r
f194e429 416 size_t length = len;\r
5bcc76c4 417 uint32_t cpt = 0;\r
418\r
f194e429 419 if (!length) return 0;\r
420 if (!usb_check()) return 0;\r
421\r
5bcc76c4 422 // Send the first packet\r
f194e429 423 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 424 length -= cpt;\r
f194e429 425 while (cpt--) {\r
426 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
427 }\r
3a89d04c 428 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 429\r
430 while (length) {\r
f194e429 431 // Fill the next bank\r
432 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 433 length -= cpt;\r
f194e429 434 while (cpt--) {\r
435 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
436 }\r
437 // Wait for the previous bank to be sent\r
5bcc76c4 438 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
439 if (!usb_check()) return length;\r
f194e429 440 }\r
3a89d04c 441 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 442 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
3a89d04c 443 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 444 }\r
f194e429 445\r
5bcc76c4 446 // Wait for the end of transfer\r
447 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
448 if (!usb_check()) return length;\r
f194e429 449 }\r
450\r
3a89d04c 451 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 452 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
453\r
454 return length;\r
455}\r
456\r
f194e429 457\r
5bcc76c4 458//*----------------------------------------------------------------------------\r
459//* \fn AT91F_USB_SendData\r
460//* \brief Send Data through the control endpoint\r
461//*----------------------------------------------------------------------------\r
5ee70129 462unsigned int csrTab[100] = {0x00};\r
5bcc76c4 463unsigned char csrIdx = 0;\r
464\r
6e82300d 465static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
5bcc76c4 466 uint32_t cpt = 0;\r
467 AT91_REG csr;\r
468\r
469 do {\r
470 cpt = MIN(length, 8);\r
471 length -= cpt;\r
472\r
473 while (cpt--)\r
474 pUdp->UDP_FDR[0] = *pData++;\r
475\r
3a89d04c 476 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
477 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
478 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 479 }\r
480\r
3a89d04c 481 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 482 do {\r
3a89d04c 483 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
5bcc76c4 484\r
485 // Data IN stage has been stopped by a status OUT\r
486 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
3a89d04c 487 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 488 return;\r
489 }\r
490 } while ( !(csr & AT91C_UDP_TXCOMP) );\r
491\r
492 } while (length);\r
493\r
3a89d04c 494 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
495 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
496 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 497 }\r
498}\r
499\r
f194e429 500\r
5bcc76c4 501//*----------------------------------------------------------------------------\r
502//* \fn AT91F_USB_SendZlp\r
503//* \brief Send zero length packet through the control endpoint\r
504//*----------------------------------------------------------------------------\r
6e82300d 505void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
3a89d04c 506 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
507 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) );\r
508 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
509 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 510}\r
511\r
f194e429 512\r
5bcc76c4 513//*----------------------------------------------------------------------------\r
514//* \fn AT91F_USB_SendStall\r
515//* \brief Stall the control endpoint\r
516//*----------------------------------------------------------------------------\r
6e82300d 517void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
3a89d04c 518 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
519 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR) );\r
520 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
521 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));\r
5bcc76c4 522}\r
523\r
f194e429 524\r
5bcc76c4 525//*----------------------------------------------------------------------------\r
526//* \fn AT91F_CDC_Enumerate\r
527//* \brief This function is a callback invoked when a SETUP packet is received\r
528//*----------------------------------------------------------------------------\r
6e82300d 529void AT91F_CDC_Enumerate() {\r
5bcc76c4 530 byte_t bmRequestType, bRequest;\r
531 uint16_t wValue, wIndex, wLength, wStatus;\r
532\r
3a89d04c 533 if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) )\r
5bcc76c4 534 return;\r
535\r
f194e429 536 bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
537 bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
538 wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
539 wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
540 wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
541 wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
542 wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
543 wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
5bcc76c4 544\r
f194e429 545 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
3a89d04c 546 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
547 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) );\r
5bcc76c4 548 }\r
3a89d04c 549 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
550 while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) );\r
5bcc76c4 551\r
552 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
553 switch ((bRequest << 8) | bmRequestType) {\r
554 case STD_GET_DESCRIPTOR:\r
555 if (wValue == 0x100) // Return Device Descriptor\r
556 AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
557 else if (wValue == 0x200) // Return Configuration Descriptor\r
558 AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
1f42ccdd 559 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
560 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
561 if (strDescriptor != NULL) {\r
562 AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength));\r
563 } else {\r
13c25f89 564 AT91F_USB_SendStall(pUdp);\r
1f42ccdd 565 }\r
566 }\r
5bcc76c4 567 else\r
568 AT91F_USB_SendStall(pUdp);\r
569 break;\r
570 case STD_SET_ADDRESS:\r
571 AT91F_USB_SendZlp(pUdp);\r
572 pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
573 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
574 break;\r
575 case STD_SET_CONFIGURATION:\r
576 btConfiguration = wValue;\r
577 AT91F_USB_SendZlp(pUdp);\r
578 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
f194e429 579 pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
580 pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
581 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
5bcc76c4 582 break;\r
583 case STD_GET_CONFIGURATION:\r
584 AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));\r
585 break;\r
586 case STD_GET_STATUS_ZERO:\r
f194e429 587 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
5bcc76c4 588 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
589 break;\r
590 case STD_GET_STATUS_INTERFACE:\r
f194e429 591 wStatus = 0; // reserved for future use\r
5bcc76c4 592 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
593 break;\r
594 case STD_GET_STATUS_ENDPOINT:\r
595 wStatus = 0;\r
596 wIndex &= 0x0F;\r
f194e429 597 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 598 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
599 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
600 }\r
f194e429 601 else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
5bcc76c4 602 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
603 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
604 }\r
605 else\r
606 AT91F_USB_SendStall(pUdp);\r
607 break;\r
608 case STD_SET_FEATURE_ZERO:\r
609 AT91F_USB_SendStall(pUdp);\r
610 break;\r
611 case STD_SET_FEATURE_INTERFACE:\r
612 AT91F_USB_SendZlp(pUdp);\r
613 break;\r
614 case STD_SET_FEATURE_ENDPOINT:\r
615 wIndex &= 0x0F;\r
f194e429 616 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 617 pUdp->UDP_CSR[wIndex] = 0;\r
618 AT91F_USB_SendZlp(pUdp);\r
619 }\r
620 else\r
621 AT91F_USB_SendStall(pUdp);\r
622 break;\r
623 case STD_CLEAR_FEATURE_ZERO:\r
624 AT91F_USB_SendStall(pUdp);\r
625 break;\r
626 case STD_CLEAR_FEATURE_INTERFACE:\r
627 AT91F_USB_SendZlp(pUdp);\r
628 break;\r
629 case STD_CLEAR_FEATURE_ENDPOINT:\r
630 wIndex &= 0x0F;\r
f194e429 631 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
632 if (wIndex == AT91C_EP_OUT)\r
633 pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
634 else if (wIndex == AT91C_EP_IN)\r
635 pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
636 else if (wIndex == AT91C_EP_NOTIFY)\r
637 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);\r
5bcc76c4 638 AT91F_USB_SendZlp(pUdp);\r
639 }\r
640 else\r
641 AT91F_USB_SendStall(pUdp);\r
642 break;\r
643\r
644 // handle CDC class requests\r
645 case SET_LINE_CODING:\r
3a89d04c 646 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0) );\r
647 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 648 AT91F_USB_SendZlp(pUdp);\r
649 break;\r
650 case GET_LINE_CODING:\r
651 AT91F_USB_SendData(pUdp, (char *) &line, MIN(sizeof(line), wLength));\r
652 break;\r
653 case SET_CONTROL_LINE_STATE:\r
654 btConnection = wValue;\r
655 AT91F_USB_SendZlp(pUdp);\r
656 break;\r
657 default:\r
658 AT91F_USB_SendStall(pUdp);\r
659 break;\r
660 }\r
661}\r
Impressum, Datenschutz