1 /*
2  * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include "esp32s2/rom/usb/usb_common.h"
9 #include "soc/soc.h"
10 #include "hal/efuse_hal.h"
11 
12 /* USB CDC descriptor.
13  * Note that we aren't using the one in ROM since it doesn't
14  * set "serial" to the MAC address.
15  * However overriding the descriptor is cheap - we can reuse most
16  * of its components from ROM.
17  */
18 
19 /* This is not const, since the MAC address is only known at run time */
20 static struct string_descriptor s_str_serial_descr = {
21     .bLength = 2 + 2 * 17,
22     .bDescriptorType = 0x03,
23     .bString={'0', '0', ':', '0', '0', ':', '0', '0', ':', '0', '0', ':', '0', '0', ':', '0', '0'}
24 };
25 
26 static const struct rom_usb_descriptors s_acm_usb_descriptors_override = {
27     .device_descr = &general_device_descr,
28     .config_descr = { &acm_config_descr },
29     .string_count = 4,
30     .string0_descr = &string0_descr,
31     .string_descrs = {
32         &str_manu_descr,
33         &str_prod_descr,
34         &s_str_serial_descr
35     }
36 };
37 
nibble_to_hex_u16(uint8_t b)38 static inline uint16_t nibble_to_hex_u16(uint8_t b)
39 {
40     if (b < 0xa) {
41         return '0' + b;
42     } else {
43         return 'a' + b - 0xa;
44     }
45 }
46 
rom_usb_cdc_set_descriptor_patch(void)47 void rom_usb_cdc_set_descriptor_patch(void)
48 {
49     uint8_t mac_bytes[6];
50     efuse_hal_get_mac(mac_bytes);
51     /* Convert to UTF16 string */
52 #pragma GCC diagnostic push
53 #if     __GNUC__ >= 9
54 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
55 #endif
56     uint16_t* dst = s_str_serial_descr.bString;
57     for (int i = 0; i < 6; ++i) {
58         uint8_t b = mac_bytes[5 - i]; /* printing from the MSB */
59         *dst++ = nibble_to_hex_u16(b >> 4);
60         *dst++ = nibble_to_hex_u16(b & 0xf);
61         dst++;
62     }
63 #pragma GCC diagnostic pop
64 
65     /* Override the pointer to descriptors structure */
66     rom_usb_curr_desc = &s_acm_usb_descriptors_override;
67 }
68 
69 /* On ESP32-S2, ROM doesn't provide interfaces to clear usb_dev and usb_dw_ctrl structures.
70  * Starting from ESP32-S3, usb_dev_deinit and usb_dw_ctrl_deinit ROM functions are available.
71  * Here we implement the missing functionality for the ESP32-S2.
72  */
usb_dev_deinit(void)73 void usb_dev_deinit(void)
74 {
75     extern char rom_usb_dev, rom_usb_dev_end;
76     memset((void *) &rom_usb_dev, 0, &rom_usb_dev_end - &rom_usb_dev);
77 }
78 
usb_dw_ctrl_deinit(void)79 void usb_dw_ctrl_deinit(void)
80 {
81     extern char rom_usb_dw_ctrl, rom_usb_dw_ctrl_end;
82     memset((void *) &rom_usb_dw_ctrl, 0, &rom_usb_dw_ctrl_end - &rom_usb_dw_ctrl);
83 }
84