1 /*
2  * This file is based on a file originally part of the
3  * MicroPython project, http://micropython.org/
4  *
5  * The MIT License (MIT)
6  *
7  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
8  * Copyright (c) 2019 Damien P. George
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #if !defined(LIB_TINYUSB_HOST) && !defined(LIB_TINYUSB_DEVICE)
30 
31 #include "tusb.h"
32 #include "pico/stdio_usb/reset_interface.h"
33 #include "pico/unique_id.h"
34 
35 #ifndef USBD_VID
36 #define USBD_VID (0x2E8A) // Raspberry Pi
37 #endif
38 
39 #ifndef USBD_PID
40 #if PICO_RP2040
41 #define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC for RP2040
42 #else
43 #define USBD_PID (0x0009) // Raspberry Pi Pico SDK CDC
44 #endif
45 #endif
46 
47 #ifndef USBD_MANUFACTURER
48 #define USBD_MANUFACTURER "Raspberry Pi"
49 #endif
50 
51 #ifndef USBD_PRODUCT
52 #define USBD_PRODUCT "Pico"
53 #endif
54 
55 #define TUD_RPI_RESET_DESC_LEN  9
56 #if !PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE
57 #define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
58 #else
59 #define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_RPI_RESET_DESC_LEN)
60 #endif
61 #if !PICO_STDIO_USB_DEVICE_SELF_POWERED
62 #define USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE (0)
63 #define USBD_MAX_POWER_MA (250)
64 #else
65 #define USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE TUSB_DESC_CONFIG_ATT_SELF_POWERED
66 #define USBD_MAX_POWER_MA (1)
67 #endif
68 
69 #define USBD_ITF_CDC       (0) // needs 2 interfaces
70 #if !PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE
71 #define USBD_ITF_MAX       (2)
72 #else
73 #define USBD_ITF_RPI_RESET (2)
74 #define USBD_ITF_MAX       (3)
75 #endif
76 
77 #define USBD_CDC_EP_CMD (0x81)
78 #define USBD_CDC_EP_OUT (0x02)
79 #define USBD_CDC_EP_IN (0x82)
80 #define USBD_CDC_CMD_MAX_SIZE (8)
81 #define USBD_CDC_IN_OUT_MAX_SIZE (64)
82 
83 #define USBD_STR_0 (0x00)
84 #define USBD_STR_MANUF (0x01)
85 #define USBD_STR_PRODUCT (0x02)
86 #define USBD_STR_SERIAL (0x03)
87 #define USBD_STR_CDC (0x04)
88 #define USBD_STR_RPI_RESET (0x05)
89 
90 // Note: descriptors returned from callbacks must exist long enough for transfer to complete
91 
92 static const tusb_desc_device_t usbd_desc_device = {
93     .bLength = sizeof(tusb_desc_device_t),
94     .bDescriptorType = TUSB_DESC_DEVICE,
95 // On Windows, if bcdUSB = 0x210 then a Microsoft OS 2.0 descriptor is required, else the device won't be detected
96 // This is only needed for driverless access to the reset interface - the CDC interface doesn't require these descriptors
97 // for driverless access, but will still not work if bcdUSB = 0x210 and no descriptor is provided. Therefore always
98 // use bcdUSB = 0x200 if the Microsoft OS 2.0 descriptor isn't enabled
99 #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
100     .bcdUSB = 0x0210,
101 #else
102     .bcdUSB = 0x0200,
103 #endif
104     .bDeviceClass = TUSB_CLASS_MISC,
105     .bDeviceSubClass = MISC_SUBCLASS_COMMON,
106     .bDeviceProtocol = MISC_PROTOCOL_IAD,
107     .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
108     .idVendor = USBD_VID,
109     .idProduct = USBD_PID,
110     .bcdDevice = 0x0100,
111     .iManufacturer = USBD_STR_MANUF,
112     .iProduct = USBD_STR_PRODUCT,
113     .iSerialNumber = USBD_STR_SERIAL,
114     .bNumConfigurations = 1,
115 };
116 
117 #define TUD_RPI_RESET_DESCRIPTOR(_itfnum, _stridx) \
118   /* Interface */\
119   9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, RESET_INTERFACE_PROTOCOL, _stridx,
120 
121 static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
122     TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
123         USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE, USBD_MAX_POWER_MA),
124 
125     TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
126         USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),
127 
128 #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE
129     TUD_RPI_RESET_DESCRIPTOR(USBD_ITF_RPI_RESET, USBD_STR_RPI_RESET)
130 #endif
131 };
132 
133 static char usbd_serial_str[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
134 
135 static const char *const usbd_desc_str[] = {
136     [USBD_STR_MANUF] = USBD_MANUFACTURER,
137     [USBD_STR_PRODUCT] = USBD_PRODUCT,
138     [USBD_STR_SERIAL] = usbd_serial_str,
139     [USBD_STR_CDC] = "Board CDC",
140 #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE
141     [USBD_STR_RPI_RESET] = "Reset",
142 #endif
143 };
144 
tud_descriptor_device_cb(void)145 const uint8_t *tud_descriptor_device_cb(void) {
146     return (const uint8_t *)&usbd_desc_device;
147 }
148 
tud_descriptor_configuration_cb(__unused uint8_t index)149 const uint8_t *tud_descriptor_configuration_cb(__unused uint8_t index) {
150     return usbd_desc_cfg;
151 }
152 
tud_descriptor_string_cb(uint8_t index,__unused uint16_t langid)153 const uint16_t *tud_descriptor_string_cb(uint8_t index, __unused uint16_t langid) {
154 #ifndef USBD_DESC_STR_MAX
155 #define USBD_DESC_STR_MAX (20)
156 #elif USBD_DESC_STR_MAX > 127
157 #error USBD_DESC_STR_MAX too high (max is 127).
158 #elif USBD_DESC_STR_MAX < 17
159 #error USBD_DESC_STR_MAX too low (min is 17).
160 #endif
161     static uint16_t desc_str[USBD_DESC_STR_MAX];
162 
163     // Assign the SN using the unique flash id
164     if (!usbd_serial_str[0]) {
165         pico_get_unique_board_id_string(usbd_serial_str, sizeof(usbd_serial_str));
166     }
167 
168     uint8_t len;
169     if (index == 0) {
170         desc_str[1] = 0x0409; // supported language is English
171         len = 1;
172     } else {
173         if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
174             return NULL;
175         }
176         const char *str = usbd_desc_str[index];
177         for (len = 0; len < USBD_DESC_STR_MAX - 1 && str[len]; ++len) {
178             desc_str[1 + len] = str[len];
179         }
180     }
181 
182     // first byte is length (including header), second byte is string type
183     desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * len + 2));
184 
185     return desc_str;
186 }
187 
188 #endif
189