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
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(usbd_core, CONFIG_USBD_LOG_LEVEL);
26
27 static K_KERNEL_STACK_DEFINE(usbd_stack, CONFIG_USBD_THREAD_STACK_SIZE);
28 static struct k_thread usbd_thread_data;
29
30 K_MSGQ_DEFINE(usbd_msgq, sizeof(struct udc_event),
31 CONFIG_USBD_MAX_UDC_MSG, sizeof(uint32_t));
32
usbd_event_carrier(const struct device * dev,const struct udc_event * const event)33 static int usbd_event_carrier(const struct device *dev,
34 const struct udc_event *const event)
35 {
36 return k_msgq_put(&usbd_msgq, event, K_NO_WAIT);
37 }
38
event_handler_ep_request(struct usbd_contex * const uds_ctx,const struct udc_event * const event)39 static int event_handler_ep_request(struct usbd_contex *const uds_ctx,
40 const struct udc_event *const event)
41 {
42 struct udc_buf_info *bi;
43 int ret;
44
45 bi = udc_get_buf_info(event->buf);
46
47 if (USB_EP_GET_IDX(bi->ep) == 0) {
48 ret = usbd_handle_ctrl_xfer(uds_ctx, event->buf, bi->err);
49 } else {
50 ret = usbd_class_handle_xfer(uds_ctx, event->buf, bi->err);
51 }
52
53 if (ret) {
54 LOG_ERR("unrecoverable error %d, ep 0x%02x, buf %p",
55 ret, bi->ep, event->buf);
56 /* TODO: Shutdown USB device gracefully */
57 k_panic();
58 }
59
60 return ret;
61 }
62
usbd_class_bcast_event(struct usbd_contex * const uds_ctx,struct udc_event * const event)63 static void usbd_class_bcast_event(struct usbd_contex *const uds_ctx,
64 struct udc_event *const event)
65 {
66 struct usbd_config_node *cfg_nd;
67 struct usbd_class_node *c_nd;
68
69 if (!usbd_state_is_configured(uds_ctx)) {
70 return;
71 }
72
73 cfg_nd = usbd_config_get_current(uds_ctx);
74 if (cfg_nd == NULL) {
75 LOG_ERR("Failed to get cfg_nd, despite configured state");
76 return;
77 }
78
79 SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) {
80 switch (event->type) {
81 case UDC_EVT_SUSPEND:
82 usbd_class_suspended(c_nd);
83 break;
84 case UDC_EVT_RESUME:
85 usbd_class_resumed(c_nd);
86 break;
87 default:
88 break;
89 }
90 }
91 }
92
event_handler_bus_reset(struct usbd_contex * const uds_ctx)93 static int event_handler_bus_reset(struct usbd_contex *const uds_ctx)
94 {
95 int ret;
96
97 LOG_WRN("Bus reset event");
98
99 usbd_status_suspended(uds_ctx, false);
100 ret = udc_set_address(uds_ctx->dev, 0);
101 if (ret) {
102 LOG_ERR("Failed to set default address after bus reset");
103 return ret;
104 }
105
106 ret = usbd_config_set(uds_ctx, 0);
107 if (ret) {
108 LOG_ERR("Failed to set default state after bus reset");
109 return ret;
110 }
111
112 /* There might be pending data stage transfer */
113 if (usbd_ep_dequeue(uds_ctx, USB_CONTROL_EP_IN)) {
114 LOG_ERR("Failed to dequeue control IN");
115 }
116
117 LOG_INF("Actual device speed %d", udc_device_speed(uds_ctx->dev));
118 uds_ctx->ch9_data.state = USBD_STATE_DEFAULT;
119
120 return 0;
121 }
122
123 /* TODO: Add event broadcaster to user application */
usbd_event_handler(struct usbd_contex * const uds_ctx,struct udc_event * const event)124 static ALWAYS_INLINE int usbd_event_handler(struct usbd_contex *const uds_ctx,
125 struct udc_event *const event)
126 {
127 int ret = 0;
128
129 switch (event->type) {
130 case UDC_EVT_VBUS_REMOVED:
131 LOG_WRN("VBUS remove event");
132 break;
133 case UDC_EVT_VBUS_READY:
134 LOG_WRN("VBUS detected event");
135 break;
136 case UDC_EVT_SUSPEND:
137 LOG_WRN("SUSPEND event");
138 usbd_status_suspended(uds_ctx, true);
139 usbd_class_bcast_event(uds_ctx, event);
140 break;
141 case UDC_EVT_RESUME:
142 LOG_WRN("RESUME event");
143 usbd_status_suspended(uds_ctx, false);
144 usbd_class_bcast_event(uds_ctx, event);
145 break;
146 case UDC_EVT_SOF:
147 usbd_class_bcast_event(uds_ctx, event);
148 break;
149 case UDC_EVT_RESET:
150 LOG_WRN("RESET event");
151 ret = event_handler_bus_reset(uds_ctx);
152 break;
153 case UDC_EVT_EP_REQUEST:
154 ret = event_handler_ep_request(uds_ctx, event);
155 break;
156 case UDC_EVT_ERROR:
157 LOG_ERR("Error event");
158 break;
159 default:
160 break;
161 };
162
163 return ret;
164 }
165
usbd_thread(void)166 static void usbd_thread(void)
167 {
168 struct udc_event event;
169
170 while (true) {
171 k_msgq_get(&usbd_msgq, &event, K_FOREVER);
172
173 STRUCT_SECTION_FOREACH(usbd_contex, uds_ctx) {
174 if (uds_ctx->dev == event.dev &&
175 usbd_is_initialized(uds_ctx)) {
176 usbd_event_handler(uds_ctx, &event);
177 }
178 }
179 }
180 }
181
usbd_device_init_core(struct usbd_contex * const uds_ctx)182 int usbd_device_init_core(struct usbd_contex *const uds_ctx)
183 {
184 int ret;
185
186 ret = udc_init(uds_ctx->dev, usbd_event_carrier);
187 if (ret != 0) {
188 LOG_ERR("Failed to init device driver");
189 return ret;
190 }
191
192 usbd_set_config_value(uds_ctx, 0);
193
194 ret = usbd_init_configurations(uds_ctx);
195 if (ret != 0) {
196 udc_shutdown(uds_ctx->dev);
197 return ret;
198 }
199
200 return ret;
201 }
202
usbd_device_shutdown_core(struct usbd_contex * const uds_ctx)203 int usbd_device_shutdown_core(struct usbd_contex *const uds_ctx)
204 {
205 struct usbd_config_node *cfg_nd;
206 int ret;
207
208 SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->configs, cfg_nd, node) {
209 uint8_t cfg_value = usbd_config_get_value(cfg_nd);
210
211 ret = usbd_class_remove_all(uds_ctx, cfg_value);
212 if (ret) {
213 LOG_ERR("Failed to cleanup registered classes, %d", ret);
214 }
215 }
216
217 ret = usbd_desc_remove_all(uds_ctx);
218 if (ret) {
219 LOG_ERR("Failed to cleanup descriptors, %d", ret);
220 }
221
222 return udc_shutdown(uds_ctx->dev);
223 }
224
usbd_pre_init(void)225 static int usbd_pre_init(void)
226 {
227 k_thread_create(&usbd_thread_data, usbd_stack,
228 K_KERNEL_STACK_SIZEOF(usbd_stack),
229 (k_thread_entry_t)usbd_thread,
230 NULL, NULL, NULL,
231 K_PRIO_COOP(8), 0, K_NO_WAIT);
232
233 k_thread_name_set(&usbd_thread_data, "usbd");
234
235 LOG_DBG("Available USB class nodes:");
236 STRUCT_SECTION_FOREACH(usbd_class_node, node) {
237 atomic_set(&node->data->state, 0);
238 LOG_DBG("\t%p, name %s", node, node->name);
239 }
240
241 return 0;
242 }
243
244 SYS_INIT(usbd_pre_init, POST_KERNEL, CONFIG_USBD_THREAD_INIT_PRIO);
245