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