]> git.zerfleddert.de Git - proxmark3-svn/blame - common/usb_cdc.c
modify USB communications
[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
72622d64 36\r
37#include <stddef.h>\r
38#include <stdint.h>\r
39#include <stdbool.h>\r
40\r
41#include "common.h"\r
1f42ccdd 42#include "at91sam7s512.h"\r
79a73ab2 43#include "config_gpio.h"\r
5bcc76c4 44\r
3a89d04c 45#define AT91C_EP_CONTROL 0\r
5bcc76c4 46#define AT91C_EP_OUT 1\r
5bcc76c4 47#define AT91C_EP_IN 2\r
f194e429 48#define AT91C_EP_NOTIFY 3\r
49#define AT91C_EP_OUT_SIZE 0x40\r
50#define AT91C_EP_IN_SIZE 0x40\r
5bcc76c4 51\r
05b6b117
MF
52// Language must always be 0.\r
53#define STR_LANGUAGE_CODES 0x00\r
54#define STR_MANUFACTURER 0x01\r
55#define STR_PRODUCT 0x02\r
56\r
72622d64 57\r
1f42ccdd 58static const char devDescriptor[] = {\r
5bcc76c4 59 /* Device descriptor */\r
60 0x12, // bLength\r
61 0x01, // bDescriptorType\r
1f42ccdd 62 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)\r
f194e429 63 0x02, // bDeviceClass: (Communication Device Class)\r
64 0x00, // bDeviceSubclass: (unused at this time)\r
65 0x00, // bDeviceProtocol: (unused at this time)\r
5bcc76c4 66 0x08, // bMaxPacketSize0\r
1f42ccdd 67 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)\r
68 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)\r
5bcc76c4 69 0x01,0x00, // Device release number (0001)\r
05b6b117
MF
70 STR_MANUFACTURER, // iManufacturer\r
71 STR_PRODUCT, // iProduct\r
1f42ccdd 72 0x00, // iSerialNumber\r
5bcc76c4 73 0x01 // bNumConfigs\r
74};\r
75\r
72622d64 76\r
1f42ccdd 77static const char cfgDescriptor[] = {\r
5bcc76c4 78 /* ============== CONFIGURATION 1 =========== */\r
79 /* Configuration 1 descriptor */\r
80 0x09, // CbLength\r
81 0x02, // CbDescriptorType\r
82 0x43, // CwTotalLength 2 EP + Control\r
83 0x00,\r
84 0x02, // CbNumInterfaces\r
85 0x01, // CbConfigurationValue\r
86 0x00, // CiConfiguration\r
f3803172 87 0x80, // CbmAttributes (Bus Powered)\r
88 0x4B, // CMaxPower (150mA max current drawn from bus)\r
5bcc76c4 89\r
f194e429 90 /* Interface 0 Descriptor: Communication Class Interface */\r
5bcc76c4 91 0x09, // bLength\r
92 0x04, // bDescriptorType\r
93 0x00, // bInterfaceNumber\r
94 0x00, // bAlternateSetting\r
95 0x01, // bNumEndpoints\r
f194e429 96 0x02, // bInterfaceClass: Communication Interface Class\r
97 0x02, // bInterfaceSubclass: Abstract Control Model\r
98 0x01, // bInterfaceProtocol: Common AT Commands, V.25ter\r
5bcc76c4 99 0x00, // iInterface\r
100\r
101 /* Header Functional Descriptor */\r
102 0x05, // bFunction Length\r
f194e429 103 0x24, // bDescriptor type: CS_INTERFACE\r
104 0x00, // bDescriptor subtype: Header Functional Descriptor\r
5bcc76c4 105 0x10, // bcdCDC:1.1\r
106 0x01,\r
107\r
108 /* ACM Functional Descriptor */\r
109 0x04, // bFunctionLength\r
f194e429 110 0x24, // bDescriptor Type: CS_INTERFACE\r
111 0x02, // bDescriptor Subtype: Abstract Control Management Functional Descriptor\r
112 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 113\r
114 /* Union Functional Descriptor */\r
115 0x05, // bFunctionLength\r
f194e429 116 0x24, // bDescriptorType: CS_INTERFACE\r
117 0x06, // bDescriptor Subtype: Union Functional Descriptor\r
118 0x00, // bMasterInterface: Communication Class Interface\r
119 0x01, // bSlaveInterface0: Data Class Interface\r
5bcc76c4 120\r
121 /* Call Management Functional Descriptor */\r
122 0x05, // bFunctionLength\r
f194e429 123 0x24, // bDescriptor Type: CS_INTERFACE\r
124 0x01, // bDescriptor Subtype: Call Management Functional Descriptor\r
125 0x00, // bmCapabilities: Device sends/receives call management information only over the Communication Class interface. Device does not handle call management itself\r
126 0x01, // bDataInterface: Data Class Interface 1\r
5bcc76c4 127\r
128 /* Endpoint 1 descriptor */\r
129 0x07, // bLength\r
130 0x05, // bDescriptorType\r
f194e429 131 0x83, // bEndpointAddress: Endpoint 03 - IN\r
132 0x03, // bmAttributes: INT\r
133 0x08, // wMaxPacketSize: 8\r
5bcc76c4 134 0x00,\r
135 0xFF, // bInterval\r
136\r
f194e429 137 /* Interface 1 Descriptor: Data Class Interface */\r
5bcc76c4 138 0x09, // bLength\r
139 0x04, // bDescriptorType\r
140 0x01, // bInterfaceNumber\r
141 0x00, // bAlternateSetting\r
142 0x02, // bNumEndpoints\r
f194e429 143 0x0A, // bInterfaceClass: Data Interface Class\r
144 0x00, // bInterfaceSubclass: not used\r
145 0x00, // bInterfaceProtocol: No class specific protocol required)\r
5bcc76c4 146 0x00, // iInterface\r
147\r
5bcc76c4 148 /* Endpoint 1 descriptor */\r
149 0x07, // bLength\r
150 0x05, // bDescriptorType\r
f194e429 151 0x01, // bEndpointAddress: Endpoint 01 - OUT\r
152 0x02, // bmAttributes: BULK\r
153 AT91C_EP_OUT_SIZE, // wMaxPacketSize\r
5bcc76c4 154 0x00,\r
155 0x00, // bInterval\r
156\r
157 /* Endpoint 2 descriptor */\r
158 0x07, // bLength\r
159 0x05, // bDescriptorType\r
f194e429 160 0x82, // bEndpointAddress: Endpoint 02 - IN\r
161 0x02, // bmAttributes: BULK\r
5bcc76c4 162 AT91C_EP_IN_SIZE, // wMaxPacketSize\r
163 0x00,\r
164 0x00 // bInterval\r
165};\r
166\r
72622d64 167\r
1f42ccdd 168static const char StrDescLanguageCodes[] = {\r
72622d64 169 4, // Length\r
170 0x03, // Type is string\r
171 0x09, 0x04 // supported language Code 0 = 0x0409 (English)\r
1f42ccdd 172};\r
05b6b117 173\r
72622d64 174\r
05b6b117
MF
175// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the\r
176// manufacturer string "proxmark.org". Don't change this.\r
1f42ccdd 177static const char StrDescManufacturer[] = {\r
72622d64 178 26, // Length\r
179 0x03, // Type is string\r
180 'p', 0x00,\r
181 'r', 0x00,\r
182 'o', 0x00,\r
183 'x', 0x00,\r
184 'm', 0x00,\r
185 'a', 0x00,\r
186 'r', 0x00,\r
187 'k', 0x00,\r
188 '.', 0x00,\r
189 'o', 0x00,\r
190 'r', 0x00,\r
191 'g', 0x00\r
1f42ccdd 192};\r
193\r
72622d64 194\r
1f42ccdd 195static const char StrDescProduct[] = {\r
72622d64 196 20, // Length\r
197 0x03, // Type is string\r
198 'p', 0x00,\r
199 'r', 0x00,\r
200 'o', 0x00,\r
201 'x', 0x00,\r
202 'm', 0x00,\r
203 'a', 0x00,\r
204 'r', 0x00,\r
205 'k', 0x00,\r
206 '3', 0x00\r
1f42ccdd 207};\r
5bcc76c4 208\r
72622d64 209\r
867e10a5 210static const char* getStringDescriptor(uint8_t idx) {\r
05b6b117
MF
211 switch (idx) {\r
212 case STR_LANGUAGE_CODES:\r
213 return StrDescLanguageCodes;\r
214 case STR_MANUFACTURER:\r
215 return StrDescManufacturer;\r
216 case STR_PRODUCT:\r
217 return StrDescProduct;\r
218 default:\r
219 return NULL;\r
1f42ccdd 220 }\r
221}\r
5bcc76c4 222\r
72622d64 223\r
3a89d04c 224// Bitmap for all status bits in CSR which must be written as 1 to cause no effect\r
225#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \\r
72622d64 226 |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \\r
227 |AT91C_UDP_TXCOMP\r
228\r
3a89d04c 229\r
230// Clear flags in the UDP_CSR register\r
231#define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \\r
232 volatile unsigned int reg; \\r
233 reg = pUdp->UDP_CSR[(endpoint)]; \\r
234 reg |= REG_NO_EFFECT_1_ALL; \\r
235 reg &= ~(flags); \\r
236 pUdp->UDP_CSR[(endpoint)] = reg; \\r
72622d64 237}\r
238\r
3a89d04c 239\r
240// Set flags in the UDP_CSR register\r
241#define UDP_SET_EP_FLAGS(endpoint, flags) { \\r
242 volatile unsigned int reg; \\r
243 reg = pUdp->UDP_CSR[(endpoint)]; \\r
244 reg |= REG_NO_EFFECT_1_ALL; \\r
245 reg |= (flags); \\r
246 pUdp->UDP_CSR[(endpoint)] = reg; \\r
247}\r
248\r
72622d64 249\r
3a89d04c 250/* USB standard request codes */\r
5bcc76c4 251#define STD_GET_STATUS_ZERO 0x0080\r
252#define STD_GET_STATUS_INTERFACE 0x0081\r
253#define STD_GET_STATUS_ENDPOINT 0x0082\r
254\r
255#define STD_CLEAR_FEATURE_ZERO 0x0100\r
256#define STD_CLEAR_FEATURE_INTERFACE 0x0101\r
257#define STD_CLEAR_FEATURE_ENDPOINT 0x0102\r
258\r
259#define STD_SET_FEATURE_ZERO 0x0300\r
260#define STD_SET_FEATURE_INTERFACE 0x0301\r
261#define STD_SET_FEATURE_ENDPOINT 0x0302\r
262\r
263#define STD_SET_ADDRESS 0x0500\r
264#define STD_GET_DESCRIPTOR 0x0680\r
265#define STD_SET_DESCRIPTOR 0x0700\r
266#define STD_GET_CONFIGURATION 0x0880\r
267#define STD_SET_CONFIGURATION 0x0900\r
268#define STD_GET_INTERFACE 0x0A81\r
269#define STD_SET_INTERFACE 0x0B01\r
270#define STD_SYNCH_FRAME 0x0C82\r
271\r
272/* CDC Class Specific Request Code */\r
273#define GET_LINE_CODING 0x21A1\r
274#define SET_LINE_CODING 0x2021\r
275#define SET_CONTROL_LINE_STATE 0x2221\r
276\r
72622d64 277\r
5bcc76c4 278typedef struct {\r
279 unsigned int dwDTERRate;\r
280 char bCharFormat;\r
281 char bParityType;\r
282 char bDataBits;\r
283} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;\r
284\r
72622d64 285\r
5bcc76c4 286AT91S_CDC_LINE_CODING line = {\r
287 115200, // baudrate\r
288 0, // 1 Stop Bit\r
289 0, // None Parity\r
290 8}; // 8 Data bits\r
291\r
f194e429 292\r
867e10a5 293static void AT91F_CDC_Enumerate();\r
5bcc76c4 294\r
295AT91PS_UDP pUdp = AT91C_BASE_UDP;\r
72622d64 296uint8_t btConfiguration = 0;\r
297uint8_t btConnection = 0;\r
298uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;\r
5bcc76c4 299\r
f194e429 300\r
6e82300d 301//*----------------------------------------------------------------------------\r
79a73ab2 302//* \fn usb_disable\r
6e82300d 303//* \brief This function deactivates the USB device\r
304//*----------------------------------------------------------------------------\r
305void usb_disable() {\r
f194e429 306 // Disconnect the USB device\r
307 AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;\r
308\r
309 // Clear all lingering interrupts\r
72622d64 310 if (pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {\r
f194e429 311 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
312 }\r
6e82300d 313}\r
314\r
f194e429 315\r
5bcc76c4 316//*----------------------------------------------------------------------------\r
79a73ab2 317//* \fn usb_enable\r
5bcc76c4 318//* \brief This function Activates the USB device\r
319//*----------------------------------------------------------------------------\r
6e82300d 320void usb_enable() {\r
f194e429 321 // Set the PLL USB Divider\r
322 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;\r
323\r
324 // Specific Chip USB Initialisation\r
325 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock\r
326 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
327 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
328\r
329 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO\r
330 // Set in PIO mode and Configure in Output\r
331 AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode\r
79a73ab2 332 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output\r
f194e429 333\r
334 // Clear for set the Pullup resistor\r
79a73ab2 335 AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;\r
6e82300d 336\r
f194e429 337 // Disconnect and reconnect USB controller for 100ms\r
338 usb_disable();\r
339\r
340 // Wait for a short while\r
72622d64 341 for (volatile size_t i = 0; i < 0x100000; i++);\r
f194e429 342\r
343 // Reconnect USB reconnect\r
344 AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;\r
345 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;\r
5bcc76c4 346}\r
347\r
f194e429 348\r
5bcc76c4 349//*----------------------------------------------------------------------------\r
79a73ab2 350//* \fn usb_check\r
5bcc76c4 351//* \brief Test if the device is configured and handle enumeration\r
352//*----------------------------------------------------------------------------\r
867e10a5 353static bool usb_check() {\r
5bcc76c4 354 AT91_REG isr = pUdp->UDP_ISR;\r
355\r
356 if (isr & AT91C_UDP_ENDBUSRES) {\r
357 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
358 // reset all endpoints\r
359 pUdp->UDP_RSTEP = (unsigned int)-1;\r
360 pUdp->UDP_RSTEP = 0;\r
361 // Enable the function\r
362 pUdp->UDP_FADDR = AT91C_UDP_FEN;\r
363 // Configure endpoint 0\r
3a89d04c 364 pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);\r
f194e429 365 } else if (isr & AT91C_UDP_EPINT0) {\r
5bcc76c4 366 pUdp->UDP_ICR = AT91C_UDP_EPINT0;\r
367 AT91F_CDC_Enumerate();\r
368 }\r
369 return (btConfiguration) ? true : false;\r
370}\r
371\r
372\r
72622d64 373bool usb_poll() {\r
f194e429 374 if (!usb_check()) return false;\r
375 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
5bcc76c4 376}\r
377\r
f194e429 378\r
83f3f8ac
MHS
379/**\r
380 In github PR #129, some users appears to get a false positive from\r
381 usb_poll, which returns true, but the usb_read operation\r
382 still returns 0.\r
383 This check is basically the same as above, but also checks\r
384 that the length available to read is non-zero, thus hopefully fixes the\r
385 bug.\r
386**/\r
72622d64 387bool usb_poll_validate_length() {\r
83f3f8ac
MHS
388 if (!usb_check()) return false;\r
389 if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;\r
390 return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;\r
391}\r
392\r
72622d64 393\r
5bcc76c4 394//*----------------------------------------------------------------------------\r
79a73ab2 395//* \fn usb_read\r
5bcc76c4 396//* \brief Read available data from Endpoint OUT\r
397//*----------------------------------------------------------------------------\r
867e10a5 398static uint32_t usb_read(uint8_t* data, size_t len) {\r
72622d64 399 uint8_t bank = btReceiveBank;\r
5bcc76c4 400 uint32_t packetSize, nbBytesRcv = 0;\r
d2deaf7b 401 uint32_t time_out = 0;\r
72622d64 402\r
23b598ee 403 while (len) {\r
5bcc76c4 404 if (!usb_check()) break;\r
405\r
406 if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) {\r
407 packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len);\r
d2deaf7b 408 len -= packetSize;\r
72622d64 409 while (packetSize--)\r
5bcc76c4 410 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
3a89d04c 411 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
23b598ee 412 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
5bcc76c4 413 bank = AT91C_UDP_RX_DATA_BK1;\r
d2deaf7b 414 } else {\r
5bcc76c4 415 bank = AT91C_UDP_RX_DATA_BK0;\r
d2deaf7b 416 }\r
5bcc76c4 417 }\r
d2deaf7b 418 if (time_out++ == 0x1fff) break;\r
5bcc76c4 419 }\r
420\r
421 btReceiveBank = bank;\r
422 return nbBytesRcv;\r
423}\r
424\r
f194e429 425\r
5bcc76c4 426//*----------------------------------------------------------------------------\r
79a73ab2 427//* \fn usb_write\r
5bcc76c4 428//* \brief Send through endpoint 2\r
429//*----------------------------------------------------------------------------\r
867e10a5 430static uint32_t usb_write(const uint8_t* data, const size_t len) {\r
f194e429 431 size_t length = len;\r
5bcc76c4 432 uint32_t cpt = 0;\r
433\r
f194e429 434 if (!length) return 0;\r
435 if (!usb_check()) return 0;\r
436\r
5bcc76c4 437 // Send the first packet\r
f194e429 438 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 439 length -= cpt;\r
f194e429 440 while (cpt--) {\r
441 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
442 }\r
3a89d04c 443 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 444\r
445 while (length) {\r
f194e429 446 // Fill the next bank\r
447 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 448 length -= cpt;\r
f194e429 449 while (cpt--) {\r
450 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
451 }\r
452 // Wait for the previous bank to be sent\r
5bcc76c4 453 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
454 if (!usb_check()) return length;\r
f194e429 455 }\r
3a89d04c 456 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
72622d64 457 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)\r
458 /* wait */;\r
3a89d04c 459 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 460 }\r
f194e429 461\r
5bcc76c4 462 // Wait for the end of transfer\r
463 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
464 if (!usb_check()) return length;\r
f194e429 465 }\r
466\r
3a89d04c 467 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
72622d64 468 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)\r
469 /* wait */;\r
5bcc76c4 470\r
471 return length;\r
472}\r
473\r
f194e429 474\r
5bcc76c4 475//*----------------------------------------------------------------------------\r
476//* \fn AT91F_USB_SendData\r
477//* \brief Send Data through the control endpoint\r
478//*----------------------------------------------------------------------------\r
6e82300d 479static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
5bcc76c4 480 uint32_t cpt = 0;\r
481 AT91_REG csr;\r
482\r
483 do {\r
484 cpt = MIN(length, 8);\r
485 length -= cpt;\r
486\r
487 while (cpt--)\r
488 pUdp->UDP_FDR[0] = *pData++;\r
489\r
3a89d04c 490 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
491 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
72622d64 492 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
493 /* wait */;\r
5bcc76c4 494 }\r
495\r
3a89d04c 496 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 497 do {\r
3a89d04c 498 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
5bcc76c4 499\r
500 // Data IN stage has been stopped by a status OUT\r
501 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
3a89d04c 502 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 503 return;\r
504 }\r
72622d64 505 } while (!(csr & AT91C_UDP_TXCOMP));\r
5bcc76c4 506\r
507 } while (length);\r
508\r
3a89d04c 509 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
510 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
72622d64 511 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
512 /* wait */;\r
5bcc76c4 513 }\r
514}\r
515\r
f194e429 516\r
5bcc76c4 517//*----------------------------------------------------------------------------\r
518//* \fn AT91F_USB_SendZlp\r
519//* \brief Send zero length packet through the control endpoint\r
520//*----------------------------------------------------------------------------\r
867e10a5 521static void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
3a89d04c 522 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
72622d64 523 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP))\r
524 /* wait */;\r
3a89d04c 525 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
72622d64 526 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
527 /* wait */;\r
5bcc76c4 528}\r
529\r
f194e429 530\r
5bcc76c4 531//*----------------------------------------------------------------------------\r
532//* \fn AT91F_USB_SendStall\r
533//* \brief Stall the control endpoint\r
534//*----------------------------------------------------------------------------\r
867e10a5 535static void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
3a89d04c 536 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
72622d64 537 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR))\r
538 /* wait */;\r
3a89d04c 539 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
72622d64 540 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR))\r
541 /* wait */;\r
5bcc76c4 542}\r
543\r
f194e429 544\r
5bcc76c4 545//*----------------------------------------------------------------------------\r
546//* \fn AT91F_CDC_Enumerate\r
547//* \brief This function is a callback invoked when a SETUP packet is received\r
548//*----------------------------------------------------------------------------\r
867e10a5 549static void AT91F_CDC_Enumerate() {\r
72622d64 550 uint8_t bmRequestType, bRequest;\r
5bcc76c4 551 uint16_t wValue, wIndex, wLength, wStatus;\r
552\r
72622d64 553 if (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP))\r
5bcc76c4 554 return;\r
555\r
f194e429 556 bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
557 bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
558 wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
559 wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
560 wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
561 wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
562 wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
563 wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
5bcc76c4 564\r
72622d64 565 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
3a89d04c 566 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
72622d64 567 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR))\r
568 /* wait */;\r
5bcc76c4 569 }\r
3a89d04c 570 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
72622d64 571 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP)\r
572 /* wait */;\r
5bcc76c4 573\r
574 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
575 switch ((bRequest << 8) | bmRequestType) {\r
576 case STD_GET_DESCRIPTOR:\r
577 if (wValue == 0x100) // Return Device Descriptor\r
578 AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
579 else if (wValue == 0x200) // Return Configuration Descriptor\r
580 AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
1f42ccdd 581 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
582 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
583 if (strDescriptor != NULL) {\r
584 AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength));\r
585 } else {\r
13c25f89 586 AT91F_USB_SendStall(pUdp);\r
1f42ccdd 587 }\r
588 }\r
5bcc76c4 589 else\r
590 AT91F_USB_SendStall(pUdp);\r
591 break;\r
592 case STD_SET_ADDRESS:\r
593 AT91F_USB_SendZlp(pUdp);\r
594 pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
595 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
596 break;\r
597 case STD_SET_CONFIGURATION:\r
598 btConfiguration = wValue;\r
599 AT91F_USB_SendZlp(pUdp);\r
600 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
f194e429 601 pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
602 pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
603 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
5bcc76c4 604 break;\r
605 case STD_GET_CONFIGURATION:\r
606 AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));\r
607 break;\r
608 case STD_GET_STATUS_ZERO:\r
72622d64 609 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
5bcc76c4 610 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
611 break;\r
612 case STD_GET_STATUS_INTERFACE:\r
72622d64 613 wStatus = 0; // reserved for future use\r
5bcc76c4 614 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
615 break;\r
616 case STD_GET_STATUS_ENDPOINT:\r
617 wStatus = 0;\r
618 wIndex &= 0x0F;\r
f194e429 619 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 620 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
621 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
72622d64 622 } else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
5bcc76c4 623 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
624 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
72622d64 625 } else\r
5bcc76c4 626 AT91F_USB_SendStall(pUdp);\r
627 break;\r
628 case STD_SET_FEATURE_ZERO:\r
629 AT91F_USB_SendStall(pUdp);\r
72622d64 630 break;\r
5bcc76c4 631 case STD_SET_FEATURE_INTERFACE:\r
632 AT91F_USB_SendZlp(pUdp);\r
633 break;\r
634 case STD_SET_FEATURE_ENDPOINT:\r
635 wIndex &= 0x0F;\r
f194e429 636 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 637 pUdp->UDP_CSR[wIndex] = 0;\r
638 AT91F_USB_SendZlp(pUdp);\r
72622d64 639 } else\r
5bcc76c4 640 AT91F_USB_SendStall(pUdp);\r
641 break;\r
642 case STD_CLEAR_FEATURE_ZERO:\r
643 AT91F_USB_SendStall(pUdp);\r
72622d64 644 break;\r
5bcc76c4 645 case STD_CLEAR_FEATURE_INTERFACE:\r
646 AT91F_USB_SendZlp(pUdp);\r
647 break;\r
648 case STD_CLEAR_FEATURE_ENDPOINT:\r
649 wIndex &= 0x0F;\r
f194e429 650 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
651 if (wIndex == AT91C_EP_OUT)\r
652 pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
653 else if (wIndex == AT91C_EP_IN)\r
654 pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
655 else if (wIndex == AT91C_EP_NOTIFY)\r
656 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);\r
5bcc76c4 657 AT91F_USB_SendZlp(pUdp);\r
658 }\r
659 else\r
660 AT91F_USB_SendStall(pUdp);\r
661 break;\r
662\r
663 // handle CDC class requests\r
664 case SET_LINE_CODING:\r
867e10a5 665 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0))\r
72622d64 666 /* wait */;\r
3a89d04c 667 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 668 AT91F_USB_SendZlp(pUdp);\r
669 break;\r
670 case GET_LINE_CODING:\r
671 AT91F_USB_SendData(pUdp, (char *) &line, MIN(sizeof(line), wLength));\r
672 break;\r
673 case SET_CONTROL_LINE_STATE:\r
674 btConnection = wValue;\r
675 AT91F_USB_SendZlp(pUdp);\r
676 break;\r
677 default:\r
678 AT91F_USB_SendStall(pUdp);\r
72622d64 679 break;\r
5bcc76c4 680 }\r
681}\r
867e10a5 682\r
683\r
684//***************************************************************************\r
685// Interface to the main program\r
686//***************************************************************************\r
687\r
688// The function to receive a command from the client via USB\r
689bool cmd_receive(UsbCommand* cmd) {\r
690\r
691 // Check if there is a usb packet available\r
692 if (!usb_poll())\r
693 return false;\r
694\r
695 // Try to retrieve the available command frame\r
696 size_t rxlen = usb_read((uint8_t*)cmd, sizeof(UsbCommand));\r
697\r
698 // Check if the transfer was complete\r
699 if (rxlen != sizeof(UsbCommand))\r
700 return false;\r
701\r
702 // Received command successfully\r
703 return true;\r
704}\r
705\r
706\r
707// The function to send a response to the client via USB\r
b8ed9975 708bool cmd_send(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) {\r
709\r
710 UsbResponse txcmd;\r
711\r
712 // Compose the outgoing response frame\r
713 txcmd.cmd = cmd | CMD_VARIABLE_SIZE_FLAG;\r
714 txcmd.arg[0] = arg0;\r
715 txcmd.arg[1] = arg1;\r
716 txcmd.arg[2] = arg2;\r
867e10a5 717\r
b8ed9975 718 // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE\r
719 if (data) {\r
720 datalen = MIN(datalen, USB_CMD_DATA_SIZE);\r
721 for (uint16_t i = 0; i < datalen; i++) {\r
722 txcmd.d.asBytes[i] = ((uint8_t*)data)[i];\r
723 }\r
724 txcmd.datalen = datalen;\r
725 } else {\r
726 txcmd.datalen = 0;\r
867e10a5 727 }\r
728\r
b8ed9975 729 // Send frame and make sure all bytes are transmitted\r
730 size_t tx_size = offsetof(UsbResponse, d) + datalen;\r
731 if (usb_write((uint8_t*)&txcmd, tx_size) != 0) return false;\r
732\r
733 return true;\r
734}\r
735\r
736\r
737// For compatibility only: legacy function to send a response with fixed size to the client via USB\r
738bool cmd_send_old(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) {\r
739\r
740 UsbCommand txcmd;\r
741\r
742 // Compose the outgoing response frame\r
867e10a5 743 txcmd.cmd = cmd;\r
744 txcmd.arg[0] = arg0;\r
745 txcmd.arg[1] = arg1;\r
746 txcmd.arg[2] = arg2;\r
747\r
748 // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE\r
b8ed9975 749 if (data) {\r
750 datalen = MIN(datalen, USB_CMD_DATA_SIZE);\r
751 for (uint16_t i = 0; i < datalen; i++) {\r
867e10a5 752 txcmd.d.asBytes[i] = ((uint8_t*)data)[i];\r
753 }\r
754 }\r
b8ed9975 755 \r
867e10a5 756 // Send frame and make sure all bytes are transmitted\r
757 if (usb_write((uint8_t*)&txcmd, sizeof(UsbCommand)) != 0) return false;\r
758\r
759 return true;\r
760}\r
b8ed9975 761\r
Impressum, Datenschutz