Contiki-NG
usb_descriptors.c
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 */
25
26#include "tusb.h"
27
28/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
29 * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
30 *
31 * Auto ProductID layout's Bitmap:
32 * [MSB] HID | MSC | CDC [LSB]
33 */
34#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
35#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
36 _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
37
38//--------------------------------------------------------------------+
39// Device Descriptors
40//--------------------------------------------------------------------+
41tusb_desc_device_t const desc_device =
42{
43 .bLength = sizeof(tusb_desc_device_t),
44 .bDescriptorType = TUSB_DESC_DEVICE,
45 .bcdUSB = 0x0200,
46
47 // Use Interface Association Descriptor (IAD) for CDC
48 // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
49 .bDeviceClass = TUSB_CLASS_MISC,
50 .bDeviceSubClass = MISC_SUBCLASS_COMMON,
51 .bDeviceProtocol = MISC_PROTOCOL_IAD,
52
53 .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
54
55 .idVendor = 0x1915,
56 .idProduct = USB_PID,
57 .bcdDevice = 0x0100,
58
59 .iManufacturer = 0x01,
60 .iProduct = 0x02,
61 .iSerialNumber = 0x03,
62
63 .bNumConfigurations = 0x01
64};
65
66// Invoked when received GET DEVICE DESCRIPTOR
67// Application return pointer to descriptor
68uint8_t const * tud_descriptor_device_cb(void)
69{
70 return (uint8_t const *) &desc_device;
71}
72
73//--------------------------------------------------------------------+
74// Configuration Descriptor
75//--------------------------------------------------------------------+
76
77enum
78{
79 ITF_NUM_CDC = 0,
80 ITF_NUM_CDC_DATA,
81 ITF_NUM_TOTAL
82};
83
84#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
85
86#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
87 // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
88 // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
89 #define EPNUM_CDC_NOTIF 0x81
90 #define EPNUM_CDC_OUT 0x02
91 #define EPNUM_CDC_IN 0x82
92
93#elif CFG_TUSB_MCU == OPT_MCU_SAMG
94 // SAMG doesn't support a same endpoint number with different direction IN and OUT
95 // e.g EP1 OUT & EP1 IN cannot exist together
96 #define EPNUM_CDC_NOTIF 0x81
97 #define EPNUM_CDC_OUT 0x02
98 #define EPNUM_CDC_IN 0x83
99
100#elif CFG_TUSB_MCU == OPT_MCU_CXD56
101 // CXD56 doesn't support a same endpoint number with different direction IN and OUT
102 // e.g EP1 OUT & EP1 IN cannot exist together
103 // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
104 // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
105 #define EPNUM_CDC_NOTIF 0x83
106 #define EPNUM_CDC_OUT 0x02
107 #define EPNUM_CDC_IN 0x81
108
109#else
110 #define EPNUM_CDC_NOTIF 0x81
111 #define EPNUM_CDC_OUT 0x02
112 #define EPNUM_CDC_IN 0x82
113
114#endif
115
116uint8_t const desc_fs_configuration[] =
117{
118 // Config number, interface count, string index, total length, attribute, power in mA
119 TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
120
121 // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
122 TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
123};
124
125#if TUD_OPT_HIGH_SPEED
126uint8_t const desc_hs_configuration[] =
127{
128 // Config number, interface count, string index, total length, attribute, power in mA
129 TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
130
131 // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
132 TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
133};
134#endif
135
136
137// Invoked when received GET CONFIGURATION DESCRIPTOR
138// Application return pointer to descriptor
139// Descriptor contents must exist long enough for transfer to complete
140uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
141{
142 (void) index; // for multiple configurations
143
144#if TUD_OPT_HIGH_SPEED
145 // Although we are highspeed, host may be fullspeed.
146 return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
147#else
148 return desc_fs_configuration;
149#endif
150}
151
152//--------------------------------------------------------------------+
153// String Descriptors
154//--------------------------------------------------------------------+
155
156// array of pointer to string descriptors
157char const* string_desc_arr [] =
158{
159 (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
160 NULL, // 1: Manufacturer
161 NULL, // 2: Product
162 NULL, // 3: Serials, should use chip ID
163 NULL, // 4: CDC Interface
164};
165
166void usb_descriptor_set_manufacturer(char * manufacturer)
167{
168 string_desc_arr[1] = manufacturer;
169}
170
171void usb_descriptor_set_product(char * product)
172{
173 string_desc_arr[2] = product;
174}
175
176void usb_descriptor_set_serial(char * serial)
177{
178 string_desc_arr[3] = serial;
179}
180
181void usb_descriptor_set_cdc_interface(char * cdc_interface)
182{
183 string_desc_arr[4] = cdc_interface;
184}
185
186static uint16_t _desc_str[32];
187
188// Invoked when received GET STRING DESCRIPTOR request
189// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
190uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
191{
192 (void) langid;
193
194 uint8_t chr_count;
195
196 if ( index == 0)
197 {
198 memcpy(&_desc_str[1], string_desc_arr[0], 2);
199 chr_count = 1;
200 }else
201 {
202 // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
203 // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
204
205 if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
206
207 const char* str = string_desc_arr[index];
208
209 // Cap at max char
210 chr_count = strlen(str);
211 if ( chr_count > 31 ) chr_count = 31;
212
213 // Convert ASCII string into UTF-16
214 for(uint8_t i=0; i<chr_count; i++)
215 {
216 _desc_str[1+i] = str[i];
217 }
218 }
219
220 // first byte is length (including header), second byte is string type
221 _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
222
223 return _desc_str;
224}
void usb_descriptor_set_serial(char *serial)
Set the serial.
void usb_descriptor_set_manufacturer(char *manufacturer)
Set the manufactorer.
void usb_descriptor_set_cdc_interface(char *cdc_interface)
Set the cdc interface.
void usb_descriptor_set_product(char *product)
Set the product.