1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/init.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/device.h>
10 #include <zephyr/toolchain.h>
11 #include <zephyr/sys/slist.h>
12 #include <zephyr/sys/iterable_sections.h>
13 #include <zephyr/drivers/usb/udc.h>
14 #include <zephyr/usb/usbd.h>
15
16 #include "usbd_device.h"
17 #include "usbd_desc.h"
18 #include "usbd_config.h"
19 #include "usbd_init.h"
20 #include "usbd_ch9.h"
21 #include "usbd_class.h"
22 #include "usbd_class_api.h"
23 #include "usbd_msg.h"
24
25 #include <zephyr/logging/log.h>
26 LOG_MODULE_REGISTER(usbd_core, CONFIG_USBD_LOG_LEVEL);
27
28 static K_KERNEL_STACK_DEFINE(usbd_stack, CONFIG_USBD_THREAD_STACK_SIZE);
29 static struct k_thread usbd_thread_data;
30
31 K_MSGQ_DEFINE(usbd_msgq, sizeof(struct udc_event),
32 CONFIG_USBD_MAX_UDC_MSG, sizeof(uint32_t));
33
usbd_event_carrier(const struct device * dev,const struct udc_event * const event)34 static int usbd_event_carrier(const struct device *dev,
35 const struct udc_event *const event)
36 {
37 return k_msgq_put(&usbd_msgq, event, K_NO_WAIT);
38 }
39
event_handler_ep_request(struct usbd_context * const uds_ctx,const struct udc_event * const event)40 static int event_handler_ep_request(struct usbd_context *const uds_ctx,
41 const struct udc_event *const event)
42 {
43 struct udc_buf_info *bi;
44 int ret;
45
46 bi = udc_get_buf_info(event->buf);
47
48 if (USB_EP_GET_IDX(bi->ep) == 0) {
49 ret = usbd_handle_ctrl_xfer(uds_ctx, event->buf, bi->err);
50 } else {
51 ret = usbd_class_handle_xfer(uds_ctx, event->buf, bi->err);
52 }
53
54 if (ret) {
55 LOG_ERR("unrecoverable error %d, ep 0x%02x, buf %p",
56 ret, bi->ep, event->buf);
57 }
58
59 return ret;
60 }
61
usbd_class_bcast_event(struct usbd_context * const uds_ctx,struct udc_event * const event)62 static void usbd_class_bcast_event(struct usbd_context *const uds_ctx,
63 struct udc_event *const event)
64 {
65 struct usbd_config_node *cfg_nd;
66 struct usbd_class_node *c_nd;
67
68 if (!usbd_state_is_configured(uds_ctx)) {
69 return;
70 }
71
72 cfg_nd = usbd_config_get_current(uds_ctx);
73 if (cfg_nd == NULL) {
74 LOG_ERR("Failed to get cfg_nd, despite configured state");
75 return;
76 }
77
78 SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) {
79 switch (event->type) {
80 case UDC_EVT_SUSPEND:
81 usbd_class_suspended(c_nd->c_data);
82 break;
83 case UDC_EVT_RESUME:
84 usbd_class_resumed(c_nd->c_data);
85 break;
86 case UDC_EVT_SOF:
87 usbd_class_sof(c_nd->c_data);
88 break;
89 default:
90 break;
91 }
92 }
93 }
94
event_handler_bus_reset(struct usbd_context * const uds_ctx)95 static int event_handler_bus_reset(struct usbd_context *const uds_ctx)
96 {
97 enum udc_bus_speed udc_speed;
98 int ret;
99
100 usbd_status_suspended(uds_ctx, false);
101 ret = udc_set_address(uds_ctx->dev, 0);
102 if (ret) {
103 LOG_ERR("Failed to set default address after bus reset");
104 return ret;
105 }
106
107 ret = usbd_config_set(uds_ctx, 0);
108 if (ret) {
109 LOG_ERR("Failed to set default state after bus reset");
110 return ret;
111 }
112
113 /* There might be pending data stage transfer */
114 if (usbd_ep_dequeue(uds_ctx, USB_CONTROL_EP_IN)) {
115 LOG_ERR("Failed to dequeue control IN");
116 }
117
118 LOG_INF("Actual device speed %u", udc_device_speed(uds_ctx->dev));
119 udc_speed = udc_device_speed(uds_ctx->dev);
120 switch (udc_speed) {
121 case UDC_BUS_SPEED_HS:
122 uds_ctx->status.speed = USBD_SPEED_HS;
123 break;
124 default:
125 uds_ctx->status.speed = USBD_SPEED_FS;
126 }
127
128 uds_ctx->ch9_data.state = USBD_STATE_DEFAULT;
129
130 uds_ctx->status.rwup = false;
131
132 return 0;
133 }
134
135
usbd_event_handler(struct usbd_context * const uds_ctx,struct udc_event * const event)136 static ALWAYS_INLINE void usbd_event_handler(struct usbd_context *const uds_ctx,
137 struct udc_event *const event)
138 {
139 int err = 0;
140
141 switch (event->type) {
142 case UDC_EVT_VBUS_REMOVED:
143 LOG_DBG("VBUS remove event");
144 usbd_msg_pub_simple(uds_ctx, USBD_MSG_VBUS_REMOVED, 0);
145 break;
146 case UDC_EVT_VBUS_READY:
147 LOG_DBG("VBUS detected event");
148 usbd_msg_pub_simple(uds_ctx, USBD_MSG_VBUS_READY, 0);
149 break;
150 case UDC_EVT_SUSPEND:
151 LOG_DBG("SUSPEND event");
152 usbd_status_suspended(uds_ctx, true);
153 usbd_class_bcast_event(uds_ctx, event);
154 usbd_msg_pub_simple(uds_ctx, USBD_MSG_SUSPEND, 0);
155 break;
156 case UDC_EVT_RESUME:
157 LOG_DBG("RESUME event");
158 usbd_status_suspended(uds_ctx, false);
159 usbd_class_bcast_event(uds_ctx, event);
160 usbd_msg_pub_simple(uds_ctx, USBD_MSG_RESUME, 0);
161 break;
162 case UDC_EVT_SOF:
163 usbd_class_bcast_event(uds_ctx, event);
164 break;
165 case UDC_EVT_RESET:
166 LOG_DBG("RESET event");
167 err = event_handler_bus_reset(uds_ctx);
168 usbd_msg_pub_simple(uds_ctx, USBD_MSG_RESET, 0);
169 break;
170 case UDC_EVT_EP_REQUEST:
171 err = event_handler_ep_request(uds_ctx, event);
172 break;
173 case UDC_EVT_ERROR:
174 LOG_ERR("UDC error event");
175 usbd_msg_pub_simple(uds_ctx, USBD_MSG_UDC_ERROR, event->status);
176 break;
177 default:
178 break;
179 };
180
181 if (err) {
182 usbd_msg_pub_simple(uds_ctx, USBD_MSG_STACK_ERROR, err);
183 }
184 }
185
usbd_thread(void * p1,void * p2,void * p3)186 static void usbd_thread(void *p1, void *p2, void *p3)
187 {
188 ARG_UNUSED(p1);
189 ARG_UNUSED(p2);
190 ARG_UNUSED(p3);
191
192 struct usbd_context *uds_ctx;
193 struct udc_event event;
194
195 while (true) {
196 k_msgq_get(&usbd_msgq, &event, K_FOREVER);
197
198 uds_ctx = (void *)udc_get_event_ctx(event.dev);
199 __ASSERT(uds_ctx != NULL && usbd_is_initialized(uds_ctx),
200 "USB device is not initialized");
201 usbd_event_handler(uds_ctx, &event);
202 }
203 }
204
usbd_device_init_core(struct usbd_context * const uds_ctx)205 int usbd_device_init_core(struct usbd_context *const uds_ctx)
206 {
207 int ret;
208
209 ret = udc_init(uds_ctx->dev, usbd_event_carrier, uds_ctx);
210 if (ret != 0) {
211 LOG_ERR("Failed to init device driver");
212 return ret;
213 }
214
215 usbd_set_config_value(uds_ctx, 0);
216
217 ret = usbd_init_configurations(uds_ctx);
218 if (ret != 0) {
219 udc_shutdown(uds_ctx->dev);
220 return ret;
221 }
222
223 return ret;
224 }
225
usbd_device_shutdown_core(struct usbd_context * const uds_ctx)226 int usbd_device_shutdown_core(struct usbd_context *const uds_ctx)
227 {
228 struct usbd_config_node *cfg_nd;
229 int ret;
230
231 SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->hs_configs, cfg_nd, node) {
232 uint8_t cfg_value = usbd_config_get_value(cfg_nd);
233
234 ret = usbd_class_remove_all(uds_ctx, USBD_SPEED_HS, cfg_value);
235 if (ret) {
236 LOG_ERR("Failed to cleanup registered classes, %d", ret);
237 }
238 }
239
240 SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->fs_configs, cfg_nd, node) {
241 uint8_t cfg_value = usbd_config_get_value(cfg_nd);
242
243 ret = usbd_class_remove_all(uds_ctx, USBD_SPEED_FS, cfg_value);
244 if (ret) {
245 LOG_ERR("Failed to cleanup registered classes, %d", ret);
246 }
247 }
248
249 ret = usbd_desc_remove_all(uds_ctx);
250 if (ret) {
251 LOG_ERR("Failed to cleanup descriptors, %d", ret);
252 }
253
254 usbd_device_unregister_all_vreq(uds_ctx);
255
256 return udc_shutdown(uds_ctx->dev);
257 }
258
usbd_pre_init(void)259 static int usbd_pre_init(void)
260 {
261 k_thread_create(&usbd_thread_data, usbd_stack,
262 K_KERNEL_STACK_SIZEOF(usbd_stack),
263 usbd_thread,
264 NULL, NULL, NULL,
265 K_PRIO_COOP(8), 0, K_NO_WAIT);
266
267 k_thread_name_set(&usbd_thread_data, "usbd");
268
269 LOG_DBG("Available USB class iterators:");
270 STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) {
271 atomic_set(&c_nd->state, 0);
272 LOG_DBG("\t%p->%p, name %s", c_nd, c_nd->c_data, c_nd->c_data->name);
273 }
274 STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, usbd_class_node, c_nd) {
275 atomic_set(&c_nd->state, 0);
276 LOG_DBG("\t%p->%p, name %s", c_nd, c_nd->c_data, c_nd->c_data->name);
277 }
278
279 return 0;
280 }
281
282 SYS_INIT(usbd_pre_init, POST_KERNEL, CONFIG_USBD_THREAD_INIT_PRIO);
283