1 /*
2  * Copyright (c) 2016-2019 Intel Corporation
3  * Copyright (c) 2023-2024 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #ifndef ZEPHYR_INCLUDE_MSOSV2_DESCRIPTOR_H
9 #define ZEPHYR_INCLUDE_MSOSV2_DESCRIPTOR_H
10 
11 /*
12  * Microsoft OS 2.0 platform capability and Microsoft OS 2.0 descriptor set.
13  * See Microsoft OS 2.0 Descriptors Specification for reference.
14  */
15 
16 #define SAMPLE_MSOS2_VENDOR_CODE	0x02U
17 /* Windows version (10)*/
18 #define SAMPLE_MSOS2_OS_VERSION		0x0A000000UL
19 
20 /* random GUID {FA611CC3-7057-42EE-9D82-4919639562B3} */
21 #define WEBUSB_DEVICE_INTERFACE_GUID \
22 	'{', 0x00, 'F', 0x00, 'A', 0x00, '6', 0x00, '1', 0x00, '1', 0x00, \
23 	'C', 0x00, 'C', 0x00, '3', 0x00, '-', 0x00, '7', 0x00, '0', 0x00, \
24 	'5', 0x00, '7', 0x00, '-', 0x00, '4', 0x00, '2', 0x00, 'E', 0x00, \
25 	'E', 0x00, '-', 0x00, '9', 0x00, 'D', 0x00, '8', 0x00, '2', 0x00, \
26 	'-', 0x00, '4', 0x00, '9', 0x00, '1', 0x00, '9', 0x00, '6', 0x00, \
27 	'3', 0x00, '9', 0x00, '5', 0x00, '6', 0x00, '2', 0x00, 'B', 0x00, \
28 	'3', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
29 
30 #define CDC_ACM_DESCRIPTOR_LENGTH 160
31 
32 struct msosv2_descriptor {
33 	struct msosv2_descriptor_set_header header;
34 #if defined(CONFIG_USBD_CDC_ACM_CLASS)
35 	/*
36 	 * The composition of this descriptor is specific to the WebUSB example
37 	 * in its default configuration. If you use it for your application or
38 	 * change the configuration, you may need to modify this descriptor for
39 	 * your USB device. The following only covers the case where the CDC
40 	 * ACM implementation is enabled, and there is only one CDC ACM UART
41 	 * instance, and the CDC ACM communication interface is the first in
42 	 * the configuration.
43 	 */
44 	struct msosv2_function_subset_header subset_header;
45 #endif
46 	struct msosv2_compatible_id compatible_id;
47 	struct msosv2_guids_property guids_property;
48 } __packed;
49 
50 static struct msosv2_descriptor msosv2_desc = {
51 	.header = {
52 		.wLength = sizeof(struct msosv2_descriptor_set_header),
53 		.wDescriptorType = MS_OS_20_SET_HEADER_DESCRIPTOR,
54 		.dwWindowsVersion = sys_cpu_to_le32(SAMPLE_MSOS2_OS_VERSION),
55 		.wTotalLength = sizeof(msosv2_desc),
56 	},
57 #if defined(CONFIG_USBD_CDC_ACM_CLASS)
58 	.subset_header = {
59 		.wLength = sizeof(struct msosv2_function_subset_header),
60 		.wDescriptorType = MS_OS_20_SUBSET_HEADER_FUNCTION,
61 		.bFirstInterface = 0,
62 		.wSubsetLength = CDC_ACM_DESCRIPTOR_LENGTH,
63 	},
64 #endif
65 	.compatible_id = {
66 		.wLength = sizeof(struct msosv2_compatible_id),
67 		.wDescriptorType = MS_OS_20_FEATURE_COMPATIBLE_ID,
68 		.CompatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00},
69 	},
70 	.guids_property = {
71 		.wLength = sizeof(struct msosv2_guids_property),
72 		.wDescriptorType = MS_OS_20_FEATURE_REG_PROPERTY,
73 		.wPropertyDataType = MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ,
74 		.wPropertyNameLength = 42,
75 		.PropertyName = {DEVICE_INTERFACE_GUIDS_PROPERTY_NAME},
76 		.wPropertyDataLength = 80,
77 		.bPropertyData = {WEBUSB_DEVICE_INTERFACE_GUID},
78 	},
79 };
80 
81 struct bos_msosv2_descriptor {
82 	struct usb_bos_platform_descriptor platform;
83 	struct usb_bos_capability_msos cap;
84 } __packed;
85 
86 struct bos_msosv2_descriptor bos_msosv2_desc = {
87 	/*
88 	 * Microsoft OS 2.0 Platform Capability Descriptor,
89 	 * see Microsoft OS 2.0 Descriptors Specification
90 	 */
91 	.platform = {
92 		.bLength = sizeof(struct usb_bos_platform_descriptor)
93 			 + sizeof(struct usb_bos_capability_msos),
94 		.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
95 		.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM,
96 		.bReserved = 0,
97 		/* Microsoft OS 2.0 descriptor platform capability UUID
98 		 * D8DD60DF-4589-4CC7-9CD2-659D9E648A9F
99 		 */
100 		.PlatformCapabilityUUID = {
101 			0xDF, 0x60, 0xDD, 0xD8,
102 			0x89, 0x45,
103 			0xC7, 0x4C,
104 			0x9C, 0xD2,
105 			0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,
106 		},
107 	},
108 	.cap = {
109 		.dwWindowsVersion = sys_cpu_to_le32(SAMPLE_MSOS2_OS_VERSION),
110 		.wMSOSDescriptorSetTotalLength = sys_cpu_to_le16(sizeof(msosv2_desc)),
111 		.bMS_VendorCode = SAMPLE_MSOS2_VENDOR_CODE,
112 		.bAltEnumCode = 0x00
113 	},
114 };
115 
msosv2_to_host_cb(const struct usbd_context * const ctx,const struct usb_setup_packet * const setup,struct net_buf * const buf)116 static int msosv2_to_host_cb(const struct usbd_context *const ctx,
117 			     const struct usb_setup_packet *const setup,
118 			     struct net_buf *const buf)
119 {
120 	LOG_INF("Vendor callback to host");
121 
122 	if (setup->bRequest == SAMPLE_MSOS2_VENDOR_CODE &&
123 	    setup->wIndex == MS_OS_20_DESCRIPTOR_INDEX) {
124 		LOG_INF("Get MS OS 2.0 Descriptor Set");
125 
126 		net_buf_add_mem(buf, &msosv2_desc,
127 				MIN(net_buf_tailroom(buf), sizeof(msosv2_desc)));
128 
129 		return 0;
130 	}
131 
132 	return -ENOTSUP;
133 }
134 
135 USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_msosv2, sizeof(bos_msosv2_desc), &bos_msosv2_desc,
136 			  SAMPLE_MSOS2_VENDOR_CODE, msosv2_to_host_cb, NULL);
137 
138 #endif /* ZEPHYR_INCLUDE_MSOSV2_DESCRIPTOR_H */
139