]> git.zerfleddert.de Git - proxmark3-svn/blame_incremental - common/usb_cdc.c
Add BOS USB descriptor. This allows non-root access on Android devices
[proxmark3-svn] / common / usb_cdc.c
... / ...
CommitLineData
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
36#include "at91sam7s512.h"\r
37#include "config_gpio.h"\r
38\r
39\r
40#define AT91C_EP_CONTROL 0\r
41#define AT91C_EP_OUT 1\r
42#define AT91C_EP_IN 2\r
43#define AT91C_EP_NOTIFY 3\r
44#define AT91C_EP_OUT_SIZE 0x40\r
45#define AT91C_EP_IN_SIZE 0x40\r
46\r
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
52static const char devDescriptor[] = {\r
53 /* Device descriptor */\r
54 0x12, // bLength\r
55 0x01, // bDescriptorType\r
56 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)\r
57 0x02, // bDeviceClass: (Communication Device Class)\r
58 0x00, // bDeviceSubclass: (unused at this time)\r
59 0x00, // bDeviceProtocol: (unused at this time)\r
60 0x08, // bMaxPacketSize0\r
61 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)\r
62 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)\r
63 0x01,0x00, // Device release number (0001)\r
64 STR_MANUFACTURER, // iManufacturer\r
65 STR_PRODUCT, // iProduct\r
66 0x00, // iSerialNumber\r
67 0x01 // bNumConfigs\r
68};\r
69\r
70static const char cfgDescriptor[] = {\r
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 0x80, // CbmAttributes (Bus Powered)\r
81 0x4B, // CMaxPower (150mA max current drawn from bus)\r
82\r
83 /* Interface 0 Descriptor: Communication Class Interface */\r
84 0x09, // bLength\r
85 0x04, // bDescriptorType\r
86 0x00, // bInterfaceNumber\r
87 0x00, // bAlternateSetting\r
88 0x01, // bNumEndpoints\r
89 0x02, // bInterfaceClass: Communication Interface Class\r
90 0x02, // bInterfaceSubclass: Abstract Control Model\r
91 0x01, // bInterfaceProtocol: Common AT Commands, V.25ter\r
92 0x00, // iInterface\r
93\r
94 /* Header Functional Descriptor */\r
95 0x05, // bFunction Length\r
96 0x24, // bDescriptor type: CS_INTERFACE\r
97 0x00, // bDescriptor subtype: Header Functional Descriptor\r
98 0x10, // bcdCDC:1.1\r
99 0x01,\r
100\r
101 /* ACM Functional Descriptor */\r
102 0x04, // bFunctionLength\r
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
106\r
107 /* Union Functional Descriptor */\r
108 0x05, // bFunctionLength\r
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
113\r
114 /* Call Management Functional Descriptor */\r
115 0x05, // bFunctionLength\r
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
120\r
121 /* Endpoint 1 descriptor */\r
122 0x07, // bLength\r
123 0x05, // bDescriptorType\r
124 0x83, // bEndpointAddress: Endpoint 03 - IN\r
125 0x03, // bmAttributes: INT\r
126 0x08, // wMaxPacketSize: 8\r
127 0x00,\r
128 0xFF, // bInterval\r
129\r
130 /* Interface 1 Descriptor: Data Class Interface */\r
131 0x09, // bLength\r
132 0x04, // bDescriptorType\r
133 0x01, // bInterfaceNumber\r
134 0x00, // bAlternateSetting\r
135 0x02, // bNumEndpoints\r
136 0x0A, // bInterfaceClass: Data Interface Class\r
137 0x00, // bInterfaceSubclass: not used\r
138 0x00, // bInterfaceProtocol: No class specific protocol required)\r
139 0x00, // iInterface\r
140\r
141 /* Endpoint 1 descriptor */\r
142 0x07, // bLength\r
143 0x05, // bDescriptorType\r
144 0x01, // bEndpointAddress: Endpoint 01 - OUT\r
145 0x02, // bmAttributes: BULK\r
146 AT91C_EP_OUT_SIZE, // wMaxPacketSize\r
147 0x00,\r
148 0x00, // bInterval\r
149\r
150 /* Endpoint 2 descriptor */\r
151 0x07, // bLength\r
152 0x05, // bDescriptorType\r
153 0x82, // bEndpointAddress: Endpoint 02 - IN\r
154 0x02, // bmAttributes: BULK\r
155 AT91C_EP_IN_SIZE, // wMaxPacketSize\r
156 0x00,\r
157 0x00 // bInterval\r
158};\r
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
181\r
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
187\r
188// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the\r
189// manufacturer string "proxmark.org". Don't change this.\r
190static const char StrDescManufacturer[] = {\r
191 26, // Length\r
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
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
214\r
215const char* getStringDescriptor(uint8_t idx)\r
216{\r
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
226 }\r
227}\r
228\r
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
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
292\r
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
300\r
301//*----------------------------------------------------------------------------\r
302//* \fn usb_disable\r
303//* \brief This function deactivates the USB device\r
304//*----------------------------------------------------------------------------\r
305void usb_disable() {\r
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
313}\r
314\r
315\r
316//*----------------------------------------------------------------------------\r
317//* \fn usb_enable\r
318//* \brief This function Activates the USB device\r
319//*----------------------------------------------------------------------------\r
320void usb_enable() {\r
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
332 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output\r
333\r
334 // Clear for set the Pullup resistor\r
335 AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;\r
336\r
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
346}\r
347\r
348\r
349//*----------------------------------------------------------------------------\r
350//* \fn usb_check\r
351//* \brief Test if the device is configured and handle enumeration\r
352//*----------------------------------------------------------------------------\r
353bool usb_check() {\r
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
364 pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);\r
365 } else if (isr & AT91C_UDP_EPINT0) {\r
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
375 if (!usb_check()) return false;\r
376 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
377}\r
378\r
379\r
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
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
395//*----------------------------------------------------------------------------\r
396//* \fn usb_read\r
397//* \brief Read available data from Endpoint OUT\r
398//*----------------------------------------------------------------------------\r
399uint32_t usb_read(byte_t* data, size_t len) {\r
400 byte_t bank = btReceiveBank;\r
401 uint32_t packetSize, nbBytesRcv = 0;\r
402 uint32_t time_out = 0;\r
403 \r
404 while (len) {\r
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
409 len -= packetSize;\r
410 while(packetSize--)\r
411 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
412 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
413 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
414 bank = AT91C_UDP_RX_DATA_BK1;\r
415 } else {\r
416 bank = AT91C_UDP_RX_DATA_BK0;\r
417 }\r
418 }\r
419 if (time_out++ == 0x1fff) break;\r
420 }\r
421\r
422 btReceiveBank = bank;\r
423 return nbBytesRcv;\r
424}\r
425\r
426\r
427//*----------------------------------------------------------------------------\r
428//* \fn usb_write\r
429//* \brief Send through endpoint 2\r
430//*----------------------------------------------------------------------------\r
431uint32_t usb_write(const byte_t* data, const size_t len) {\r
432 size_t length = len;\r
433 uint32_t cpt = 0;\r
434\r
435 if (!length) return 0;\r
436 if (!usb_check()) return 0;\r
437\r
438 // Send the first packet\r
439 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
440 length -= cpt;\r
441 while (cpt--) {\r
442 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
443 }\r
444 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
445\r
446 while (length) {\r
447 // Fill the next bank\r
448 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
449 length -= cpt;\r
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
454 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
455 if (!usb_check()) return length;\r
456 }\r
457 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
458 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
459 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
460 }\r
461\r
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
465 }\r
466\r
467 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
468 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
469\r
470 return length;\r
471}\r
472\r
473\r
474//*----------------------------------------------------------------------------\r
475//* \fn AT91F_USB_SendData\r
476//* \brief Send Data through the control endpoint\r
477//*----------------------------------------------------------------------------\r
478unsigned int csrTab[100] = {0x00};\r
479unsigned char csrIdx = 0;\r
480\r
481static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
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
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
495 }\r
496\r
497 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
498 do {\r
499 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
500\r
501 // Data IN stage has been stopped by a status OUT\r
502 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
503 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
504 return;\r
505 }\r
506 } while ( !(csr & AT91C_UDP_TXCOMP) );\r
507\r
508 } while (length);\r
509\r
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
513 }\r
514}\r
515\r
516\r
517//*----------------------------------------------------------------------------\r
518//* \fn AT91F_USB_SendZlp\r
519//* \brief Send zero length packet through the control endpoint\r
520//*----------------------------------------------------------------------------\r
521void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
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
526}\r
527\r
528\r
529//*----------------------------------------------------------------------------\r
530//* \fn AT91F_USB_SendStall\r
531//* \brief Stall the control endpoint\r
532//*----------------------------------------------------------------------------\r
533void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
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
538}\r
539\r
540\r
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
545void AT91F_CDC_Enumerate() {\r
546 byte_t bmRequestType, bRequest;\r
547 uint16_t wValue, wIndex, wLength, wStatus;\r
548\r
549 if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) )\r
550 return;\r
551\r
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
560\r
561 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
562 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
563 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) );\r
564 }\r
565 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
566 while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) );\r
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
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
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
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
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
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
607 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
608 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
609 break;\r
610 case STD_GET_STATUS_INTERFACE:\r
611 wStatus = 0; // reserved for future use\r
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
617 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
618 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
619 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
620 }\r
621 else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
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
636 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
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
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
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
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
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