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