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