]> git.zerfleddert.de Git - proxmark3-svn/blame - common/usb_cdc.c
Merge pull request #420 from merlokk/b_fix
[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_IN_SIZE 0x40\r
42#define AT91C_EP_OUT 1\r
43#define AT91C_EP_OUT_SIZE 0x40\r
44#define AT91C_EP_IN 2\r
45\r
1f42ccdd 46static const char devDescriptor[] = {\r
5bcc76c4 47 /* Device descriptor */\r
48 0x12, // bLength\r
49 0x01, // bDescriptorType\r
1f42ccdd 50 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)\r
5bcc76c4 51 0x02, // bDeviceClass: CDC class code\r
52 0x00, // bDeviceSubclass: CDC class sub code\r
53 0x00, // bDeviceProtocol: CDC Device protocol\r
54 0x08, // bMaxPacketSize0\r
1f42ccdd 55 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)\r
56 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)\r
5bcc76c4 57 0x01,0x00, // Device release number (0001)\r
1f42ccdd 58 0x01, // iManufacturer\r
59 0x02, // iProduct\r
60 0x00, // iSerialNumber\r
5bcc76c4 61 0x01 // bNumConfigs\r
62};\r
63\r
1f42ccdd 64static const char cfgDescriptor[] = {\r
5bcc76c4 65 /* ============== CONFIGURATION 1 =========== */\r
66 /* Configuration 1 descriptor */\r
67 0x09, // CbLength\r
68 0x02, // CbDescriptorType\r
69 0x43, // CwTotalLength 2 EP + Control\r
70 0x00,\r
71 0x02, // CbNumInterfaces\r
72 0x01, // CbConfigurationValue\r
73 0x00, // CiConfiguration\r
74 0xC0, // CbmAttributes 0xA0\r
1f42ccdd 75 0xFA, // CMaxPower\r
5bcc76c4 76\r
77 /* Communication Class Interface Descriptor Requirement */\r
78 0x09, // bLength\r
79 0x04, // bDescriptorType\r
80 0x00, // bInterfaceNumber\r
81 0x00, // bAlternateSetting\r
82 0x01, // bNumEndpoints\r
83 0x02, // bInterfaceClass\r
84 0x02, // bInterfaceSubclass\r
1f42ccdd 85 0x01, // bInterfaceProtocol\r
5bcc76c4 86 0x00, // iInterface\r
87\r
88 /* Header Functional Descriptor */\r
89 0x05, // bFunction Length\r
90 0x24, // bDescriptor type: CS_INTERFACE\r
91 0x00, // bDescriptor subtype: Header Func Desc\r
92 0x10, // bcdCDC:1.1\r
93 0x01,\r
94\r
95 /* ACM Functional Descriptor */\r
96 0x04, // bFunctionLength\r
97 0x24, // bDescriptor Type: CS_INTERFACE\r
98 0x02, // bDescriptor Subtype: ACM Func Desc\r
1f42ccdd 99 0x02, // bmCapabilities\r
5bcc76c4 100\r
101 /* Union Functional Descriptor */\r
102 0x05, // bFunctionLength\r
103 0x24, // bDescriptorType: CS_INTERFACE\r
104 0x06, // bDescriptor Subtype: Union Func Desc\r
105 0x00, // bMasterInterface: Communication Class Interface\r
106 0x01, // bSlaveInterface0: Data Class Interface\r
107\r
108 /* Call Management Functional Descriptor */\r
109 0x05, // bFunctionLength\r
110 0x24, // bDescriptor Type: CS_INTERFACE\r
111 0x01, // bDescriptor Subtype: Call Management Func Desc\r
112 0x00, // bmCapabilities: D1 + D0\r
113 0x01, // bDataInterface: Data Class Interface 1\r
114\r
115 /* Endpoint 1 descriptor */\r
116 0x07, // bLength\r
117 0x05, // bDescriptorType\r
118 0x83, // bEndpointAddress, Endpoint 03 - IN\r
119 0x03, // bmAttributes INT\r
120 0x08, // wMaxPacketSize\r
121 0x00,\r
122 0xFF, // bInterval\r
123\r
124 /* Data Class Interface Descriptor Requirement */\r
125 0x09, // bLength\r
126 0x04, // bDescriptorType\r
127 0x01, // bInterfaceNumber\r
128 0x00, // bAlternateSetting\r
129 0x02, // bNumEndpoints\r
130 0x0A, // bInterfaceClass\r
131 0x00, // bInterfaceSubclass\r
132 0x00, // bInterfaceProtocol\r
133 0x00, // iInterface\r
134\r
135 /* First alternate setting */\r
136 /* Endpoint 1 descriptor */\r
137 0x07, // bLength\r
138 0x05, // bDescriptorType\r
139 0x01, // bEndpointAddress, Endpoint 01 - OUT\r
140 0x02, // bmAttributes BULK\r
141 AT91C_EP_OUT_SIZE, // wMaxPacketSize\r
142 0x00,\r
143 0x00, // bInterval\r
144\r
145 /* Endpoint 2 descriptor */\r
146 0x07, // bLength\r
147 0x05, // bDescriptorType\r
148 0x82, // bEndpointAddress, Endpoint 02 - IN\r
149 0x02, // bmAttributes BULK\r
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
265void AT91F_CDC_Enumerate();\r
266\r
267AT91PS_UDP pUdp = AT91C_BASE_UDP;\r
268byte_t btConfiguration = 0;\r
269byte_t btConnection = 0;\r
270byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;\r
271\r
6e82300d 272//*----------------------------------------------------------------------------\r
79a73ab2 273//* \fn usb_disable\r
6e82300d 274//* \brief This function deactivates the USB device\r
275//*----------------------------------------------------------------------------\r
276void usb_disable() {\r
79a73ab2 277 // Disconnect the USB device\r
278 AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;\r
6e82300d 279 \r
280 // Clear all lingering interrupts\r
281 if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {\r
282 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
283 }\r
284}\r
285\r
5bcc76c4 286//*----------------------------------------------------------------------------\r
79a73ab2 287//* \fn usb_enable\r
5bcc76c4 288//* \brief This function Activates the USB device\r
289//*----------------------------------------------------------------------------\r
6e82300d 290void usb_enable() {\r
5bcc76c4 291 // Set the PLL USB Divider\r
292 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;\r
293 \r
294 // Specific Chip USB Initialisation\r
295 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock\r
296 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
297 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
298 \r
299 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO\r
300 // Set in PIO mode and Configure in Output\r
79a73ab2 301 AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode\r
302 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output\r
5bcc76c4 303 \r
79a73ab2 304 // Clear for set the Pullup resistor\r
305 AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;\r
6e82300d 306 \r
79a73ab2 307 // Disconnect and reconnect USB controller for 100ms\r
6e82300d 308 usb_disable();\r
309 \r
310 // Wait for a short while\r
28fdb04f 311 for (volatile size_t i=0; i<0x100000; i++);\r
6e82300d 312\r
313 // Reconnect USB reconnect\r
79a73ab2 314 AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;\r
315 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;\r
5bcc76c4 316}\r
317\r
318//*----------------------------------------------------------------------------\r
79a73ab2 319//* \fn usb_check\r
5bcc76c4 320//* \brief Test if the device is configured and handle enumeration\r
321//*----------------------------------------------------------------------------\r
6e82300d 322bool usb_check() {\r
5bcc76c4 323 AT91_REG isr = pUdp->UDP_ISR;\r
324\r
325 if (isr & AT91C_UDP_ENDBUSRES) {\r
326 pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
327 // reset all endpoints\r
328 pUdp->UDP_RSTEP = (unsigned int)-1;\r
329 pUdp->UDP_RSTEP = 0;\r
330 // Enable the function\r
331 pUdp->UDP_FADDR = AT91C_UDP_FEN;\r
332 // Configure endpoint 0\r
3a89d04c 333 pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);\r
5bcc76c4 334 }\r
335 else if (isr & AT91C_UDP_EPINT0) {\r
336 pUdp->UDP_ICR = AT91C_UDP_EPINT0;\r
337 AT91F_CDC_Enumerate();\r
338 }\r
339 return (btConfiguration) ? true : false;\r
340}\r
341\r
342\r
343bool usb_poll()\r
344{\r
345 if (!usb_check()) return false;\r
346 return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
347}\r
348\r
83f3f8ac
MHS
349/**\r
350 In github PR #129, some users appears to get a false positive from\r
351 usb_poll, which returns true, but the usb_read operation\r
352 still returns 0.\r
353 This check is basically the same as above, but also checks\r
354 that the length available to read is non-zero, thus hopefully fixes the\r
355 bug.\r
356**/\r
357bool usb_poll_validate_length()\r
358{\r
359\r
360 if (!usb_check()) return false;\r
361 if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;\r
362 return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;\r
363}\r
364\r
5bcc76c4 365//*----------------------------------------------------------------------------\r
79a73ab2 366//* \fn usb_read\r
5bcc76c4 367//* \brief Read available data from Endpoint OUT\r
368//*----------------------------------------------------------------------------\r
6e82300d 369uint32_t usb_read(byte_t* data, size_t len) {\r
d2deaf7b 370 byte_t bank = btReceiveBank;\r
5bcc76c4 371 uint32_t packetSize, nbBytesRcv = 0;\r
d2deaf7b 372 uint32_t time_out = 0;\r
5bcc76c4 373 \r
23b598ee 374 while (len) {\r
5bcc76c4 375 if (!usb_check()) break;\r
376\r
377 if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) {\r
378 packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len);\r
d2deaf7b 379 len -= packetSize;\r
5bcc76c4 380 while(packetSize--)\r
381 data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];\r
3a89d04c 382 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
23b598ee 383 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
5bcc76c4 384 bank = AT91C_UDP_RX_DATA_BK1;\r
d2deaf7b 385 } else {\r
5bcc76c4 386 bank = AT91C_UDP_RX_DATA_BK0;\r
d2deaf7b 387 }\r
5bcc76c4 388 }\r
d2deaf7b 389 if (time_out++ == 0x1fff) break;\r
5bcc76c4 390 }\r
391\r
392 btReceiveBank = bank;\r
393 return nbBytesRcv;\r
394}\r
395\r
396//*----------------------------------------------------------------------------\r
79a73ab2 397//* \fn usb_write\r
5bcc76c4 398//* \brief Send through endpoint 2\r
399//*----------------------------------------------------------------------------\r
6e82300d 400uint32_t usb_write(const byte_t* data, const size_t len) {\r
5bcc76c4 401 size_t length = len;\r
402 uint32_t cpt = 0;\r
403\r
404 if (!length) return 0;\r
405 if (!usb_check()) return 0;\r
406 \r
407 // Send the first packet\r
408 cpt = MIN(length, AT91C_EP_IN_SIZE-1);\r
409 length -= cpt;\r
410 while (cpt--) pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
3a89d04c 411 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 412\r
413 while (length) {\r
414 // Fill the second bank\r
415 cpt = MIN(length, AT91C_EP_IN_SIZE-1);\r
416 length -= cpt;\r
417 while (cpt--) pUdp->UDP_FDR[AT91C_EP_IN] = *data++;\r
b8140ab1 418 // Wait for the first bank to be sent\r
5bcc76c4 419 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
420 if (!usb_check()) return length;\r
421 }\r
3a89d04c 422 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 423 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
3a89d04c 424 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 425 }\r
426 \r
427 // Wait for the end of transfer\r
428 while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
429 if (!usb_check()) return length;\r
430 }\r
431 \r
3a89d04c 432 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
5bcc76c4 433 while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);\r
434\r
435 return length;\r
436}\r
437\r
438//*----------------------------------------------------------------------------\r
439//* \fn AT91F_USB_SendData\r
440//* \brief Send Data through the control endpoint\r
441//*----------------------------------------------------------------------------\r
5ee70129 442unsigned int csrTab[100] = {0x00};\r
5bcc76c4 443unsigned char csrIdx = 0;\r
444\r
6e82300d 445static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {\r
5bcc76c4 446 uint32_t cpt = 0;\r
447 AT91_REG csr;\r
448\r
449 do {\r
450 cpt = MIN(length, 8);\r
451 length -= cpt;\r
452\r
453 while (cpt--)\r
454 pUdp->UDP_FDR[0] = *pData++;\r
455\r
3a89d04c 456 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
457 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
458 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 459 }\r
460\r
3a89d04c 461 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 462 do {\r
3a89d04c 463 csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];\r
5bcc76c4 464\r
465 // Data IN stage has been stopped by a status OUT\r
466 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
3a89d04c 467 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 468 return;\r
469 }\r
470 } while ( !(csr & AT91C_UDP_TXCOMP) );\r
471\r
472 } while (length);\r
473\r
3a89d04c 474 if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
475 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
476 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 477 }\r
478}\r
479\r
480//*----------------------------------------------------------------------------\r
481//* \fn AT91F_USB_SendZlp\r
482//* \brief Send zero length packet through the control endpoint\r
483//*----------------------------------------------------------------------------\r
6e82300d 484void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {\r
3a89d04c 485 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
486 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) );\r
487 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
488 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);\r
5bcc76c4 489}\r
490\r
491//*----------------------------------------------------------------------------\r
492//* \fn AT91F_USB_SendStall\r
493//* \brief Stall the control endpoint\r
494//*----------------------------------------------------------------------------\r
6e82300d 495void AT91F_USB_SendStall(AT91PS_UDP pUdp) {\r
3a89d04c 496 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
497 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR) );\r
498 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
499 while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));\r
5bcc76c4 500}\r
501\r
502//*----------------------------------------------------------------------------\r
503//* \fn AT91F_CDC_Enumerate\r
504//* \brief This function is a callback invoked when a SETUP packet is received\r
505//*----------------------------------------------------------------------------\r
6e82300d 506void AT91F_CDC_Enumerate() {\r
5bcc76c4 507 byte_t bmRequestType, bRequest;\r
508 uint16_t wValue, wIndex, wLength, wStatus;\r
509\r
3a89d04c 510 if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) )\r
5bcc76c4 511 return;\r
512\r
513 bmRequestType = pUdp->UDP_FDR[0];\r
514 bRequest = pUdp->UDP_FDR[0];\r
515 wValue = (pUdp->UDP_FDR[0] & 0xFF);\r
516 wValue |= (pUdp->UDP_FDR[0] << 8);\r
517 wIndex = (pUdp->UDP_FDR[0] & 0xFF);\r
518 wIndex |= (pUdp->UDP_FDR[0] << 8);\r
519 wLength = (pUdp->UDP_FDR[0] & 0xFF);\r
520 wLength |= (pUdp->UDP_FDR[0] << 8);\r
521\r
522 if (bmRequestType & 0x80) {\r
3a89d04c 523 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
524 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) );\r
5bcc76c4 525 }\r
3a89d04c 526 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
527 while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) );\r
5bcc76c4 528\r
529 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
530 switch ((bRequest << 8) | bmRequestType) {\r
531 case STD_GET_DESCRIPTOR:\r
532 if (wValue == 0x100) // Return Device Descriptor\r
533 AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
534 else if (wValue == 0x200) // Return Configuration Descriptor\r
535 AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
1f42ccdd 536 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
537 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
538 if (strDescriptor != NULL) {\r
539 AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength));\r
540 } else {\r
541 AT91F_USB_SendStall(pUdp);\r
542 }\r
543 }\r
5bcc76c4 544 else\r
545 AT91F_USB_SendStall(pUdp);\r
546 break;\r
547 case STD_SET_ADDRESS:\r
548 AT91F_USB_SendZlp(pUdp);\r
549 pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
550 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
551 break;\r
552 case STD_SET_CONFIGURATION:\r
553 btConfiguration = wValue;\r
554 AT91F_USB_SendZlp(pUdp);\r
555 pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
556 pUdp->UDP_CSR[1] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
557 pUdp->UDP_CSR[2] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
558 pUdp->UDP_CSR[3] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
559 break;\r
560 case STD_GET_CONFIGURATION:\r
561 AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));\r
562 break;\r
563 case STD_GET_STATUS_ZERO:\r
564 wStatus = 0;\r
565 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
566 break;\r
567 case STD_GET_STATUS_INTERFACE:\r
568 wStatus = 0;\r
569 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
570 break;\r
571 case STD_GET_STATUS_ENDPOINT:\r
572 wStatus = 0;\r
573 wIndex &= 0x0F;\r
574 if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= 3)) {\r
575 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
576 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
577 }\r
578 else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == 0)) {\r
579 wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
580 AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));\r
581 }\r
582 else\r
583 AT91F_USB_SendStall(pUdp);\r
584 break;\r
585 case STD_SET_FEATURE_ZERO:\r
586 AT91F_USB_SendStall(pUdp);\r
587 break;\r
588 case STD_SET_FEATURE_INTERFACE:\r
589 AT91F_USB_SendZlp(pUdp);\r
590 break;\r
591 case STD_SET_FEATURE_ENDPOINT:\r
592 wIndex &= 0x0F;\r
593 if ((wValue == 0) && wIndex && (wIndex <= 3)) {\r
594 pUdp->UDP_CSR[wIndex] = 0;\r
595 AT91F_USB_SendZlp(pUdp);\r
596 }\r
597 else\r
598 AT91F_USB_SendStall(pUdp);\r
599 break;\r
600 case STD_CLEAR_FEATURE_ZERO:\r
601 AT91F_USB_SendStall(pUdp);\r
602 break;\r
603 case STD_CLEAR_FEATURE_INTERFACE:\r
604 AT91F_USB_SendZlp(pUdp);\r
605 break;\r
606 case STD_CLEAR_FEATURE_ENDPOINT:\r
607 wIndex &= 0x0F;\r
608 if ((wValue == 0) && wIndex && (wIndex <= 3)) {\r
609 if (wIndex == 1)\r
610 pUdp->UDP_CSR[1] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
611 else if (wIndex == 2)\r
612 pUdp->UDP_CSR[2] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
613 else if (wIndex == 3)\r
614 pUdp->UDP_CSR[3] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_ISO_IN);\r
615 AT91F_USB_SendZlp(pUdp);\r
616 }\r
617 else\r
618 AT91F_USB_SendStall(pUdp);\r
619 break;\r
620\r
621 // handle CDC class requests\r
622 case SET_LINE_CODING:\r
3a89d04c 623 while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0) );\r
624 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 625 AT91F_USB_SendZlp(pUdp);\r
626 break;\r
627 case GET_LINE_CODING:\r
628 AT91F_USB_SendData(pUdp, (char *) &line, MIN(sizeof(line), wLength));\r
629 break;\r
630 case SET_CONTROL_LINE_STATE:\r
631 btConnection = wValue;\r
632 AT91F_USB_SendZlp(pUdp);\r
633 break;\r
634 default:\r
635 AT91F_USB_SendStall(pUdp);\r
636 break;\r
637 }\r
638}\r
Impressum, Datenschutz