-
Notifications
You must be signed in to change notification settings - Fork 0
/
usb_descriptors.h
394 lines (355 loc) · 18 KB
/
usb_descriptors.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/** @addtogroup 06 USB USB_Group
*
* @ingroup infrastructure_apis
*
* @file usb_descriptors.h Defines the USB descriptors. Header file of cdcacm.c.
*
* @brief <b>Defines the USB descriptors: Header file of cdcacm.c</b>
*
* @version 1.0.0
*
* @author @htmlonly © @endhtmlonly 2022
* Evandro Souza <evandro.r.souza@gmail.com>
*
* @date 01 September 2022
*
* This library supports the USART with DMA in the STM32F4 and STM32F1
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms ref lgpl_license
*/
/*
* This file is part of the MSX Keyboard Subsystem Emulator project.
*
* Copyright (C) 2022 Evandro Souza <evandro.r.souza@gmail.com>
*
* Based on CDCACM example of:
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USB_DESCRIPTORS_H
#define USB_DESCRIPTORS_H
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
#include <libopencm3/usb/dfu.h>
#include "system.h"
#include "serial_no.h"
#include "version.h"
/** Defines the Board identification + Firmware version
*
@{*/
//#define BOARD_IDENT "MSX keyboard subsystem emulator " FIRMWARE_VERSION
#define BOARD_IDENT DESIGN_DEF HARDWARE_BASE FIRMWARE_VERSION
/**@}*/
/** Get locale of serial_no
*
@{*/
extern char serial_no[LEN_SERIAL_No + 1]; //Declared as uint8_t on serial_no.c
/**@}*/
#if USE_USB == true
static const char *usb_strings[] = {
"Evandro Rodrigues de Souza Technologies",
BOARD_IDENT,
serial_no,
DESIGN_DEF "Console", // Console Port
DESIGN_DEF "Console ACM Port", // Console ACM Port
DESIGN_DEF "Console DataPort", // Console DATA Port
DESIGN_DEF "Converter USB <-> Serial", // Serial Port
DESIGN_DEF "USB-Serial ACM Port", // Serial ACM Port
DESIGN_DEF "USB-Serial DataPort", // Serial DATA Port
};
#define NUM_STRINGS (sizeof(usb_strings) / sizeof(usb_strings[0]))
enum usb_strings_index { // Index of USB strings. Must sync with *usb_strings[], starts from 1.
USB_STRINGS_MANUFACTURER = 1,
USB_STRINGS_PRODUCT,
USB_STRINGS_SERIAL_NUMBER,
USB_STRINGS_CONSOLE,
USB_STRINGS_CON_COMM,
USB_STRINGS_CON_DATA,
USB_STRINGS_UART,
USB_STRINGS_UART_COMM,
USB_STRINGS_UART_DATA,
};
static const struct usb_device_descriptor dev_desc = {
.bLength = USB_DT_DEVICE_SIZE, // 18: Length of this descriptor.
.bDescriptorType = USB_DT_DEVICE, // This is a Device Descriptor
#if USB21_INTERFACE == true
.bcdUSB = 0x0210, // USB Version 2.1. Need to handle special requests e.g. BOS.
#else
.bcdUSB = 0x0200, // USB Version 2.0. No need to handle special requests e.g. BOS.
#endif // #if USB21_INTERFACE == true
#if (CDC_ONLY_ON_USB == true)
.bDeviceClass = USB_CLASS_CDC, //0x02 Set the class to CDC if it's only serial. Serial interface will not start on Windows when class = 0.
.bDeviceSubClass = 0, //Communications Device Subclass code, unused at this time.
.bDeviceProtocol = 0, //Communications Device Subclass code, unused at this time.
#else //#if (CDC_ONLY_ON_USB == true)
.bDeviceClass = USB_CLASS_MISCELLANEOUS, //0xEF Set the class to CDC to miscellaneous.
.bDeviceSubClass = 2, //0xEF, 0x02, 0x01 is Interface Association Descriptor
.bDeviceProtocol = 1, //0xEF, 0x02, 0x01 is Interface Association Descriptor
#endif //#if (CDC_ONLY_ON_USB == true)
.bMaxPacketSize0 = USBD_DATA_BUFFER_SIZE, // USB packet size (64)
.idVendor = USB_VID, // Official USB Vendor ID
.idProduct = USB_PID, // Official USB Product ID
.bcdDevice = 0x0100, // Device Release number 1.0
.iManufacturer = USB_STRINGS_MANUFACTURER, // Name of manufacturer (index of string descriptor)
.iProduct = USB_STRINGS_PRODUCT, // Name of product (index of string descriptor)
.iSerialNumber = USB_STRINGS_SERIAL_NUMBER, // Serial number (index of string descriptor)
.bNumConfigurations = 1, // How many configurations we support
};
/*
* This notification endpoint isn't implemented. According to CDC spec its
* optional, but its absence causes a NULL pointer dereference in Linux
* cdc_acm driver.
*/
// Console ACM interface
// CON Endpoint Descriptors
static const struct usb_endpoint_descriptor con_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, //7 (as defined in usbstd.h)
.bDescriptorType = USB_DT_ENDPOINT, //5 (as defined in usbstd.h)
.bEndpointAddress = EP_CON_COMM_IN, //0x82 Console USB IN Control Endpoint//EP_CON_COMM_IN=0x83 originally
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,//0x03 (as defined in usbstd.h)
.wMaxPacketSize = COMM_PACKET_SIZE, //16 - Smaller than others
.bInterval = 255,
}};
static const struct usb_endpoint_descriptor con_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, //7 (as defined in usbstd.h)
.bDescriptorType = USB_DT_ENDPOINT, //5 (as defined in usbstd.h)
.bEndpointAddress = EP_CON_DATA_OUT, //0x01 Console USB OUT Data Endpoint//EP_CON_DATA_OUT=0x01 originally
.bmAttributes = USB_ENDPOINT_ATTR_BULK, //0x02 (as defined in usbstd.h)
.wMaxPacketSize = USBD_DATA_BUFFER_SIZE, //64
.bInterval = 1,
}, {
.bLength = USB_DT_ENDPOINT_SIZE, //7 (as defined in usbstd.h)
.bDescriptorType = USB_DT_ENDPOINT, //5 (as defined in usbstd.h)
.bEndpointAddress = EP_CON_DATA_IN, //0x01 Console USB OUT Data Endpoint//EP_CON_DATA_IN=0x82 originally
.bmAttributes = USB_ENDPOINT_ATTR_BULK, //0x02 (as defined in usbstd.h)
.wMaxPacketSize = USBD_DATA_BUFFER_SIZE, //64
.bInterval = 1,
}};
// CON Functional Descriptor
static const struct {
struct usb_cdc_header_descriptor header;
struct usb_cdc_call_management_descriptor call_mgmt;
struct usb_cdc_acm_descriptor acm;
struct usb_cdc_union_descriptor cdc_union;
} __attribute__((packed)) con_cdcacm_functional_descriptors = {
.header = {
.bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_HEADER,//0x00 (as defined in cdc.h)
.bcdCDC = 0x0110,
},
.call_mgmt = {
.bFunctionLength =
sizeof(struct usb_cdc_call_management_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,//0x01 (as defined in cdc.h)
.bmCapabilities = 0,
.bDataInterface = INTF_CON_DATA, // DATA Interface
},
.acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_ACM, //0x02 (as defined in cdc.h)
.bmCapabilities = 2, // SET_LINE_CODING supported (BMP uses for both GDB and uart)
},
.cdc_union = {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_UNION, //0x06 (as defined in cdc.h)
.bControlInterface = INTF_CON_COMM, // COMM Interface
.bSubordinateInterface0 = INTF_CON_DATA, // DATA Interface
},
};
// CON Interface Descriptor (Comm)
static const struct usb_interface_descriptor con_comm_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, //9 (as defined in usbstd.h)
.bDescriptorType = USB_DT_INTERFACE, //4 (as defined in usbstd.h)
.bInterfaceNumber = INTF_CON_COMM, // CDC ACM interface ID is 0
.bAlternateSetting = 0, //No alternate setting
.bNumEndpoints = 1, //1 EP: CDC ACM Endpoint
.bInterfaceClass = USB_CLASS_CDC, //0x02 Communications Interface Class (as defined in cdc.h)
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, //0x02 Abstract Control Model (as defined in cdc.h)
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT, //0x01 AT Commands: V.250 etc (as defined in cdc.h)
.iInterface = USB_STRINGS_CON_COMM, // Name of CDC ACM interface (index of string descriptor)
.endpoint = con_comm_endp,
.extra = &con_cdcacm_functional_descriptors,
.extralen = sizeof(con_cdcacm_functional_descriptors),
}};
// CON Interface Descriptor (Data)
static const struct usb_interface_descriptor con_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, //9 (as defined in usbstd.h)
.bDescriptorType = USB_DT_INTERFACE, //4 (as defined in usbstd.h)
.bInterfaceNumber = INTF_CON_DATA, // CDC ACM interface ID is 1
.bAlternateSetting = 0, //No alternate setting
.bNumEndpoints = 2, //2 EP's: Data OUT (for received data) and Data IN (for sent data)
.bInterfaceClass = USB_CLASS_DATA, //0x0A (as defined in cdc.h)
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = USB_STRINGS_CON_DATA, // Name of CDC ACM interface (index of string descriptor)
.endpoint = con_data_endp, // CDC ACM Endpoint
}};
#if !(CDC_ONLY_ON_USB == true)
// CON Interface Association Descriptor - CDC Interfaces
static const struct usb_iface_assoc_descriptor con_iface_assoc = { // Copied from BMP. Mandatory for composite device.
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,//8 (as defined in usbstd.h)
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,//11 (as defined in usbstd.h)
.bFirstInterface = INTF_CON_COMM, // First associated interface (INTF_CON_COMM and INTF_CON_DATA)
.bInterfaceCount = 2, // Total number of associated interfaces (INTF_CON_COMM and INTF_CON_DATA), ID must be consecutive.
.bFunctionClass = USB_CLASS_CDC, //0x02 This is a USB CDC (Comms Device Class) interface
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM, //0x02 That implements ACM (Abstract Control Model)
.bFunctionProtocol = USB_CDC_PROTOCOL_AT, //0x01 Using the AT protocol
.iFunction = USB_STRINGS_CONSOLE, // Name of Console Port
};
#endif //#if (CDC_ONLY_ON_USB == true)
// UART ACM interface
// UART Endpoint Descriptors
static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, //7 (as defined in usbstd.h)
.bDescriptorType = USB_DT_ENDPOINT, //5 (as defined in usbstd.h)
.bEndpointAddress = EP_UART_COMM_IN, //0x84 UART USB Comm Endpoint
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,//0x03 (as defined in usbstd.h)
.wMaxPacketSize = COMM_PACKET_SIZE, // Smaller than others: 16
.bInterval = 255,
} };
static const struct usb_endpoint_descriptor uart_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, //7 (as defined in usbstd.h)
.bDescriptorType = USB_DT_ENDPOINT, //5 (as defined in usbstd.h)
.bEndpointAddress = EP_UART_DATA_OUT, //3 UART USB OUT Data Endpoint
.bmAttributes = USB_ENDPOINT_ATTR_BULK, //0x02 (as defined in usbstd.h)
.wMaxPacketSize = USBD_DATA_BUFFER_SIZE, //64
.bInterval = 1,
}, {
.bLength = USB_DT_ENDPOINT_SIZE, //7 (as defined in usbstd.h)
.bDescriptorType = USB_DT_ENDPOINT, //5 (as defined in usbstd.h)
.bEndpointAddress = EP_UART_DATA_IN, //0x83 UART USB IN Data Endpoint
.bmAttributes = USB_ENDPOINT_ATTR_BULK, //0x02 (as defined in usbstd.h)
.wMaxPacketSize = USBD_DATA_BUFFER_SIZE, //64
.bInterval = 1,
} };
// UART Functional Descriptor
static const struct {
struct usb_cdc_header_descriptor header;
struct usb_cdc_call_management_descriptor call_mgmt;
struct usb_cdc_acm_descriptor acm;
struct usb_cdc_union_descriptor cdc_union;
} __attribute__((packed)) uart_cdcacm_functional_descriptors = {
.header = {
.bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_HEADER,//0x00 (as defined in cdc.h)
.bcdCDC = 0x0110,
},
.call_mgmt = {
.bFunctionLength = sizeof(struct usb_cdc_call_management_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,//0x01 (as defined in cdc.h)
.bmCapabilities = 0,
.bDataInterface = INTF_UART_DATA, // DATA Interface
},
.acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_ACM, //0x02 (as defined in cdc.h)
.bmCapabilities = 2, // SET_LINE_CODING supported (BMP uses for both GDB and uart)
},
.cdc_union = {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE, //0x24 (as defined in cdc.h)
.bDescriptorSubtype = USB_CDC_TYPE_UNION, //0x06 (as defined in cdc.h)
.bControlInterface = INTF_UART_COMM, // COMM Interface
.bSubordinateInterface0 = INTF_UART_DATA, // DATA Interface
}
};
// UART Interface Descriptor (comm)
static const struct usb_interface_descriptor uart_comm_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, //9 (as defined in usbstd.h)
.bDescriptorType = USB_DT_INTERFACE, //4 (as defined in usbstd.h)
.bInterfaceNumber = INTF_UART_COMM, // CDC ACM interface ID is 2
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_CDC, //0x02 (as defined in cdc.h)
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, //0x02 (as defined in cdc.h)
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT, //0x01 (as defined in cdc.h)
.iInterface = USB_STRINGS_UART_COMM, // Name of CDC ACM interface (index of string descriptor)
.endpoint = uart_comm_endp,
.extra = &uart_cdcacm_functional_descriptors,
.extralen = sizeof(uart_cdcacm_functional_descriptors),
} };
// UART Interface Descriptor (data)
static const struct usb_interface_descriptor uart_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, //9 (as defined in usbstd.h)
.bDescriptorType = USB_DT_INTERFACE, //4 (as defined in usbstd.h)
.bInterfaceNumber = INTF_UART_DATA, // CDC ACM interface ID is 3
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_DATA, //0x0A (as defined in cdc.h)
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = USB_STRINGS_UART_DATA, // Name of CDC ACM interface (index of string descriptor)
.endpoint = uart_data_endp, // CDC ACM Endpoint
} };
#if !(CDC_ONLY_ON_USB == true)
// UART Interface Association Descriptor - CDC Interfaces
static const struct usb_iface_assoc_descriptor uart_iface_assoc = // Copied from BMP. Mandatory for composite device.
{
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,//8 (as defined in usbstd.h)
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,//11 (as defined in usbstd.h)
.bFirstInterface = INTF_UART_COMM,// First associated interface (INTF_UART_COMM and INTF_UART_DATA)
.bInterfaceCount = 2, // Total number of associated interfaces (INTF_UART_COMM and INTF_UART_DATA), ID must be consecutive.
.bFunctionClass = USB_CLASS_CDC, //0x02 This is a USB CDC (Comms Device Class) interface
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM, //0x02 That implements ACM (Abstract Control Model)
.bFunctionProtocol = USB_CDC_PROTOCOL_AT, //0x01 Using the AT protocol
.iFunction = USB_STRINGS_UART, // Name of Serial Port
};
#endif //#if (CDC_ONLY_ON_USB == true)
// Both Console and UART ACM interfaces
// USB Configuration Descriptor (Both interfaces)
static const struct usb_interface interfaces[] = {
{
.num_altsetting = 1,
#if !(CDC_ONLY_ON_USB == true)
.iface_assoc = &con_iface_assoc, //Mandatory for composite device with multiple interfaces. static const struct usb_iface_assoc_descriptor con_iface_assoc
#endif //#if !(CDC_ONLY_ON_USB == true)
.altsetting = con_comm_iface, //Index must sync with INTF_CON_COMM.
}, {
.num_altsetting = 1,
.altsetting = con_data_iface, //Index must sync with INTF_CON_DATA.
},
{
.num_altsetting = 1,
#if !(CDC_ONLY_ON_USB == true)
.iface_assoc = &uart_iface_assoc, //Mandatory for composite device with multiple interfaces. static const struct usb_iface_assoc_descriptor uart_iface_assoc
#endif //#if !(CDC_ONLY_ON_USB == true)
.altsetting = uart_comm_iface, //Index must sync with INTF_UART_COMM.
}, {
.num_altsetting = 1,
.altsetting = uart_data_iface, //Index must sync with INTF_UART_DATA.
},};
static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, //Libopencm3 will fill this automatically at sending time
.bNumInterfaces = sizeof(interfaces) / \
sizeof(interfaces[0]), // We will have 4 interfaces
.bConfigurationValue = 1, // This is the configuration ID 1
.iConfiguration = 0, // Configuration string (0 means none)
.bmAttributes = USB_CONFIG_ATTR_DEFAULT | \
USB_CONFIG_ATTR_SELF_POWERED,// Self-powered: it doesn't draw power from USB bus.
.bMaxPower = 5, // Specifies how much bus current a device requires: 10 mA. (2 x .bMaxPower)
.interface = interfaces, // List of all interfaces
};
#endif //#if USE_USB == true
#endif //#ifndef USB_DESCRIPTORS_H