]> git.zerfleddert.de Git - proxmark3-svn/blame - common/usb_cdc.c
Add BOS USB descriptor. This allows non-root access on Android devices
[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
948b49c4
P
159const char BOSDescriptor[] = {\r
160 // BOS descriptor header\r
161 0x05, 0x0F, 0x39, 0x00, 0x02,\r
162\r
163 // Microsoft OS 2.0 Platform Capability Descriptor\r
164 0x1C, // Descriptor size (28 bytes)\r
165 0x10, // Descriptor type (Device Capability)\r
166 0x05, // Capability type (Platform)\r
167 0x00, // Reserved\r
168\r
169 // MS OS 2.0 Platform Capability ID (D8DD60DF-4589-4CC7-9CD2-659D9E648A9F)\r
170 0xDF, 0x60, 0xDD, 0xD8,\r
171 0x89, 0x45,\r
172 0xC7, 0x4C,\r
173 0x9C, 0xD2,\r
174 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,\r
175\r
176 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000)\r
177 0x1e, 0x00,\r
178 252, // Vendor-assigned bMS_VendorCode\r
179 0x00 // Doesn’t support alternate enumeration\r
180};\r
5bcc76c4 181\r
1f42ccdd 182static const char StrDescLanguageCodes[] = {\r
183 4, // Length\r
184 0x03, // Type is string\r
185 0x09, 0x04 // supported language Code 0 = 0x0409 (English)\r
186};\r
05b6b117
MF
187\r
188// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the\r
189// manufacturer string "proxmark.org". Don't change this.\r
1f42ccdd 190static const char StrDescManufacturer[] = {\r
191 26, // Length\r
5bcc76c4 192 0x03, // Type is string\r
193 'p', 0x00,\r
194 'r', 0x00,\r
195 'o', 0x00,\r
196 'x', 0x00,\r
197 'm', 0x00,\r
198 'a', 0x00,\r
199 'r', 0x00,\r
200 'k', 0x00,\r
201 '.', 0x00,\r
202 'o', 0x00,\r
203 'r', 0x00,\r
1f42ccdd 204 'g', 0x00\r
205};\r
206\r
207static const char StrDescProduct[] = {\r
208 8, // Length\r
209 0x03, // Type is string\r
210 'P', 0x00,\r
211 'M', 0x00,\r
212 '3', 0x00\r
213};\r
5bcc76c4 214\r
1f42ccdd 215const char* getStringDescriptor(uint8_t idx)\r
216{\r
05b6b117
MF
217 switch (idx) {\r
218 case STR_LANGUAGE_CODES:\r
219 return StrDescLanguageCodes;\r
220 case STR_MANUFACTURER:\r
221 return StrDescManufacturer;\r
222 case STR_PRODUCT:\r
223 return StrDescProduct;\r
224 default:\r
225 return NULL;\r
1f42ccdd 226 }\r
227}\r
5bcc76c4 228\r
3a89d04c 229// Bitmap for all status bits in CSR which must be written as 1 to cause no effect\r
230#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \\r
231 |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \\r
232 |AT91C_UDP_TXCOMP\r
233\r
234// Clear flags in the UDP_CSR register\r
235#define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \\r
236 volatile unsigned int reg; \\r
237 reg = pUdp->UDP_CSR[(endpoint)]; \\r
238 reg |= REG_NO_EFFECT_1_ALL; \\r
239 reg &= ~(flags); \\r
240 pUdp->UDP_CSR[(endpoint)] = reg; \\r
241} \r
242\r
243// Set flags in the UDP_CSR register\r
244#define UDP_SET_EP_FLAGS(endpoint, flags) { \\r
245 volatile unsigned int reg; \\r
246 reg = pUdp->UDP_CSR[(endpoint)]; \\r
247 reg |= REG_NO_EFFECT_1_ALL; \\r
248 reg |= (flags); \\r
249 pUdp->UDP_CSR[(endpoint)] = reg; \\r
250}\r
251\r
252/* USB standard request codes */\r
5bcc76c4 253#define STD_GET_STATUS_ZERO 0x0080\r
254#define STD_GET_STATUS_INTERFACE 0x0081\r
255#define STD_GET_STATUS_ENDPOINT 0x0082\r
256\r
257#define STD_CLEAR_FEATURE_ZERO 0x0100\r
258#define STD_CLEAR_FEATURE_INTERFACE 0x0101\r
259#define STD_CLEAR_FEATURE_ENDPOINT 0x0102\r
260\r
261#define STD_SET_FEATURE_ZERO 0x0300\r
262#define STD_SET_FEATURE_INTERFACE 0x0301\r
263#define STD_SET_FEATURE_ENDPOINT 0x0302\r
264\r
265#define STD_SET_ADDRESS 0x0500\r
266#define STD_GET_DESCRIPTOR 0x0680\r
267#define STD_SET_DESCRIPTOR 0x0700\r
268#define STD_GET_CONFIGURATION 0x0880\r
269#define STD_SET_CONFIGURATION 0x0900\r
270#define STD_GET_INTERFACE 0x0A81\r
271#define STD_SET_INTERFACE 0x0B01\r
272#define STD_SYNCH_FRAME 0x0C82\r
273\r
274/* CDC Class Specific Request Code */\r
275#define GET_LINE_CODING 0x21A1\r
276#define SET_LINE_CODING 0x2021\r
277#define SET_CONTROL_LINE_STATE 0x2221\r
278\r
279typedef struct {\r
280 unsigned int dwDTERRate;\r
281 char bCharFormat;\r
282 char bParityType;\r
283 char bDataBits;\r
284} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;\r
285\r
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
5bcc76c4 293void AT91F_CDC_Enumerate();\r
294\r
295AT91PS_UDP pUdp = AT91C_BASE_UDP;\r
296byte_t btConfiguration = 0;\r
297byte_t btConnection = 0;\r
298byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;\r
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
310 if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {\r
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
341 for (volatile size_t i=0; i<0x100000; i++);\r
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
6e82300d 353bool 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
373bool usb_poll()\r
374{\r
f194e429 375 if (!usb_check()) return false;\r
376 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
5bcc76c4 377}\r
378\r
f194e429 379\r
83f3f8ac
MHS
380/**\r
381 In github PR #129, some users appears to get a false positive from\r
382 usb_poll, which returns true, but the usb_read operation\r
383 still returns 0.\r
384 This check is basically the same as above, but also checks\r
385 that the length available to read is non-zero, thus hopefully fixes the\r
386 bug.\r
387**/\r
388bool usb_poll_validate_length()\r
389{\r
83f3f8ac
MHS
390 if (!usb_check()) return false;\r
391 if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;\r
392 return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;\r
393}\r
394\r
5bcc76c4 395//*----------------------------------------------------------------------------\r
79a73ab2 396//* \fn usb_read\r
5bcc76c4 397//* \brief Read available data from Endpoint OUT\r
398//*----------------------------------------------------------------------------\r
6e82300d 399uint32_t usb_read(byte_t* data, size_t len) {\r
d2deaf7b 400 byte_t bank = btReceiveBank;\r
5bcc76c4 401 uint32_t packetSize, nbBytesRcv = 0;\r
d2deaf7b 402 uint32_t time_out = 0;\r
5bcc76c4 403 \r
23b598ee 404 while (len) {\r
5bcc76c4 405 if (!usb_check()) break;\r
406\r
407 if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) {\r
408 packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len);\r
d2deaf7b 409 len -= packetSize;\r
5bcc76c4 410 while(packetSize--)\r
411 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
3a89d04c 412 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
23b598ee 413 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
5bcc76c4 414 bank = AT91C_UDP_RX_DATA_BK1;\r
d2deaf7b 415 } else {\r
5bcc76c4 416 bank = AT91C_UDP_RX_DATA_BK0;\r
d2deaf7b 417 }\r
5bcc76c4 418 }\r
d2deaf7b 419 if (time_out++ == 0x1fff) break;\r
5bcc76c4 420 }\r
421\r
422 btReceiveBank = bank;\r
423 return nbBytesRcv;\r
424}\r
425\r
f194e429 426\r
5bcc76c4 427//*----------------------------------------------------------------------------\r
79a73ab2 428//* \fn usb_write\r
5bcc76c4 429//* \brief Send through endpoint 2\r
430//*----------------------------------------------------------------------------\r
6e82300d 431uint32_t usb_write(const byte_t* data, const size_t len) {\r
f194e429 432 size_t length = len;\r
5bcc76c4 433 uint32_t cpt = 0;\r
434\r
f194e429 435 if (!length) return 0;\r
436 if (!usb_check()) return 0;\r
437\r
5bcc76c4 438 // Send the first packet\r
f194e429 439 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 440 length -= cpt;\r
f194e429 441 while (cpt--) {\r
442 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
443 }\r
3a89d04c 444 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 445\r
446 while (length) {\r
f194e429 447 // Fill the next bank\r
448 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
5bcc76c4 449 length -= cpt;\r
f194e429 450 while (cpt--) {\r
451 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
452 }\r
453 // Wait for the previous bank to be sent\r
5bcc76c4 454 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
455 if (!usb_check()) return length;\r
f194e429 456 }\r
3a89d04c 457 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 458 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\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
5bcc76c4 468 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
469\r
470 return length;\r
471}\r
472\r
f194e429 473\r
5bcc76c4 474//*----------------------------------------------------------------------------\r
475//* \fn AT91F_USB_SendData\r
476//* \brief Send Data through the control endpoint\r
477//*----------------------------------------------------------------------------\r
5ee70129 478unsigned int csrTab[100] = {0x00};\r
5bcc76c4 479unsigned char csrIdx = 0;\r
480\r
6e82300d 481static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
5bcc76c4 482 uint32_t cpt = 0;\r
483 AT91_REG csr;\r
484\r
485 do {\r
486 cpt = MIN(length, 8);\r
487 length -= cpt;\r
488\r
489 while (cpt--)\r
490 pUdp->UDP_FDR[0] = *pData++;\r
491\r
3a89d04c 492 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
493 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
494 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 495 }\r
496\r
3a89d04c 497 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 498 do {\r
3a89d04c 499 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
5bcc76c4 500\r
501 // Data IN stage has been stopped by a status OUT\r
502 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
3a89d04c 503 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 504 return;\r
505 }\r
506 } while ( !(csr & AT91C_UDP_TXCOMP) );\r
507\r
508 } while (length);\r
509\r
3a89d04c 510 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
511 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
512 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\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
6e82300d 521void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
3a89d04c 522 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
523 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) );\r
524 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
525 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 526}\r
527\r
f194e429 528\r
5bcc76c4 529//*----------------------------------------------------------------------------\r
530//* \fn AT91F_USB_SendStall\r
531//* \brief Stall the control endpoint\r
532//*----------------------------------------------------------------------------\r
6e82300d 533void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
3a89d04c 534 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
535 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR) );\r
536 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
537 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));\r
5bcc76c4 538}\r
539\r
f194e429 540\r
5bcc76c4 541//*----------------------------------------------------------------------------\r
542//* \fn AT91F_CDC_Enumerate\r
543//* \brief This function is a callback invoked when a SETUP packet is received\r
544//*----------------------------------------------------------------------------\r
6e82300d 545void AT91F_CDC_Enumerate() {\r
5bcc76c4 546 byte_t bmRequestType, bRequest;\r
547 uint16_t wValue, wIndex, wLength, wStatus;\r
548\r
3a89d04c 549 if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) )\r
5bcc76c4 550 return;\r
551\r
f194e429 552 bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
553 bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
554 wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
555 wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
556 wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
557 wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
558 wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
559 wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
5bcc76c4 560\r
f194e429 561 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
3a89d04c 562 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
563 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) );\r
5bcc76c4 564 }\r
3a89d04c 565 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
566 while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) );\r
5bcc76c4 567\r
568 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
569 switch ((bRequest << 8) | bmRequestType) {\r
570 case STD_GET_DESCRIPTOR:\r
571 if (wValue == 0x100) // Return Device Descriptor\r
572 AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
573 else if (wValue == 0x200) // Return Configuration Descriptor\r
574 AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
948b49c4
P
575 else if ((wValue & 0xF00) == 0xF00) // Return BOS Descriptor\r
576 AT91F_USB_SendData(pUdp, BOSDescriptor, MIN(sizeof(BOSDescriptor), wLength));\r
577 else if ((wValue & 0x300) == 0x300) // Return Manufacturer Descriptor - this is needed by Android\r
578 AT91F_USB_SendData(pUdp, StrDescManufacturer, MIN(sizeof(StrDescManufacturer), wLength));\r
1f42ccdd 579 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
580 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
581 if (strDescriptor != NULL) {\r
582 AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength));\r
583 } else {\r
584 AT91F_USB_SendStall(pUdp);\r
585 }\r
586 }\r
5bcc76c4 587 else\r
588 AT91F_USB_SendStall(pUdp);\r
589 break;\r
590 case STD_SET_ADDRESS:\r
591 AT91F_USB_SendZlp(pUdp);\r
592 pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
593 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
594 break;\r
595 case STD_SET_CONFIGURATION:\r
596 btConfiguration = wValue;\r
597 AT91F_USB_SendZlp(pUdp);\r
598 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
f194e429 599 pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
600 pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
601 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
5bcc76c4 602 break;\r
603 case STD_GET_CONFIGURATION:\r
604 AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));\r
605 break;\r
606 case STD_GET_STATUS_ZERO:\r
f194e429 607 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
5bcc76c4 608 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
609 break;\r
610 case STD_GET_STATUS_INTERFACE:\r
f194e429 611 wStatus = 0; // reserved for future use\r
5bcc76c4 612 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
613 break;\r
614 case STD_GET_STATUS_ENDPOINT:\r
615 wStatus = 0;\r
616 wIndex &= 0x0F;\r
f194e429 617 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
5bcc76c4 618 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
619 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
620 }\r
f194e429 621 else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
5bcc76c4 622 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
623 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
624 }\r
625 else\r
626 AT91F_USB_SendStall(pUdp);\r
627 break;\r
628 case STD_SET_FEATURE_ZERO:\r
629 AT91F_USB_SendStall(pUdp);\r
630 break;\r
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
639 }\r
640 else\r
641 AT91F_USB_SendStall(pUdp);\r
642 break;\r
643 case STD_CLEAR_FEATURE_ZERO:\r
644 AT91F_USB_SendStall(pUdp);\r
645 break;\r
646 case STD_CLEAR_FEATURE_INTERFACE:\r
647 AT91F_USB_SendZlp(pUdp);\r
648 break;\r
649 case STD_CLEAR_FEATURE_ENDPOINT:\r
650 wIndex &= 0x0F;\r
f194e429 651 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
652 if (wIndex == AT91C_EP_OUT)\r
653 pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
654 else if (wIndex == AT91C_EP_IN)\r
655 pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
656 else if (wIndex == AT91C_EP_NOTIFY)\r
657 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);\r
5bcc76c4 658 AT91F_USB_SendZlp(pUdp);\r
659 }\r
660 else\r
661 AT91F_USB_SendStall(pUdp);\r
662 break;\r
663\r
664 // handle CDC class requests\r
665 case SET_LINE_CODING:\r
3a89d04c 666 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0) );\r
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
679 break;\r
680 }\r
681}\r
Impressum, Datenschutz