1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/usb/udc.h>
8 #include <zephyr/usb/usbd.h>
9 
10 #include "usbd_device.h"
11 #include "usbd_config.h"
12 #include "usbd_class.h"
13 #include "usbd_ch9.h"
14 #include "usbd_desc.h"
15 
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(usbd_dev, CONFIG_USBD_LOG_LEVEL);
18 
19 /*
20  * All the functions below are part of public USB device support API.
21  */
22 
usbd_device_set_bcd(struct usbd_contex * const uds_ctx,const uint16_t bcd)23 int usbd_device_set_bcd(struct usbd_contex *const uds_ctx,
24 			const uint16_t bcd)
25 {
26 	struct usb_device_descriptor *desc = uds_ctx->desc;
27 	int ret = 0;
28 
29 	usbd_device_lock(uds_ctx);
30 
31 	if (usbd_is_enabled(uds_ctx)) {
32 		ret = -EALREADY;
33 		goto set_bcd_exit;
34 	}
35 
36 	desc->bcdUSB = sys_cpu_to_le16(bcd);
37 
38 set_bcd_exit:
39 	usbd_device_unlock(uds_ctx);
40 	return ret;
41 }
42 
usbd_device_set_vid(struct usbd_contex * const uds_ctx,const uint16_t vid)43 int usbd_device_set_vid(struct usbd_contex *const uds_ctx,
44 			 const uint16_t vid)
45 {
46 	struct usb_device_descriptor *desc = uds_ctx->desc;
47 	int ret = 0;
48 
49 	usbd_device_lock(uds_ctx);
50 
51 	if (usbd_is_enabled(uds_ctx)) {
52 		ret = -EALREADY;
53 		goto set_vid_exit;
54 	}
55 
56 	desc->idVendor = sys_cpu_to_le16(vid);
57 
58 set_vid_exit:
59 	usbd_device_unlock(uds_ctx);
60 	return ret;
61 }
62 
usbd_device_set_pid(struct usbd_contex * const uds_ctx,const uint16_t pid)63 int usbd_device_set_pid(struct usbd_contex *const uds_ctx,
64 			 const uint16_t pid)
65 {
66 	struct usb_device_descriptor *desc = uds_ctx->desc;
67 	int ret = 0;
68 
69 	usbd_device_lock(uds_ctx);
70 
71 	if (usbd_is_enabled(uds_ctx)) {
72 		ret = -EALREADY;
73 		goto set_pid_exit;
74 	}
75 
76 	desc->idProduct = sys_cpu_to_le16(pid);
77 
78 set_pid_exit:
79 	usbd_device_unlock(uds_ctx);
80 	return ret;
81 }
82 
usbd_device_set_class(struct usbd_contex * const uds_ctx,const uint8_t value)83 int usbd_device_set_class(struct usbd_contex *const uds_ctx,
84 			   const uint8_t value)
85 {
86 	struct usb_device_descriptor *desc = uds_ctx->desc;
87 	int ret = 0;
88 
89 	usbd_device_lock(uds_ctx);
90 
91 	if (usbd_is_enabled(uds_ctx)) {
92 		ret = -EALREADY;
93 		goto set_class_exit;
94 	}
95 
96 	desc->bDeviceClass = value;
97 
98 set_class_exit:
99 	usbd_device_unlock(uds_ctx);
100 	return ret;
101 }
102 
usbd_device_set_subclass(struct usbd_contex * const uds_ctx,const uint8_t value)103 int usbd_device_set_subclass(struct usbd_contex *const uds_ctx,
104 			     const uint8_t value)
105 {
106 	struct usb_device_descriptor *desc = uds_ctx->desc;
107 	int ret = 0;
108 
109 	usbd_device_lock(uds_ctx);
110 
111 	if (usbd_is_enabled(uds_ctx)) {
112 		ret = -EALREADY;
113 		goto set_subclass_exit;
114 	}
115 
116 	desc->bDeviceSubClass = value;
117 
118 set_subclass_exit:
119 	usbd_device_unlock(uds_ctx);
120 	return ret;
121 }
122 
usbd_device_set_proto(struct usbd_contex * const uds_ctx,const uint8_t value)123 int usbd_device_set_proto(struct usbd_contex *const uds_ctx,
124 			  const uint8_t value)
125 {
126 	struct usb_device_descriptor *desc = uds_ctx->desc;
127 	int ret = 0;
128 
129 	usbd_device_lock(uds_ctx);
130 
131 	if (usbd_is_enabled(uds_ctx)) {
132 		ret = -EALREADY;
133 		goto set_proto_exit;
134 	}
135 
136 	desc->bDeviceProtocol = value;
137 
138 set_proto_exit:
139 	usbd_device_unlock(uds_ctx);
140 	return ret;
141 }
142 
usbd_wakeup_request(struct usbd_contex * const uds_ctx)143 int usbd_wakeup_request(struct usbd_contex *const uds_ctx)
144 {
145 	struct udc_device_caps caps = udc_caps(uds_ctx->dev);
146 	int ret = 0;
147 
148 	usbd_device_lock(uds_ctx);
149 
150 	if (!caps.rwup) {
151 		LOG_ERR("Remote wakeup feature not supported");
152 		ret = -ENOTSUP;
153 		goto wakeup_request_error;
154 	}
155 
156 	if (!uds_ctx->status.rwup || !usbd_is_suspended(uds_ctx)) {
157 		LOG_ERR("Remote wakeup feature not enabled or not suspended");
158 		ret = -EACCES;
159 		goto wakeup_request_error;
160 	}
161 
162 	ret = udc_host_wakeup(uds_ctx->dev);
163 
164 wakeup_request_error:
165 	usbd_device_unlock(uds_ctx);
166 
167 	return ret;
168 }
169 
usbd_is_suspended(struct usbd_contex * uds_ctx)170 bool usbd_is_suspended(struct usbd_contex *uds_ctx)
171 {
172 	return uds_ctx->status.suspended;
173 }
174 
usbd_init(struct usbd_contex * const uds_ctx)175 int usbd_init(struct usbd_contex *const uds_ctx)
176 {
177 	int ret;
178 
179 	usbd_device_lock(uds_ctx);
180 
181 	if (uds_ctx->dev == NULL) {
182 		ret = -ENODEV;
183 		goto init_exit;
184 	}
185 
186 	if (usbd_is_initialized(uds_ctx)) {
187 		LOG_WRN("USB device support is already initialized");
188 		ret = -EALREADY;
189 		goto init_exit;
190 	}
191 
192 	if (!device_is_ready(uds_ctx->dev)) {
193 		LOG_ERR("USB device controller is not ready");
194 		ret = -ENODEV;
195 		goto init_exit;
196 	}
197 
198 	ret = usbd_device_init_core(uds_ctx);
199 	if (ret) {
200 		goto init_exit;
201 	}
202 
203 	memset(&uds_ctx->ch9_data, 0, sizeof(struct usbd_ch9_data));
204 	uds_ctx->status.initialized = true;
205 
206 init_exit:
207 	usbd_device_unlock(uds_ctx);
208 	return ret;
209 }
210 
usbd_enable(struct usbd_contex * const uds_ctx)211 int usbd_enable(struct usbd_contex *const uds_ctx)
212 {
213 	int ret;
214 
215 	usbd_device_lock(uds_ctx);
216 
217 	if (!usbd_is_initialized(uds_ctx)) {
218 		LOG_WRN("USB device support is not initialized");
219 		ret = -EPERM;
220 		goto enable_exit;
221 	}
222 
223 	if (usbd_is_enabled(uds_ctx)) {
224 		LOG_WRN("USB device support is already enabled");
225 		ret = -EALREADY;
226 		goto enable_exit;
227 	}
228 
229 	ret = udc_enable(uds_ctx->dev);
230 	if (ret != 0) {
231 		LOG_ERR("Failed to enable controller");
232 		goto enable_exit;
233 	}
234 
235 	ret = usbd_init_control_pipe(uds_ctx);
236 	if (ret != 0) {
237 		udc_disable(uds_ctx->dev);
238 		goto enable_exit;
239 	}
240 
241 	uds_ctx->status.enabled = true;
242 
243 enable_exit:
244 	usbd_device_unlock(uds_ctx);
245 	return ret;
246 }
247 
usbd_disable(struct usbd_contex * const uds_ctx)248 int usbd_disable(struct usbd_contex *const uds_ctx)
249 {
250 	int ret;
251 
252 	if (!usbd_is_enabled(uds_ctx)) {
253 		LOG_WRN("USB device support is already disabled");
254 		return -EALREADY;
255 	}
256 
257 	usbd_device_lock(uds_ctx);
258 
259 	ret = usbd_config_set(uds_ctx, 0);
260 	if (ret) {
261 		LOG_ERR("Failed to reset configuration");
262 	}
263 
264 	ret = udc_disable(uds_ctx->dev);
265 	if (ret) {
266 		LOG_ERR("Failed to disable USB device");
267 	}
268 
269 	uds_ctx->status.enabled = false;
270 
271 	usbd_device_unlock(uds_ctx);
272 
273 	return ret;
274 }
275 
usbd_shutdown(struct usbd_contex * const uds_ctx)276 int usbd_shutdown(struct usbd_contex *const uds_ctx)
277 {
278 	int ret;
279 
280 	usbd_device_lock(uds_ctx);
281 
282 	/* TODO: control request dequeue ? */
283 	ret = usbd_device_shutdown_core(uds_ctx);
284 	if (ret) {
285 		LOG_ERR("Failed to shutdown USB device");
286 	}
287 
288 	uds_ctx->status.initialized = false;
289 	usbd_device_unlock(uds_ctx);
290 
291 	return 0;
292 }
293