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