]> git.zerfleddert.de Git - proxmark3-svn/blame - common/usb_cdc.c
gcc10 compiler fixes:
[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
72622d64 36\r
37#include <stddef.h>\r
38#include <stdint.h>\r
39#include <stdbool.h>\r
40\r
41#include "common.h"\r
1f42ccdd 42#include "at91sam7s512.h"\r
79a73ab2 43#include "config_gpio.h"\r
5bcc76c4 44\r
3a89d04c 45#define AT91C_EP_CONTROL 0\r
5bcc76c4 46#define AT91C_EP_OUT 1\r
5bcc76c4 47#define AT91C_EP_IN 2\r
f194e429 48#define AT91C_EP_NOTIFY 3\r
49#define AT91C_EP_OUT_SIZE 0x40\r
50#define AT91C_EP_IN_SIZE 0x40\r
5bcc76c4 51\r
05b6b117
MF
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
72622d64 57\r
1f42ccdd 58static const char devDescriptor[] = {\r
5bcc76c4 59 /* Device descriptor */\r
60 0x12, // bLength\r
61 0x01, // bDescriptorType\r
1f42ccdd 62 0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)\r
f194e429 63 0x02, // bDeviceClass: (Communication Device Class)\r
64 0x00, // bDeviceSubclass: (unused at this time)\r
65 0x00, // bDeviceProtocol: (unused at this time)\r
5bcc76c4 66 0x08, // bMaxPacketSize0\r
1f42ccdd 67 0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)\r
68 0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)\r
5bcc76c4 69 0x01,0x00, // Device release number (0001)\r
05b6b117
MF
70 STR_MANUFACTURER, // iManufacturer\r
71 STR_PRODUCT, // iProduct\r
1f42ccdd 72 0x00, // iSerialNumber\r
5bcc76c4 73 0x01 // bNumConfigs\r
74};\r
75\r
72622d64 76\r
1f42ccdd 77static const char cfgDescriptor[] = {\r
5bcc76c4 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
f3803172 87 0x80, // CbmAttributes (Bus Powered)\r
88 0x4B, // CMaxPower (150mA max current drawn from bus)\r
5bcc76c4 89\r
f194e429 90 /* Interface 0 Descriptor: Communication Class Interface */\r
5bcc76c4 91 0x09, // bLength\r
92 0x04, // bDescriptorType\r
93 0x00, // bInterfaceNumber\r
94 0x00, // bAlternateSetting\r
95 0x01, // bNumEndpoints\r
f194e429 96 0x02, // bInterfaceClass: Communication Interface Class\r
97 0x02, // bInterfaceSubclass: Abstract Control Model\r
98 0x01, // bInterfaceProtocol: Common AT Commands, V.25ter\r
5bcc76c4 99 0x00, // iInterface\r
100\r
101 /* Header Functional Descriptor */\r
102 0x05, // bFunction Length\r
f194e429 103 0x24, // bDescriptor type: CS_INTERFACE\r
104 0x00, // bDescriptor subtype: Header Functional Descriptor\r
5bcc76c4 105 0x10, // bcdCDC:1.1\r
106 0x01,\r
107\r
108 /* ACM Functional Descriptor */\r
109 0x04, // bFunctionLength\r
f194e429 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
5bcc76c4 113\r
114 /* Union Functional Descriptor */\r
115 0x05, // bFunctionLength\r
f194e429 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
5bcc76c4 120\r
121 /* Call Management Functional Descriptor */\r
122 0x05, // bFunctionLength\r
f194e429 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
5bcc76c4 127\r
128 /* Endpoint 1 descriptor */\r
129 0x07, // bLength\r
130 0x05, // bDescriptorType\r
f194e429 131 0x83, // bEndpointAddress: Endpoint 03 - IN\r
132 0x03, // bmAttributes: INT\r
133 0x08, // wMaxPacketSize: 8\r
5bcc76c4 134 0x00,\r
135 0xFF, // bInterval\r
136\r
f194e429 137 /* Interface 1 Descriptor: Data Class Interface */\r
5bcc76c4 138 0x09, // bLength\r
139 0x04, // bDescriptorType\r
140 0x01, // bInterfaceNumber\r
141 0x00, // bAlternateSetting\r
142 0x02, // bNumEndpoints\r
f194e429 143 0x0A, // bInterfaceClass: Data Interface Class\r
144 0x00, // bInterfaceSubclass: not used\r
145 0x00, // bInterfaceProtocol: No class specific protocol required)\r
5bcc76c4 146 0x00, // iInterface\r
147\r
5bcc76c4 148 /* Endpoint 1 descriptor */\r
149 0x07, // bLength\r
150 0x05, // bDescriptorType\r
f194e429 151 0x01, // bEndpointAddress: Endpoint 01 - OUT\r
152 0x02, // bmAttributes: BULK\r
153 AT91C_EP_OUT_SIZE, // wMaxPacketSize\r
5bcc76c4 154 0x00,\r
155 0x00, // bInterval\r
156\r
157 /* Endpoint 2 descriptor */\r
158 0x07, // bLength\r
159 0x05, // bDescriptorType\r
f194e429 160 0x82, // bEndpointAddress: Endpoint 02 - IN\r
161 0x02, // bmAttributes: BULK\r
5bcc76c4 162 AT91C_EP_IN_SIZE, // wMaxPacketSize\r
163 0x00,\r
164 0x00 // bInterval\r
165};\r
166\r
72622d64 167\r
1f42ccdd 168static const char StrDescLanguageCodes[] = {\r
72622d64 169 4, // Length\r
170 0x03, // Type is string\r
171 0x09, 0x04 // supported language Code 0 = 0x0409 (English)\r
1f42ccdd 172};\r
05b6b117 173\r
72622d64 174\r
05b6b117
MF
175// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the\r
176// manufacturer string "proxmark.org". Don't change this.\r
1f42ccdd 177static const char StrDescManufacturer[] = {\r
72622d64 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
1f42ccdd 192};\r
193\r
72622d64 194\r
1f42ccdd 195static const char StrDescProduct[] = {\r
72622d64 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
1f42ccdd 207};\r
5bcc76c4 208\r
72622d64 209\r
867e10a5 210static const char* getStringDescriptor(uint8_t idx) {\r
05b6b117
MF
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
1f42ccdd 220 }\r
221}\r
5bcc76c4 222\r
72622d64 223\r
3a89d04c 224// Bitmap for all status bits in CSR which must be written as 1 to cause no effect\r
929b61c6 225#define REG_NO_EFFECT_1_ALL (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_TXCOMP)\r
72622d64 226\r
3a89d04c 227\r
228// Clear flags in the UDP_CSR register\r
229#define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \\r
230 volatile unsigned int reg; \\r
929b61c6 231 reg = AT91C_BASE_UDP->UDP_CSR[(endpoint)]; \\r
3a89d04c 232 reg |= REG_NO_EFFECT_1_ALL; \\r
233 reg &= ~(flags); \\r
929b61c6 234 AT91C_BASE_UDP->UDP_CSR[(endpoint)] = reg; \\r
72622d64 235}\r
236\r
3a89d04c 237\r
238// Set flags in the UDP_CSR register\r
239#define UDP_SET_EP_FLAGS(endpoint, flags) { \\r
240 volatile unsigned int reg; \\r
929b61c6 241 reg = AT91C_BASE_UDP->UDP_CSR[(endpoint)]; \\r
3a89d04c 242 reg |= REG_NO_EFFECT_1_ALL; \\r
243 reg |= (flags); \\r
929b61c6 244 AT91C_BASE_UDP->UDP_CSR[(endpoint)] = reg; \\r
3a89d04c 245}\r
246\r
72622d64 247\r
3a89d04c 248/* USB standard request codes */\r
5bcc76c4 249#define STD_GET_STATUS_ZERO 0x0080\r
250#define STD_GET_STATUS_INTERFACE 0x0081\r
251#define STD_GET_STATUS_ENDPOINT 0x0082\r
252\r
253#define STD_CLEAR_FEATURE_ZERO 0x0100\r
254#define STD_CLEAR_FEATURE_INTERFACE 0x0101\r
255#define STD_CLEAR_FEATURE_ENDPOINT 0x0102\r
256\r
257#define STD_SET_FEATURE_ZERO 0x0300\r
258#define STD_SET_FEATURE_INTERFACE 0x0301\r
259#define STD_SET_FEATURE_ENDPOINT 0x0302\r
260\r
261#define STD_SET_ADDRESS 0x0500\r
262#define STD_GET_DESCRIPTOR 0x0680\r
263#define STD_SET_DESCRIPTOR 0x0700\r
264#define STD_GET_CONFIGURATION 0x0880\r
265#define STD_SET_CONFIGURATION 0x0900\r
266#define STD_GET_INTERFACE 0x0A81\r
267#define STD_SET_INTERFACE 0x0B01\r
268#define STD_SYNCH_FRAME 0x0C82\r
269\r
270/* CDC Class Specific Request Code */\r
271#define GET_LINE_CODING 0x21A1\r
272#define SET_LINE_CODING 0x2021\r
273#define SET_CONTROL_LINE_STATE 0x2221\r
274\r
72622d64 275\r
5bcc76c4 276typedef struct {\r
277 unsigned int dwDTERRate;\r
278 char bCharFormat;\r
279 char bParityType;\r
280 char bDataBits;\r
281} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;\r
282\r
72622d64 283\r
929b61c6 284static AT91S_CDC_LINE_CODING line = {\r
5bcc76c4 285 115200, // baudrate\r
286 0, // 1 Stop Bit\r
287 0, // None Parity\r
288 8}; // 8 Data bits\r
289\r
f194e429 290\r
929b61c6 291static uint8_t btConfiguration = 0;\r
292static uint8_t btConnection = 0;\r
293static uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;\r
5bcc76c4 294\r
f194e429 295\r
6e82300d 296//*----------------------------------------------------------------------------\r
79a73ab2 297//* \fn usb_disable\r
6e82300d 298//* \brief This function deactivates the USB device\r
299//*----------------------------------------------------------------------------\r
300void usb_disable() {\r
f194e429 301 // Disconnect the USB device\r
302 AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;\r
303\r
304 // Clear all lingering interrupts\r
929b61c6 305 if (AT91C_BASE_UDP->UDP_ISR & AT91C_UDP_ENDBUSRES) {\r
306 AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
f194e429 307 }\r
6e82300d 308}\r
309\r
f194e429 310\r
5bcc76c4 311//*----------------------------------------------------------------------------\r
79a73ab2 312//* \fn usb_enable\r
5bcc76c4 313//* \brief This function Activates the USB device\r
314//*----------------------------------------------------------------------------\r
6e82300d 315void usb_enable() {\r
f194e429 316 // Set the PLL USB Divider\r
317 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;\r
318\r
319 // Specific Chip USB Initialisation\r
320 // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock\r
321 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;\r
322 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);\r
323\r
324 // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO\r
325 // Set in PIO mode and Configure in Output\r
326 AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode\r
79a73ab2 327 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output\r
f194e429 328\r
329 // Clear for set the Pullup resistor\r
79a73ab2 330 AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;\r
6e82300d 331\r
f194e429 332 // Disconnect and reconnect USB controller for 100ms\r
333 usb_disable();\r
334\r
335 // Wait for a short while\r
72622d64 336 for (volatile size_t i = 0; i < 0x100000; i++);\r
f194e429 337\r
338 // Reconnect USB reconnect\r
339 AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;\r
340 AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;\r
5bcc76c4 341}\r
342\r
f194e429 343\r
5bcc76c4 344//*----------------------------------------------------------------------------\r
929b61c6 345//* \fn AT91F_USB_SendZlp\r
346//* \brief Send zero length packet through an endpoint\r
5bcc76c4 347//*----------------------------------------------------------------------------\r
929b61c6 348static void AT91F_USB_SendZlp(uint8_t endpoint) {\r
349 UDP_SET_EP_FLAGS(endpoint, AT91C_UDP_TXPKTRDY);\r
350 while (!(AT91C_BASE_UDP->UDP_CSR[endpoint] & AT91C_UDP_TXCOMP))\r
351 /* wait */;\r
352 UDP_CLEAR_EP_FLAGS(endpoint, AT91C_UDP_TXCOMP);\r
353 while (AT91C_BASE_UDP->UDP_CSR[endpoint] & AT91C_UDP_TXCOMP)\r
72622d64 354 /* wait */;\r
5bcc76c4 355}\r
356\r
f194e429 357\r
5bcc76c4 358//*----------------------------------------------------------------------------\r
359//* \fn AT91F_USB_SendData\r
360//* \brief Send Data through the control endpoint\r
361//*----------------------------------------------------------------------------\r
929b61c6 362static void AT91F_USB_SendData(const char *pData, uint32_t length) {\r
5bcc76c4 363 uint32_t cpt = 0;\r
364 AT91_REG csr;\r
365\r
366 do {\r
367 cpt = MIN(length, 8);\r
368 length -= cpt;\r
369\r
370 while (cpt--)\r
929b61c6 371 AT91C_BASE_UDP->UDP_FDR[0] = *pData++;\r
5bcc76c4 372\r
929b61c6 373 if (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
3a89d04c 374 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
929b61c6 375 while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
72622d64 376 /* wait */;\r
5bcc76c4 377 }\r
378\r
3a89d04c 379 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);\r
5bcc76c4 380 do {\r
929b61c6 381 csr = AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL];\r
5bcc76c4 382\r
383 // Data IN stage has been stopped by a status OUT\r
384 if (csr & AT91C_UDP_RX_DATA_BK0) {\r
3a89d04c 385 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
5bcc76c4 386 return;\r
387 }\r
72622d64 388 } while (!(csr & AT91C_UDP_TXCOMP));\r
5bcc76c4 389\r
390 } while (length);\r
391\r
929b61c6 392 if (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) {\r
3a89d04c 393 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP);\r
929b61c6 394 while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP)\r
72622d64 395 /* wait */;\r
5bcc76c4 396 }\r
397}\r
398\r
f194e429 399\r
5bcc76c4 400//*----------------------------------------------------------------------------\r
401//* \fn AT91F_USB_SendStall\r
402//* \brief Stall the control endpoint\r
403//*----------------------------------------------------------------------------\r
929b61c6 404static void AT91F_USB_SendStall(void) {\r
3a89d04c 405 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL);\r
929b61c6 406 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR))\r
72622d64 407 /* wait */;\r
3a89d04c 408 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);\r
929b61c6 409 while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR))\r
72622d64 410 /* wait */;\r
5bcc76c4 411}\r
412\r
f194e429 413\r
5bcc76c4 414//*----------------------------------------------------------------------------\r
415//* \fn AT91F_CDC_Enumerate\r
416//* \brief This function is a callback invoked when a SETUP packet is received\r
417//*----------------------------------------------------------------------------\r
867e10a5 418static void AT91F_CDC_Enumerate() {\r
72622d64 419 uint8_t bmRequestType, bRequest;\r
5bcc76c4 420 uint16_t wValue, wIndex, wLength, wStatus;\r
421\r
929b61c6 422 if (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP))\r
5bcc76c4 423 return;\r
424\r
929b61c6 425 bmRequestType = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL];\r
426 bRequest = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL];\r
427 wValue = (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
428 wValue |= (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
429 wIndex = (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
430 wIndex |= (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
431 wLength = (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);\r
432 wLength |= (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] << 8);\r
5bcc76c4 433\r
72622d64 434 if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host\r
3a89d04c 435 UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);\r
929b61c6 436 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR))\r
72622d64 437 /* wait */;\r
5bcc76c4 438 }\r
3a89d04c 439 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP);\r
929b61c6 440 while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP)\r
72622d64 441 /* wait */;\r
5bcc76c4 442\r
443 // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1\r
444 switch ((bRequest << 8) | bmRequestType) {\r
445 case STD_GET_DESCRIPTOR:\r
446 if (wValue == 0x100) // Return Device Descriptor\r
929b61c6 447 AT91F_USB_SendData(devDescriptor, MIN(sizeof(devDescriptor), wLength));\r
5bcc76c4 448 else if (wValue == 0x200) // Return Configuration Descriptor\r
929b61c6 449 AT91F_USB_SendData(cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength));\r
1f42ccdd 450 else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor\r
451 const char *strDescriptor = getStringDescriptor(wValue & 0xff);\r
452 if (strDescriptor != NULL) {\r
929b61c6 453 AT91F_USB_SendData(strDescriptor, MIN(strDescriptor[0], wLength));\r
1f42ccdd 454 } else {\r
929b61c6 455 AT91F_USB_SendStall();\r
1f42ccdd 456 }\r
457 }\r
5bcc76c4 458 else\r
929b61c6 459 AT91F_USB_SendStall();\r
5bcc76c4 460 break;\r
461 case STD_SET_ADDRESS:\r
929b61c6 462 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
463 AT91C_BASE_UDP->UDP_FADDR = (AT91C_UDP_FEN | wValue);\r
464 AT91C_BASE_UDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;\r
5bcc76c4 465 break;\r
466 case STD_SET_CONFIGURATION:\r
467 btConfiguration = wValue;\r
929b61c6 468 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
469 AT91C_BASE_UDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;\r
470 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;\r
471 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;\r
472 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;\r
5bcc76c4 473 break;\r
474 case STD_GET_CONFIGURATION:\r
929b61c6 475 AT91F_USB_SendData((char *) &(btConfiguration), sizeof(btConfiguration));\r
5bcc76c4 476 break;\r
477 case STD_GET_STATUS_ZERO:\r
72622d64 478 wStatus = 0; // Device is Bus powered, remote wakeup disabled\r
929b61c6 479 AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus));\r
5bcc76c4 480 break;\r
481 case STD_GET_STATUS_INTERFACE:\r
72622d64 482 wStatus = 0; // reserved for future use\r
929b61c6 483 AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus));\r
5bcc76c4 484 break;\r
485 case STD_GET_STATUS_ENDPOINT:\r
486 wStatus = 0;\r
487 wIndex &= 0x0F;\r
929b61c6 488 if ((AT91C_BASE_UDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {\r
489 wStatus = (AT91C_BASE_UDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
490 AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus));\r
491 } else if ((AT91C_BASE_UDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {\r
492 wStatus = (AT91C_BASE_UDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;\r
493 AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus));\r
72622d64 494 } else\r
929b61c6 495 AT91F_USB_SendStall();\r
5bcc76c4 496 break;\r
497 case STD_SET_FEATURE_ZERO:\r
929b61c6 498 AT91F_USB_SendStall();\r
72622d64 499 break;\r
5bcc76c4 500 case STD_SET_FEATURE_INTERFACE:\r
929b61c6 501 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
5bcc76c4 502 break;\r
503 case STD_SET_FEATURE_ENDPOINT:\r
504 wIndex &= 0x0F;\r
f194e429 505 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
929b61c6 506 AT91C_BASE_UDP->UDP_CSR[wIndex] = 0;\r
507 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
72622d64 508 } else\r
929b61c6 509 AT91F_USB_SendStall();\r
5bcc76c4 510 break;\r
511 case STD_CLEAR_FEATURE_ZERO:\r
929b61c6 512 AT91F_USB_SendStall();\r
72622d64 513 break;\r
5bcc76c4 514 case STD_CLEAR_FEATURE_INTERFACE:\r
929b61c6 515 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
5bcc76c4 516 break;\r
517 case STD_CLEAR_FEATURE_ENDPOINT:\r
518 wIndex &= 0x0F;\r
f194e429 519 if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {\r
520 if (wIndex == AT91C_EP_OUT)\r
929b61c6 521 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);\r
f194e429 522 else if (wIndex == AT91C_EP_IN)\r
929b61c6 523 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);\r
f194e429 524 else if (wIndex == AT91C_EP_NOTIFY)\r
929b61c6 525 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);\r
526 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
5bcc76c4 527 }\r
528 else\r
929b61c6 529 AT91F_USB_SendStall();\r
5bcc76c4 530 break;\r
531\r
532 // handle CDC class requests\r
533 case SET_LINE_CODING:\r
929b61c6 534 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0))\r
72622d64 535 /* wait */;\r
3a89d04c 536 UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0);\r
929b61c6 537 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
5bcc76c4 538 break;\r
539 case GET_LINE_CODING:\r
929b61c6 540 AT91F_USB_SendData((char *) &line, MIN(sizeof(line), wLength));\r
5bcc76c4 541 break;\r
542 case SET_CONTROL_LINE_STATE:\r
543 btConnection = wValue;\r
929b61c6 544 AT91F_USB_SendZlp(AT91C_EP_CONTROL);\r
5bcc76c4 545 break;\r
546 default:\r
929b61c6 547 AT91F_USB_SendStall();\r
72622d64 548 break;\r
5bcc76c4 549 }\r
550}\r
867e10a5 551\r
552\r
929b61c6 553//*----------------------------------------------------------------------------\r
554//* \fn usb_check\r
555//* \brief Test if the device is configured and handle enumeration\r
556//*----------------------------------------------------------------------------\r
557static bool usb_check() {\r
558 AT91_REG isr = AT91C_BASE_UDP->UDP_ISR;\r
559\r
560 if (isr & AT91C_UDP_ENDBUSRES) {\r
561 AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES;\r
562 // reset all endpoints\r
563 AT91C_BASE_UDP->UDP_RSTEP = (unsigned int)-1;\r
564 AT91C_BASE_UDP->UDP_RSTEP = 0;\r
565 // Enable the function\r
566 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;\r
567 // Configure endpoint 0\r
568 AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);\r
569 } else if (isr & AT91C_UDP_EPINT0) {\r
570 AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_EPINT0;\r
571 AT91F_CDC_Enumerate();\r
572 }\r
573 return (btConfiguration) ? true : false;\r
574}\r
575\r
576\r
577bool usb_poll() {\r
578 if (!usb_check()) return false;\r
579 return (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);\r
580}\r
581\r
582\r
583/**\r
584 In github PR #129, some users appears to get a false positive from\r
585 usb_poll, which returns true, but the usb_read operation\r
586 still returns 0.\r
587 This check is basically the same as above, but also checks\r
588 that the length available to read is non-zero, thus hopefully fixes the\r
589 bug.\r
590**/\r
591bool usb_poll_validate_length() {\r
592 if (!usb_check()) return false;\r
593 if (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;\r
594 return (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;\r
595}\r
596\r
597\r
598//*----------------------------------------------------------------------------\r
599//* \fn usb_read\r
600//* \brief Read available data from Endpoint OUT\r
601//*----------------------------------------------------------------------------\r
602static uint32_t usb_read(uint8_t* data, size_t len) {\r
603 uint8_t bank = btReceiveBank;\r
604 uint32_t packetSize, nbBytesRcv = 0;\r
605 uint32_t time_out = 0;\r
606\r
607 while (len) {\r
608 if (!usb_check()) break;\r
609\r
610 if ( AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & bank ) {\r
611 packetSize = MIN(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] >> 16, len);\r
612 len -= packetSize;\r
613 while (packetSize--)\r
614 data[nbBytesRcv++] = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_OUT];\r
615 UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank);\r
616 if (bank == AT91C_UDP_RX_DATA_BK0) {\r
617 bank = AT91C_UDP_RX_DATA_BK1;\r
618 } else {\r
619 bank = AT91C_UDP_RX_DATA_BK0;\r
620 }\r
621 }\r
622 if (time_out++ == 0x1fff) break;\r
623 }\r
624\r
625 btReceiveBank = bank;\r
626 return nbBytesRcv;\r
627}\r
628\r
629\r
630//*----------------------------------------------------------------------------\r
631//* \fn usb_write\r
632//* \brief Send through endpoint 2\r
633//*----------------------------------------------------------------------------\r
634static uint32_t usb_write(const uint8_t* data, const size_t len) {\r
635 size_t length = len;\r
636 uint32_t cpt = 0;\r
637\r
638 if (!length) return 0;\r
639 if (!usb_check()) return 0;\r
640\r
641 // Send the first packet\r
642 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
643 length -= cpt;\r
644 while (cpt--) {\r
645 AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *data++;\r
646 }\r
647 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
648 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))\r
649 /* wait */;\r
650\r
651 while (length) {\r
652 // Fill the next bank\r
653 cpt = MIN(length, AT91C_EP_IN_SIZE);\r
654 length -= cpt;\r
655 while (cpt--) {\r
656 AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *data++;\r
657 }\r
658 // Wait for the previous bank to be sent\r
659 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
660 if (!usb_check()) return length;\r
661 }\r
662 UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);\r
663 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY))\r
664 /* wait */;\r
665 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
666 while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)\r
667 /* wait */;\r
668 }\r
669\r
670 // Wait for the end of transfer\r
671 while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {\r
672 if (!usb_check()) return length;\r
673 }\r
674 UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);\r
675 while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)\r
676 /* wait */;\r
677\r
678 if (len % AT91C_EP_IN_SIZE == 0) { // need to send a zero length packet to complete the transfer\r
679 AT91F_USB_SendZlp(AT91C_EP_IN);\r
680 }\r
681\r
682 return length;\r
683}\r
684\r
685\r
867e10a5 686//***************************************************************************\r
687// Interface to the main program\r
688//***************************************************************************\r
689\r
690// The function to receive a command from the client via USB\r
691bool cmd_receive(UsbCommand* cmd) {\r
692\r
693 // Check if there is a usb packet available\r
694 if (!usb_poll())\r
695 return false;\r
696\r
697 // Try to retrieve the available command frame\r
698 size_t rxlen = usb_read((uint8_t*)cmd, sizeof(UsbCommand));\r
699\r
700 // Check if the transfer was complete\r
701 if (rxlen != sizeof(UsbCommand))\r
702 return false;\r
703\r
704 // Received command successfully\r
705 return true;\r
706}\r
707\r
708\r
709// The function to send a response to the client via USB\r
b8ed9975 710bool cmd_send(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) {\r
711\r
712 UsbResponse txcmd;\r
713\r
714 // Compose the outgoing response frame\r
715 txcmd.cmd = cmd | CMD_VARIABLE_SIZE_FLAG;\r
716 txcmd.arg[0] = arg0;\r
717 txcmd.arg[1] = arg1;\r
718 txcmd.arg[2] = arg2;\r
867e10a5 719\r
b8ed9975 720 // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE\r
721 if (data) {\r
722 datalen = MIN(datalen, USB_CMD_DATA_SIZE);\r
723 for (uint16_t i = 0; i < datalen; i++) {\r
724 txcmd.d.asBytes[i] = ((uint8_t*)data)[i];\r
725 }\r
726 txcmd.datalen = datalen;\r
727 } else {\r
728 txcmd.datalen = 0;\r
867e10a5 729 }\r
730\r
b8ed9975 731 // Send frame and make sure all bytes are transmitted\r
732 size_t tx_size = offsetof(UsbResponse, d) + datalen;\r
733 if (usb_write((uint8_t*)&txcmd, tx_size) != 0) return false;\r
734\r
735 return true;\r
736}\r
737\r
738\r
739// For compatibility only: legacy function to send a response with fixed size to the client via USB\r
740bool cmd_send_old(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) {\r
741\r
742 UsbCommand txcmd;\r
743\r
744 // Compose the outgoing response frame\r
867e10a5 745 txcmd.cmd = cmd;\r
746 txcmd.arg[0] = arg0;\r
747 txcmd.arg[1] = arg1;\r
748 txcmd.arg[2] = arg2;\r
749\r
750 // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE\r
b8ed9975 751 if (data) {\r
752 datalen = MIN(datalen, USB_CMD_DATA_SIZE);\r
753 for (uint16_t i = 0; i < datalen; i++) {\r
867e10a5 754 txcmd.d.asBytes[i] = ((uint8_t*)data)[i];\r
755 }\r
756 }\r
929b61c6 757\r
867e10a5 758 // Send frame and make sure all bytes are transmitted\r
759 if (usb_write((uint8_t*)&txcmd, sizeof(UsbCommand)) != 0) return false;\r
760\r
761 return true;\r
762}\r
b8ed9975 763\r
Impressum, Datenschutz