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