1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 
9 #include <zephyr/device.h>
10 #include <zephyr/usb/usbd.h>
11 #include <zephyr/usb/bos.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(usbd_sample_config);
15 
16 /* By default, do not register the USB DFU class DFU mode instance. */
17 static const char *const blocklist[] = {
18 	"dfu_dfu",
19 	NULL,
20 };
21 
22 /* doc device instantiation start */
23 /*
24  * Instantiate a context named sample_usbd using the default USB device
25  * controller, the Zephyr project vendor ID, and the sample product ID.
26  * Zephyr project vendor ID must not be used outside of Zephyr samples.
27  */
28 USBD_DEVICE_DEFINE(sample_usbd,
29 		   DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)),
30 		   CONFIG_SAMPLE_USBD_VID, CONFIG_SAMPLE_USBD_PID);
31 /* doc device instantiation end */
32 
33 /* doc string instantiation start */
34 USBD_DESC_LANG_DEFINE(sample_lang);
35 USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, CONFIG_SAMPLE_USBD_MANUFACTURER);
36 USBD_DESC_PRODUCT_DEFINE(sample_product, CONFIG_SAMPLE_USBD_PRODUCT);
37 IF_ENABLED(CONFIG_HWINFO, (USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn)));
38 
39 /* doc string instantiation end */
40 
41 USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration");
42 USBD_DESC_CONFIG_DEFINE(hs_cfg_desc, "HS Configuration");
43 
44 /* doc configuration instantiation start */
45 static const uint8_t attributes = (IS_ENABLED(CONFIG_SAMPLE_USBD_SELF_POWERED) ?
46 				   USB_SCD_SELF_POWERED : 0) |
47 				  (IS_ENABLED(CONFIG_SAMPLE_USBD_REMOTE_WAKEUP) ?
48 				   USB_SCD_REMOTE_WAKEUP : 0);
49 
50 /* Full speed configuration */
51 USBD_CONFIGURATION_DEFINE(sample_fs_config,
52 			  attributes,
53 			  CONFIG_SAMPLE_USBD_MAX_POWER, &fs_cfg_desc);
54 
55 /* High speed configuration */
56 USBD_CONFIGURATION_DEFINE(sample_hs_config,
57 			  attributes,
58 			  CONFIG_SAMPLE_USBD_MAX_POWER, &hs_cfg_desc);
59 /* doc configuration instantiation end */
60 
61 #if CONFIG_SAMPLE_USBD_20_EXTENSION_DESC
62 /*
63  * This does not yet provide valuable information, but rather serves as an
64  * example, and will be improved in the future.
65  */
66 static const struct usb_bos_capability_lpm bos_cap_lpm = {
67 	.bLength = sizeof(struct usb_bos_capability_lpm),
68 	.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
69 	.bDevCapabilityType = USB_BOS_CAPABILITY_EXTENSION,
70 	.bmAttributes = 0UL,
71 };
72 
73 USBD_DESC_BOS_DEFINE(sample_usbext, sizeof(bos_cap_lpm), &bos_cap_lpm);
74 #endif
75 
sample_fix_code_triple(struct usbd_context * uds_ctx,const enum usbd_speed speed)76 static void sample_fix_code_triple(struct usbd_context *uds_ctx,
77 				   const enum usbd_speed speed)
78 {
79 	/* Always use class code information from Interface Descriptors */
80 	if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) ||
81 	    IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) ||
82 	    IS_ENABLED(CONFIG_USBD_CDC_NCM_CLASS) ||
83 	    IS_ENABLED(CONFIG_USBD_MIDI2_CLASS) ||
84 	    IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS) ||
85 	    IS_ENABLED(CONFIG_USBD_VIDEO_CLASS)) {
86 		/*
87 		 * Class with multiple interfaces have an Interface
88 		 * Association Descriptor available, use an appropriate triple
89 		 * to indicate it.
90 		 */
91 		usbd_device_set_code_triple(uds_ctx, speed,
92 					    USB_BCC_MISCELLANEOUS, 0x02, 0x01);
93 	} else {
94 		usbd_device_set_code_triple(uds_ctx, speed, 0, 0, 0);
95 	}
96 }
97 
sample_usbd_setup_device(usbd_msg_cb_t msg_cb)98 struct usbd_context *sample_usbd_setup_device(usbd_msg_cb_t msg_cb)
99 {
100 	int err;
101 
102 	/* doc add string descriptor start */
103 	err = usbd_add_descriptor(&sample_usbd, &sample_lang);
104 	if (err) {
105 		LOG_ERR("Failed to initialize language descriptor (%d)", err);
106 		return NULL;
107 	}
108 
109 	err = usbd_add_descriptor(&sample_usbd, &sample_mfr);
110 	if (err) {
111 		LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err);
112 		return NULL;
113 	}
114 
115 	err = usbd_add_descriptor(&sample_usbd, &sample_product);
116 	if (err) {
117 		LOG_ERR("Failed to initialize product descriptor (%d)", err);
118 		return NULL;
119 	}
120 
121 	IF_ENABLED(CONFIG_HWINFO, (
122 		err = usbd_add_descriptor(&sample_usbd, &sample_sn);
123 	))
124 	if (err) {
125 		LOG_ERR("Failed to initialize SN descriptor (%d)", err);
126 		return NULL;
127 	}
128 	/* doc add string descriptor end */
129 
130 	if (USBD_SUPPORTS_HIGH_SPEED &&
131 	    usbd_caps_speed(&sample_usbd) == USBD_SPEED_HS) {
132 		err = usbd_add_configuration(&sample_usbd, USBD_SPEED_HS,
133 					     &sample_hs_config);
134 		if (err) {
135 			LOG_ERR("Failed to add High-Speed configuration");
136 			return NULL;
137 		}
138 
139 		err = usbd_register_all_classes(&sample_usbd, USBD_SPEED_HS, 1,
140 						blocklist);
141 		if (err) {
142 			LOG_ERR("Failed to add register classes");
143 			return NULL;
144 		}
145 
146 		sample_fix_code_triple(&sample_usbd, USBD_SPEED_HS);
147 	}
148 
149 	/* doc configuration register start */
150 	err = usbd_add_configuration(&sample_usbd, USBD_SPEED_FS,
151 				     &sample_fs_config);
152 	if (err) {
153 		LOG_ERR("Failed to add Full-Speed configuration");
154 		return NULL;
155 	}
156 	/* doc configuration register end */
157 
158 	/* doc functions register start */
159 	err = usbd_register_all_classes(&sample_usbd, USBD_SPEED_FS, 1, blocklist);
160 	if (err) {
161 		LOG_ERR("Failed to add register classes");
162 		return NULL;
163 	}
164 	/* doc functions register end */
165 
166 	sample_fix_code_triple(&sample_usbd, USBD_SPEED_FS);
167 	usbd_self_powered(&sample_usbd, attributes & USB_SCD_SELF_POWERED);
168 
169 	if (msg_cb != NULL) {
170 		/* doc device init-and-msg start */
171 		err = usbd_msg_register_cb(&sample_usbd, msg_cb);
172 		if (err) {
173 			LOG_ERR("Failed to register message callback");
174 			return NULL;
175 		}
176 		/* doc device init-and-msg end */
177 	}
178 
179 #if CONFIG_SAMPLE_USBD_20_EXTENSION_DESC
180 	(void)usbd_device_set_bcd_usb(&sample_usbd, USBD_SPEED_FS, 0x0201);
181 	(void)usbd_device_set_bcd_usb(&sample_usbd, USBD_SPEED_HS, 0x0201);
182 
183 	err = usbd_add_descriptor(&sample_usbd, &sample_usbext);
184 	if (err) {
185 		LOG_ERR("Failed to add USB 2.0 Extension Descriptor");
186 		return NULL;
187 	}
188 #endif
189 
190 	return &sample_usbd;
191 }
192 
sample_usbd_init_device(usbd_msg_cb_t msg_cb)193 struct usbd_context *sample_usbd_init_device(usbd_msg_cb_t msg_cb)
194 {
195 	int err;
196 
197 	if (sample_usbd_setup_device(msg_cb) == NULL) {
198 		return NULL;
199 	}
200 
201 	/* doc device init start */
202 	err = usbd_init(&sample_usbd);
203 	if (err) {
204 		LOG_ERR("Failed to initialize device support");
205 		return NULL;
206 	}
207 	/* doc device init end */
208 
209 	return &sample_usbd;
210 }
211