]> git.zerfleddert.de Git - proxmark3-svn/blame_incremental - armsrc/usb_cdc.c
usb communication (device side) housekeeping
[proxmark3-svn] / armsrc / 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\r
37#include <stddef.h>\r
38#include <stdint.h>\r
39#include <stdbool.h>\r
40\r
41#include "common.h"\r
42#include "at91sam7s512.h"\r
43#include "config_gpio.h"\r
44\r
45#define AT91C_EP_CONTROL 0\r
46#define AT91C_EP_OUT 1\r
47#define AT91C_EP_IN 2\r
48#define AT91C_EP_NOTIFY 3\r
49#define AT91C_EP_OUT_SIZE 0x40\r
50#define AT91C_EP_IN_SIZE 0x40\r
51\r
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
57\r
58static const char devDescriptor[] = {\r
59 /* Device descriptor */\r
60 0x12, // bLength\r
61 0x01, // bDescriptorType\r
62 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)\r
63 0x02, // bDeviceClass: (Communication Device Class)\r
64 0x00, // bDeviceSubclass: (unused at this time)\r
65 0x00, // bDeviceProtocol: (unused at this time)\r
66 0x08, // bMaxPacketSize0\r
67 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)\r
68 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)\r
69 0x01,0x00, // Device release number (0001)\r
70 STR_MANUFACTURER, // iManufacturer\r
71 STR_PRODUCT, // iProduct\r
72 0x00, // iSerialNumber\r
73 0x01 // bNumConfigs\r
74};\r
75\r
76\r
77static const char cfgDescriptor[] = {\r
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
87 0x80, // CbmAttributes (Bus Powered)\r
88 0x4B, // CMaxPower (150mA max current drawn from bus)\r
89\r
90 /* Interface 0 Descriptor: Communication Class Interface */\r
91 0x09, // bLength\r
92 0x04, // bDescriptorType\r
93 0x00, // bInterfaceNumber\r
94 0x00, // bAlternateSetting\r
95 0x01, // bNumEndpoints\r
96 0x02, // bInterfaceClass: Communication Interface Class\r
97 0x02, // bInterfaceSubclass: Abstract Control Model\r
98 0x01, // bInterfaceProtocol: Common AT Commands, V.25ter\r
99 0x00, // iInterface\r
100\r
101 /* Header Functional Descriptor */\r
102 0x05, // bFunction Length\r
103 0x24, // bDescriptor type: CS_INTERFACE\r
104 0x00, // bDescriptor subtype: Header Functional Descriptor\r
105 0x10, // bcdCDC:1.1\r
106 0x01,\r
107\r
108 /* ACM Functional Descriptor */\r
109 0x04, // bFunctionLength\r
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
113\r
114 /* Union Functional Descriptor */\r
115 0x05, // bFunctionLength\r
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
120\r
121 /* Call Management Functional Descriptor */\r
122 0x05, // bFunctionLength\r
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
127\r
128 /* Endpoint 1 descriptor */\r
129 0x07, // bLength\r
130 0x05, // bDescriptorType\r
131 0x83, // bEndpointAddress: Endpoint 03 - IN\r
132 0x03, // bmAttributes: INT\r
133 0x08, // wMaxPacketSize: 8\r
134 0x00,\r
135 0xFF, // bInterval\r
136\r
137 /* Interface 1 Descriptor: Data Class Interface */\r
138 0x09, // bLength\r
139 0x04, // bDescriptorType\r
140 0x01, // bInterfaceNumber\r
141 0x00, // bAlternateSetting\r
142 0x02, // bNumEndpoints\r
143 0x0A, // bInterfaceClass: Data Interface Class\r
144 0x00, // bInterfaceSubclass: not used\r
145 0x00, // bInterfaceProtocol: No class specific protocol required)\r
146 0x00, // iInterface\r
147\r
148 /* Endpoint 1 descriptor */\r
149 0x07, // bLength\r
150 0x05, // bDescriptorType\r
151 0x01, // bEndpointAddress: Endpoint 01 - OUT\r
152 0x02, // bmAttributes: BULK\r
153 AT91C_EP_OUT_SIZE, // wMaxPacketSize\r
154 0x00,\r
155 0x00, // bInterval\r
156\r
157 /* Endpoint 2 descriptor */\r
158 0x07, // bLength\r
159 0x05, // bDescriptorType\r
160 0x82, // bEndpointAddress: Endpoint 02 - IN\r
161 0x02, // bmAttributes: BULK\r
162 AT91C_EP_IN_SIZE, // wMaxPacketSize\r
163 0x00,\r
164 0x00 // bInterval\r
165};\r
166\r
167\r
168static const char StrDescLanguageCodes[] = {\r
169 4, // Length\r
170 0x03, // Type is string\r
171 0x09, 0x04 // supported language Code 0 = 0x0409 (English)\r
172};\r
173\r
174\r
175// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the\r
176// manufacturer string "proxmark.org". Don't change this.\r
177static const char StrDescManufacturer[] = {\r
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
192};\r
193\r
194\r
195static const char StrDescProduct[] = {\r
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
207};\r
208\r
209\r
210const char* getStringDescriptor(uint8_t idx) {\r
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
220 }\r
221}\r
222\r
223\r
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
226 |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \\r
227 |AT91C_UDP_TXCOMP\r
228\r
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
237}\r
238\r
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
249\r
250/* USB standard request codes */\r
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
277\r
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
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
296uint8_t btConfiguration = 0;\r
297uint8_t btConnection = 0;\r
298uint8_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 if (!usb_check()) return false;\r
375 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
376}\r
377\r
378\r
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
387bool usb_poll_validate_length() {\r
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
393\r
394//*----------------------------------------------------------------------------\r
395//* \fn usb_read\r
396//* \brief Read available data from Endpoint OUT\r
397//*----------------------------------------------------------------------------\r
398uint32_t usb_read(uint8_t* data, size_t len) {\r
399 uint8_t bank = btReceiveBank;\r
400 uint32_t packetSize, nbBytesRcv = 0;\r
401 uint32_t time_out = 0;\r
402\r
403 while (len) {\r
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
408 len -= packetSize;\r
409 while (packetSize--)\r
410 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
411 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
412 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
413 bank = AT91C_UDP_RX_DATA_BK1;\r
414 } else {\r
415 bank = AT91C_UDP_RX_DATA_BK0;\r
416 }\r
417 }\r
418 if (time_out++ == 0x1fff) break;\r
419 }\r
420\r
421 btReceiveBank = bank;\r
422 return nbBytesRcv;\r
423}\r
424\r
425\r
426//*----------------------------------------------------------------------------\r
427//* \fn usb_write\r
428//* \brief Send through endpoint 2\r
429//*----------------------------------------------------------------------------\r
430uint32_t usb_write(const uint8_t* data, const size_t len) {\r
431 size_t length = len;\r
432 uint32_t cpt = 0;\r
433\r
434 if (!length) return 0;\r
435 if (!usb_check()) return 0;\r
436\r
437 // Send the first packet\r
438 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
439 length -= cpt;\r
440 while (cpt--) {\r
441 pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
442 }\r
443 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
444\r
445 while (length) {\r
446 // Fill the next bank\r
447 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
448 length -= cpt;\r
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
453 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
454 if (!usb_check()) return length;\r
455 }\r
456 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
457 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)\r
458 /* wait */;\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 /* wait */;\r
470\r
471 return length;\r
472}\r
473\r
474\r
475//*----------------------------------------------------------------------------\r
476//* \fn AT91F_USB_SendData\r
477//* \brief Send Data through the control endpoint\r
478//*----------------------------------------------------------------------------\r
479unsigned int csrTab[100] = {0x00};\r
480unsigned char csrIdx = 0;\r
481\r
482static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
483 uint32_t cpt = 0;\r
484 AT91_REG csr;\r
485\r
486 do {\r
487 cpt = MIN(length, 8);\r
488 length -= cpt;\r
489\r
490 while (cpt--)\r
491 pUdp->UDP_FDR[0] = *pData++;\r
492\r
493 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
494 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
495 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
496 /* wait */;\r
497 }\r
498\r
499 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
500 do {\r
501 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
502\r
503 // Data IN stage has been stopped by a status OUT\r
504 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
505 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
506 return;\r
507 }\r
508 } while (!(csr & AT91C_UDP_TXCOMP));\r
509\r
510 } while (length);\r
511\r
512 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
513 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
514 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
515 /* wait */;\r
516 }\r
517}\r
518\r
519\r
520//*----------------------------------------------------------------------------\r
521//* \fn AT91F_USB_SendZlp\r
522//* \brief Send zero length packet through the control endpoint\r
523//*----------------------------------------------------------------------------\r
524void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
525 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
526 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP))\r
527 /* wait */;\r
528 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
529 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
530 /* wait */;\r
531}\r
532\r
533\r
534//*----------------------------------------------------------------------------\r
535//* \fn AT91F_USB_SendStall\r
536//* \brief Stall the control endpoint\r
537//*----------------------------------------------------------------------------\r
538void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
539 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
540 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR))\r
541 /* wait */;\r
542 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
543 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR))\r
544 /* wait */;\r
545}\r
546\r
547\r
548//*----------------------------------------------------------------------------\r
549//* \fn AT91F_CDC_Enumerate\r
550//* \brief This function is a callback invoked when a SETUP packet is received\r
551//*----------------------------------------------------------------------------\r
552void AT91F_CDC_Enumerate() {\r
553 uint8_t bmRequestType, bRequest;\r
554 uint16_t wValue, wIndex, wLength, wStatus;\r
555\r
556 if (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP))\r
557 return;\r
558\r
559 bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
560 bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL];\r
561 wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
562 wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
563 wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
564 wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
565 wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
566 wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
567\r
568 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
569 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
570 while (!(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR))\r
571 /* wait */;\r
572 }\r
573 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
574 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP)\r
575 /* wait */;\r
576\r
577 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
578 switch ((bRequest << 8) | bmRequestType) {\r
579 case STD_GET_DESCRIPTOR:\r
580 if (wValue == 0x100) // Return Device Descriptor\r
581 AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
582 else if (wValue == 0x200) // Return Configuration Descriptor\r
583 AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
584 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
585 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
586 if (strDescriptor != NULL) {\r
587 AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength));\r
588 } else {\r
589 AT91F_USB_SendStall(pUdp);\r
590 }\r
591 }\r
592 else\r
593 AT91F_USB_SendStall(pUdp);\r
594 break;\r
595 case STD_SET_ADDRESS:\r
596 AT91F_USB_SendZlp(pUdp);\r
597 pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
598 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
599 break;\r
600 case STD_SET_CONFIGURATION:\r
601 btConfiguration = wValue;\r
602 AT91F_USB_SendZlp(pUdp);\r
603 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
604 pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
605 pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
606 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
607 break;\r
608 case STD_GET_CONFIGURATION:\r
609 AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));\r
610 break;\r
611 case STD_GET_STATUS_ZERO:\r
612 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
613 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
614 break;\r
615 case STD_GET_STATUS_INTERFACE:\r
616 wStatus = 0; // reserved for future use\r
617 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
618 break;\r
619 case STD_GET_STATUS_ENDPOINT:\r
620 wStatus = 0;\r
621 wIndex &= 0x0F;\r
622 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
623 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
624 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
625 } else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
626 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
627 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
628 } else\r
629 AT91F_USB_SendStall(pUdp);\r
630 break;\r
631 case STD_SET_FEATURE_ZERO:\r
632 AT91F_USB_SendStall(pUdp);\r
633 break;\r
634 case STD_SET_FEATURE_INTERFACE:\r
635 AT91F_USB_SendZlp(pUdp);\r
636 break;\r
637 case STD_SET_FEATURE_ENDPOINT:\r
638 wIndex &= 0x0F;\r
639 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
640 pUdp->UDP_CSR[wIndex] = 0;\r
641 AT91F_USB_SendZlp(pUdp);\r
642 } else\r
643 AT91F_USB_SendStall(pUdp);\r
644 break;\r
645 case STD_CLEAR_FEATURE_ZERO:\r
646 AT91F_USB_SendStall(pUdp);\r
647 break;\r
648 case STD_CLEAR_FEATURE_INTERFACE:\r
649 AT91F_USB_SendZlp(pUdp);\r
650 break;\r
651 case STD_CLEAR_FEATURE_ENDPOINT:\r
652 wIndex &= 0x0F;\r
653 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
654 if (wIndex == AT91C_EP_OUT)\r
655 pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
656 else if (wIndex == AT91C_EP_IN)\r
657 pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
658 else if (wIndex == AT91C_EP_NOTIFY)\r
659 pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);\r
660 AT91F_USB_SendZlp(pUdp);\r
661 }\r
662 else\r
663 AT91F_USB_SendStall(pUdp);\r
664 break;\r
665\r
666 // handle CDC class requests\r
667 case SET_LINE_CODING:\r
668 while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0))\r
669 /* wait */;\r
670 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
671 AT91F_USB_SendZlp(pUdp);\r
672 break;\r
673 case GET_LINE_CODING:\r
674 AT91F_USB_SendData(pUdp, (char *) &line, MIN(sizeof(line), wLength));\r
675 break;\r
676 case SET_CONTROL_LINE_STATE:\r
677 btConnection = wValue;\r
678 AT91F_USB_SendZlp(pUdp);\r
679 break;\r
680 default:\r
681 AT91F_USB_SendStall(pUdp);\r
682 break;\r
683 }\r
684}\r
Impressum, Datenschutz