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