1 /*
2 * Copyright (c) 2024, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbd_core.h"
7 #include "usbd_cdc_acm.h"
8
9 #define WINUSB_IN_EP 0x81
10 #define WINUSB_OUT_EP 0x02
11
12 #define CDC_IN_EP 0x83
13 #define CDC_OUT_EP 0x04
14 #define CDC_INT_EP 0x85
15
16 #define USBD_VID 0xFFFE
17 #define USBD_PID 0xFFFF
18 #define USBD_MAX_POWER 500
19 #define USBD_LANGID_STRING 1033
20
21 #define USB_CONFIG_SIZE (9 + 9 + 7 + 7 + CDC_ACM_DESCRIPTOR_LEN)
22 #define INTF_NUM 3
23
24 #ifdef CONFIG_USB_HS
25 #define WINUSB_EP_MPS 512
26 #else
27 #define WINUSB_EP_MPS 64
28 #endif
29
30 #define USBD_WINUSB_VENDOR_CODE 0x20
31
32 #define USBD_WEBUSB_ENABLE 0
33 #define USBD_BULK_ENABLE 1
34 #define USBD_WINUSB_ENABLE 1
35
36 /* WinUSB Microsoft OS 2.0 descriptor sizes */
37 #define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10
38 #define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
39 #define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20
40
41 #define FUNCTION_SUBSET_LEN 160
42 #define DEVICE_INTERFACE_GUIDS_FEATURE_LEN 132
43
44 #define USBD_WINUSB_DESC_SET_LEN (WINUSB_DESCRIPTOR_SET_HEADER_SIZE + USBD_WEBUSB_ENABLE * FUNCTION_SUBSET_LEN + USBD_BULK_ENABLE * FUNCTION_SUBSET_LEN)
45
46 __ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[] = {
47 WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */
48 WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */
49 0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
50 WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
51 #if (USBD_WEBUSB_ENABLE)
52 WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), // wLength
53 WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), // wDescriptorType
54 0, // bFirstInterface USBD_WINUSB_IF_NUM
55 0, // bReserved
56 WBVAL(FUNCTION_SUBSET_LEN), // wSubsetLength
57 WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), // wLength
58 WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), // wDescriptorType
59 'W', 'I', 'N', 'U', 'S', 'B', 0, 0, // CompatibleId
60 0, 0, 0, 0, 0, 0, 0, 0, // SubCompatibleId
61 WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), // wLength
62 WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), // wDescriptorType
63 WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), // wPropertyDataType
64 WBVAL(42), // wPropertyNameLength
65 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
66 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
67 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
68 WBVAL(80), // wPropertyDataLength
69 '{', 0,
70 '9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0,
71 '9', 0, 'C', 0, '7', 0, '7', 0, '-', 0,
72 '4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0,
73 '9', 0, '3', 0, '3', 0, 'B', 0, '-',
74 0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, '9', 0,
75 '}', 0, 0, 0, 0, 0
76 #endif
77 #if USBD_BULK_ENABLE
78 WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */
79 WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */
80 0, /* bFirstInterface USBD_BULK_IF_NUM*/
81 0, /* bReserved */
82 WBVAL(FUNCTION_SUBSET_LEN), /* wSubsetLength */
83 WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */
84 WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */
85 'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/
86 0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/
87 WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), /* wLength */
88 WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */
89 WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */
90 WBVAL(42), /* wPropertyNameLength */
91 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
92 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
93 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
94 WBVAL(80), /* wPropertyDataLength */
95 '{', 0,
96 'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0,
97 '2', 0, '9', 0, '3', 0, 'B', 0, '-', 0,
98 '4', 0, '6', 0, '6', 0, '3', 0, '-', 0,
99 'A', 0, 'A', 0, '3', 0, '6', 0, '-',
100 0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0,
101 '}', 0, 0, 0, 0, 0
102 #endif
103 };
104
105 #define USBD_NUM_DEV_CAPABILITIES (USBD_WEBUSB_ENABLE + USBD_WINUSB_ENABLE)
106
107 #define USBD_WEBUSB_DESC_LEN 24
108 #define USBD_WINUSB_DESC_LEN 28
109
110 #define USBD_BOS_WTOTALLENGTH (0x05 + \
111 USBD_WEBUSB_DESC_LEN * USBD_WEBUSB_ENABLE + \
112 USBD_WINUSB_DESC_LEN * USBD_WINUSB_ENABLE)
113
114 __ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[] = {
115 0x05, /* bLength */
116 0x0f, /* bDescriptorType */
117 WBVAL(USBD_BOS_WTOTALLENGTH), /* wTotalLength */
118 USBD_NUM_DEV_CAPABILITIES, /* bNumDeviceCaps */
119 #if (USBD_WEBUSB_ENABLE)
120 USBD_WEBUSB_DESC_LEN, /* bLength */
121 0x10, /* bDescriptorType */
122 USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
123 0x00, /* bReserved */
124 0x38, 0xB6, 0x08, 0x34, /* PlatformCapabilityUUID */
125 0xA9, 0x09, 0xA0, 0x47,
126 0x8B, 0xFD, 0xA0, 0x76,
127 0x88, 0x15, 0xB6, 0x65,
128 WBVAL(0x0100), /* 1.00 */ /* bcdVersion */
129 USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
130 0, /* iLandingPage */
131 #endif
132 #if (USBD_WINUSB_ENABLE)
133 USBD_WINUSB_DESC_LEN, /* bLength */
134 0x10, /* bDescriptorType */
135 USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
136 0x00, /* bReserved */
137 0xDF, 0x60, 0xDD, 0xD8, /* PlatformCapabilityUUID */
138 0x89, 0x45, 0xC7, 0x4C,
139 0x9C, 0xD2, 0x65, 0x9D,
140 0x9E, 0x64, 0x8A, 0x9F,
141 0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
142 WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
143 USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
144 0, /* bAltEnumCode */
145 #endif
146 };
147
148 struct usb_msosv2_descriptor msosv2_desc = {
149 .vendor_code = USBD_WINUSB_VENDOR_CODE,
150 .compat_id = USBD_WinUSBDescriptorSetDescriptor,
151 .compat_id_len = USBD_WINUSB_DESC_SET_LEN,
152 };
153
154 struct usb_bos_descriptor bos_desc = {
155 .string = USBD_BinaryObjectStoreDescriptor,
156 .string_len = USBD_BOS_WTOTALLENGTH
157 };
158
159 #ifdef CONFIG_USBDEV_ADVANCE_DESC
160 static const uint8_t device_descriptor[] = {
161 USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
162 };
163
164 static const uint8_t config_descriptor[] = {
165 /* Configuration 0 */
166 USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
167 /* Interface 0 */
168 USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
169 /* Endpoint OUT 2 */
170 USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
171 /* Endpoint IN 1 */
172 USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
173 CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, WINUSB_EP_MPS, 0x00)
174 };
175
176 static const uint8_t device_quality_descriptor[] = {
177 ///////////////////////////////////////
178 /// device qualifier descriptor
179 ///////////////////////////////////////
180 0x0a,
181 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
182 0x10,
183 0x02,
184 0x00,
185 0x00,
186 0x00,
187 0x40,
188 0x00,
189 0x00,
190 };
191
192 static const char *string_descriptors[] = {
193 (const char[]){ 0x09, 0x04 }, /* Langid */
194 "CherryUSB", /* Manufacturer */
195 "CherryUSB WINUSB DEMO", /* Product */
196 "2022123456", /* Serial Number */
197 };
198
device_descriptor_callback(uint8_t speed)199 static const uint8_t *device_descriptor_callback(uint8_t speed)
200 {
201 return device_descriptor;
202 }
203
config_descriptor_callback(uint8_t speed)204 static const uint8_t *config_descriptor_callback(uint8_t speed)
205 {
206 return config_descriptor;
207 }
208
device_quality_descriptor_callback(uint8_t speed)209 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
210 {
211 return device_quality_descriptor;
212 }
213
string_descriptor_callback(uint8_t speed,uint8_t index)214 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
215 {
216 if (index > 3) {
217 return NULL;
218 }
219 return string_descriptors[index];
220 }
221
222 const struct usb_descriptor winusbv2_descriptor = {
223 .device_descriptor_callback = device_descriptor_callback,
224 .config_descriptor_callback = config_descriptor_callback,
225 .device_quality_descriptor_callback = device_quality_descriptor_callback,
226 .string_descriptor_callback = string_descriptor_callback,
227 .msosv2_descriptor = &msosv2_desc,
228 .bos_descriptor = &bos_desc
229 };
230 #else
231 const uint8_t winusbv2_descriptor[] = {
232 USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
233 /* Configuration 0 */
234 USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
235 /* Interface 0 */
236 USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
237 /* Endpoint OUT 2 */
238 USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
239 /* Endpoint IN 1 */
240 USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
241 CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, WINUSB_EP_MPS, 0x00),
242 /* String 0 (LANGID) */
243 USB_LANGID_INIT(USBD_LANGID_STRING),
244 /* String 1 (Manufacturer) */
245 0x14, /* bLength */
246 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
247 'C', 0x00, /* wcChar0 */
248 'h', 0x00, /* wcChar1 */
249 'e', 0x00, /* wcChar2 */
250 'r', 0x00, /* wcChar3 */
251 'r', 0x00, /* wcChar4 */
252 'y', 0x00, /* wcChar5 */
253 'U', 0x00, /* wcChar6 */
254 'S', 0x00, /* wcChar7 */
255 'B', 0x00, /* wcChar8 */
256 ///////////////////////////////////////
257 /// string2 descriptor
258 ///////////////////////////////////////
259 0x2C, /* bLength */
260 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
261 'C', 0x00, /* wcChar0 */
262 'h', 0x00, /* wcChar1 */
263 'e', 0x00, /* wcChar2 */
264 'r', 0x00, /* wcChar3 */
265 'r', 0x00, /* wcChar4 */
266 'y', 0x00, /* wcChar5 */
267 'U', 0x00, /* wcChar6 */
268 'S', 0x00, /* wcChar7 */
269 'B', 0x00, /* wcChar8 */
270 ' ', 0x00, /* wcChar9 */
271 'W', 0x00, /* wcChar10 */
272 'I', 0x00, /* wcChar11 */
273 'N', 0x00, /* wcChar12 */
274 'U', 0x00, /* wcChar13 */
275 'S', 0x00, /* wcChar14 */
276 'B', 0x00, /* wcChar15 */
277 ' ', 0x00, /* wcChar16 */
278 'D', 0x00, /* wcChar17 */
279 'E', 0x00, /* wcChar18 */
280 'M', 0x00, /* wcChar19 */
281 'O', 0x00, /* wcChar20 */
282 ///////////////////////////////////////
283 /// string3 descriptor
284 ///////////////////////////////////////
285 0x16, /* bLength */
286 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
287 '2', 0x00, /* wcChar0 */
288 '0', 0x00, /* wcChar1 */
289 '2', 0x00, /* wcChar2 */
290 '2', 0x00, /* wcChar3 */
291 '1', 0x00, /* wcChar4 */
292 '2', 0x00, /* wcChar5 */
293 '3', 0x00, /* wcChar6 */
294 '4', 0x00, /* wcChar7 */
295 '5', 0x00, /* wcChar8 */
296 '6', 0x00, /* wcChar9 */
297 #ifdef CONFIG_USB_HS
298 /* Device Qualifier */
299 0x0a,
300 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
301 0x10,
302 0x02,
303 0x00,
304 0x00,
305 0x00,
306 0x40,
307 0x00,
308 0x00,
309 #endif
310 /* End */
311 0x00
312 };
313 #endif
314
315 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048];
316 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
317
318 volatile bool ep_tx_busy_flag = false;
319
usbd_event_handler(uint8_t busid,uint8_t event)320 static void usbd_event_handler(uint8_t busid, uint8_t event)
321 {
322 switch (event) {
323 case USBD_EVENT_RESET:
324 break;
325 case USBD_EVENT_CONNECTED:
326 break;
327 case USBD_EVENT_DISCONNECTED:
328 break;
329 case USBD_EVENT_RESUME:
330 break;
331 case USBD_EVENT_SUSPEND:
332 break;
333 case USBD_EVENT_CONFIGURED:
334 ep_tx_busy_flag = false;
335 /* setup first out ep read transfer */
336 usbd_ep_start_read(busid, WINUSB_OUT_EP, read_buffer, 2048);
337 usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
338 break;
339 case USBD_EVENT_SET_REMOTE_WAKEUP:
340 break;
341 case USBD_EVENT_CLR_REMOTE_WAKEUP:
342 break;
343
344 default:
345 break;
346 }
347 }
348
usbd_winusb_out(uint8_t busid,uint8_t ep,uint32_t nbytes)349 void usbd_winusb_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
350 {
351 USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
352 // for (int i = 0; i < 100; i++) {
353 // printf("%02x ", read_buffer[i]);
354 // }
355 // printf("\r\n");
356 usbd_ep_start_write(busid, WINUSB_IN_EP, read_buffer, nbytes);
357 /* setup next out ep read transfer */
358 usbd_ep_start_read(busid, WINUSB_OUT_EP, read_buffer, 2048);
359 }
360
usbd_winusb_in(uint8_t busid,uint8_t ep,uint32_t nbytes)361 void usbd_winusb_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
362 {
363 USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
364
365 if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
366 /* send zlp */
367 usbd_ep_start_write(busid, WINUSB_IN_EP, NULL, 0);
368 } else {
369 ep_tx_busy_flag = false;
370 }
371 }
372
usbd_cdc_acm_out(uint8_t busid,uint8_t ep,uint32_t nbytes)373 void usbd_cdc_acm_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
374 {
375 USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
376 // for (int i = 0; i < 100; i++) {
377 // printf("%02x ", read_buffer[i]);
378 // }
379 // printf("\r\n");
380 usbd_ep_start_write(busid, CDC_IN_EP, read_buffer, nbytes);
381 /* setup next out ep read transfer */
382 usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
383 }
384
usbd_cdc_acm_in(uint8_t busid,uint8_t ep,uint32_t nbytes)385 void usbd_cdc_acm_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
386 {
387 USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
388
389 if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
390 /* send zlp */
391 usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
392 } else {
393 ep_tx_busy_flag = false;
394 }
395 }
396
397 struct usbd_endpoint winusb_out_ep1 = {
398 .ep_addr = WINUSB_OUT_EP,
399 .ep_cb = usbd_winusb_out
400 };
401
402 struct usbd_endpoint winusb_in_ep1 = {
403 .ep_addr = WINUSB_IN_EP,
404 .ep_cb = usbd_winusb_in
405 };
406
407 static struct usbd_endpoint cdc_out_ep = {
408 .ep_addr = CDC_OUT_EP,
409 .ep_cb = usbd_cdc_acm_out
410 };
411
412 static struct usbd_endpoint cdc_in_ep = {
413 .ep_addr = CDC_IN_EP,
414 .ep_cb = usbd_cdc_acm_in
415 };
416
417 struct usbd_interface winusb_intf;
418 struct usbd_interface intf1;
419 struct usbd_interface intf2;
420
winusbv2_init(uint8_t busid,uintptr_t reg_base)421 void winusbv2_init(uint8_t busid, uintptr_t reg_base)
422 {
423 #ifdef CONFIG_USBDEV_ADVANCE_DESC
424 usbd_desc_register(busid, &winusbv2_descriptor);
425 #else
426 usbd_desc_register(busid, winusbv2_descriptor);
427 #endif
428 #ifndef CONFIG_USBDEV_ADVANCE_DESC
429 usbd_bos_desc_register(busid, &bos_desc);
430 usbd_msosv2_desc_register(busid, &msosv2_desc);
431 #endif
432 /*!< winusb */
433 usbd_add_interface(busid, &winusb_intf);
434 usbd_add_endpoint(busid, &winusb_out_ep1);
435 usbd_add_endpoint(busid, &winusb_in_ep1);
436
437 /*!< cdc acm */
438 usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
439 usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf2));
440 usbd_add_endpoint(busid, &cdc_out_ep);
441 usbd_add_endpoint(busid, &cdc_in_ep);
442
443 usbd_initialize(busid, reg_base, usbd_event_handler);
444 }
445
446 volatile uint8_t dtr_enable = 0;
447
usbd_cdc_acm_set_dtr(uint8_t busid,uint8_t intf,bool dtr)448 void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
449 {
450 if (dtr) {
451 dtr_enable = 1;
452 } else {
453 dtr_enable = 0;
454 }
455 }
456
cdc_acm_data_send_with_dtr_test(uint8_t busid)457 void cdc_acm_data_send_with_dtr_test(uint8_t busid)
458 {
459 if (dtr_enable) {
460 memset(&write_buffer[10], 'a', 2038);
461 ep_tx_busy_flag = true;
462 usbd_ep_start_write(busid, CDC_IN_EP, write_buffer, 2048);
463 while (ep_tx_busy_flag) {
464 }
465 }
466 }