1 /*
2 * Copyright (c) 2023,2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/usb/usbh.h>
8 #include <zephyr/sys/byteorder.h>
9
10 #include "usbh_device.h"
11 #include "usbh_ch9.h"
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(usbh_dev, CONFIG_USBH_LOG_LEVEL);
15
16 K_MEM_SLAB_DEFINE_STATIC(usb_device_slab, sizeof(struct usb_device),
17 CONFIG_USBH_USB_DEVICE_MAX, sizeof(void *));
18
19 K_HEAP_DEFINE(usb_device_heap, CONFIG_USBH_USB_DEVICE_HEAP);
20
usbh_device_alloc(struct usbh_contex * const uhs_ctx)21 struct usb_device *usbh_device_alloc(struct usbh_contex *const uhs_ctx)
22 {
23 struct usb_device *udev;
24
25 if (k_mem_slab_alloc(&usb_device_slab, (void **)&udev, K_NO_WAIT)) {
26 LOG_ERR("Failed to allocate USB device memory");
27 return NULL;
28 }
29
30 memset(udev, 0, sizeof(struct usb_device));
31 udev->ctx = uhs_ctx;
32 sys_dlist_append(&uhs_ctx->udevs, &udev->node);
33 k_mutex_init(&udev->mutex);
34
35 return udev;
36 }
37
usbh_device_free(struct usb_device * const udev)38 void usbh_device_free(struct usb_device *const udev)
39 {
40 struct usbh_contex *const uhs_ctx = udev->ctx;
41
42 sys_bitarray_clear_bit(uhs_ctx->addr_ba, udev->addr);
43 sys_dlist_remove(&udev->node);
44 if (udev->cfg_desc != NULL) {
45 k_heap_free(&usb_device_heap, udev->cfg_desc);
46 }
47
48 k_mem_slab_free(&usb_device_slab, (void *)udev);
49 }
50
usbh_device_get_any(struct usbh_contex * const uhs_ctx)51 struct usb_device *usbh_device_get_any(struct usbh_contex *const uhs_ctx)
52 {
53 sys_dnode_t *const node = sys_dlist_peek_head(&uhs_ctx->udevs);
54 struct usb_device *udev;
55
56 udev = SYS_DLIST_CONTAINER(node, udev, node);
57
58 return udev;
59 }
60
validate_device_mps0(const struct usb_device * const udev)61 static int validate_device_mps0(const struct usb_device *const udev)
62 {
63 const uint8_t mps0 = udev->dev_desc.bMaxPacketSize0;
64
65 if (udev->speed == USB_SPEED_SPEED_SS || udev->speed == USB_SPEED_SPEED_LS) {
66 LOG_ERR("USB device speed not supported");
67 return -ENOTSUP;
68 }
69
70 if (udev->speed == USB_SPEED_SPEED_HS) {
71 if (mps0 != 64) {
72 LOG_ERR("HS device has wrong bMaxPacketSize0 %u", mps0);
73 return -EINVAL;
74 }
75 }
76
77 if (udev->speed == USB_SPEED_SPEED_FS) {
78 if (mps0 != 8 && mps0 != 16 && mps0 != 32 && mps0 != 64) {
79 LOG_ERR("FS device has wrong bMaxPacketSize0 %u", mps0);
80 return -EINVAL;
81 }
82 }
83
84 return 0;
85 }
86
alloc_device_address(struct usb_device * const udev,uint8_t * const addr)87 static int alloc_device_address(struct usb_device *const udev, uint8_t *const addr)
88 {
89 struct usbh_contex *const uhs_ctx = udev->ctx;
90 int val;
91 int err;
92
93 for (unsigned int i = 1; i < 128; i++) {
94 err = sys_bitarray_test_and_set_bit(uhs_ctx->addr_ba, i, &val);
95 if (err) {
96 return err;
97 }
98
99 if (val == 0) {
100 *addr = i;
101 return 0;
102 }
103 }
104
105 return -ENOENT;
106 }
107
108 enum ep_op {
109 EP_OP_TEST, /* Verify endpont descriptor */
110 EP_OP_UP, /* Enable endpoint and update endpoint pointers */
111 EP_OP_DOWN, /* Disable endpoint and update endpoint pointers */
112 };
113
assign_ep_desc_ptr(struct usb_device * const udev,const uint8_t ep,void * const ptr)114 static void assign_ep_desc_ptr(struct usb_device *const udev,
115 const uint8_t ep, void *const ptr)
116 {
117 uint8_t idx = USB_EP_GET_IDX(ep) & 0xF;
118
119 if (USB_EP_DIR_IS_IN(ep)) {
120 udev->ep_in[idx].desc = ptr;
121 } else {
122 udev->ep_out[idx].desc = ptr;
123 }
124 }
125
handle_ep_op(struct usb_device * const udev,const enum ep_op op,const uint8_t ep,struct usb_ep_descriptor * const ep_desc)126 static int handle_ep_op(struct usb_device *const udev,
127 const enum ep_op op, const uint8_t ep,
128 struct usb_ep_descriptor *const ep_desc)
129 {
130 switch (op) {
131 case EP_OP_TEST:
132 break;
133 case EP_OP_UP:
134 if (ep_desc == NULL) {
135 return -ENOTSUP;
136 }
137
138 assign_ep_desc_ptr(udev, ep_desc->bEndpointAddress, ep_desc);
139 break;
140 case EP_OP_DOWN:
141 assign_ep_desc_ptr(udev, ep, NULL);
142 break;
143 }
144
145 return 0;
146 }
147
device_interface_modify(struct usb_device * const udev,const enum ep_op op,const uint8_t iface,const uint8_t alt)148 static int device_interface_modify(struct usb_device *const udev,
149 const enum ep_op op,
150 const uint8_t iface, const uint8_t alt)
151 {
152 struct usb_cfg_descriptor *cfg_desc = udev->cfg_desc;
153 struct usb_if_descriptor *if_desc = NULL;
154 struct usb_ep_descriptor *ep_desc;
155 struct usb_desc_header *dhp;
156 bool found_iface = false;
157 void *desc_end;
158 int err;
159
160 dhp = udev->ifaces[iface].dhp;
161 desc_end = (void *)((uint8_t *)udev->cfg_desc + cfg_desc->wTotalLength);
162
163 while (dhp != NULL && (void *)dhp < desc_end) {
164 if (dhp->bDescriptorType == USB_DESC_INTERFACE) {
165 if_desc = (struct usb_if_descriptor *)dhp;
166
167 if (found_iface) {
168 break;
169 }
170
171 if (if_desc->bInterfaceNumber == iface &&
172 if_desc->bAlternateSetting == alt) {
173 found_iface = true;
174 LOG_DBG("Found interface %u alternate %u", iface, alt);
175 if (if_desc->bNumEndpoints == 0) {
176 LOG_DBG("No endpoints, skip interface");
177 break;
178 }
179 }
180 }
181
182 if (dhp->bDescriptorType == USB_DESC_ENDPOINT && found_iface) {
183 ep_desc = (struct usb_ep_descriptor *)dhp;
184 err = handle_ep_op(udev, op, ep_desc->bEndpointAddress, ep_desc);
185 if (err) {
186 return err;
187 }
188
189 LOG_INF("Modify interface %u ep 0x%02x by op %u",
190 iface, ep_desc->bEndpointAddress, op);
191 }
192
193 dhp = (void *)((uint8_t *)dhp + dhp->bLength);
194 }
195
196
197 return found_iface ? 0 : -ENODATA;
198 }
199
usbh_device_interface_set(struct usb_device * const udev,const uint8_t iface,const uint8_t alt,const bool dry)200 int usbh_device_interface_set(struct usb_device *const udev,
201 const uint8_t iface, const uint8_t alt,
202 const bool dry)
203 {
204 uint8_t cur_alt;
205 int err;
206
207 if (iface > UHC_INTERFACES_MAX) {
208 LOG_ERR("Unsupported number of interfaces");
209 return -EINVAL;
210 }
211
212 err = k_mutex_lock(&udev->mutex, K_NO_WAIT);
213 if (err) {
214 LOG_ERR("Failed to lock USB device");
215 return err;
216 }
217
218 if (!dry) {
219 err = usbh_req_set_alt(udev, iface, alt);
220 if (err) {
221 LOG_ERR("Set Interface %u alternate %u request failed", iface, alt);
222 goto error;
223 }
224 }
225
226 cur_alt = udev->ifaces[iface].alternate;
227 LOG_INF("Set Interfaces %u, alternate %u -> %u", iface, cur_alt, alt);
228 if (alt == cur_alt) {
229 LOG_DBG("Already active interface alternate");
230 goto error;
231 }
232
233 /* Test if interface and interface alternate exist */
234 err = device_interface_modify(udev, EP_OP_TEST, iface, alt);
235 if (err) {
236 LOG_ERR("No interface %u with alternate %u", iface, alt);
237 goto error;
238 }
239
240 /* Shutdown current interface alternate */
241 err = device_interface_modify(udev, EP_OP_DOWN, iface, cur_alt);
242 if (err) {
243 LOG_ERR("Failed to shutdown interface %u alternate %u", iface, alt);
244 goto error;
245 }
246
247 /* Setup new interface alternate */
248 err = device_interface_modify(udev, EP_OP_UP, iface, alt);
249 if (err) {
250 LOG_ERR("Failed to setup interface %u alternate %u", iface, cur_alt);
251 goto error;
252 }
253
254 udev->ifaces[iface].alternate = alt;
255
256 error:
257 k_mutex_unlock(&udev->mutex);
258
259 return 0;
260 }
261
parse_configuration_descriptor(struct usb_device * const udev)262 static int parse_configuration_descriptor(struct usb_device *const udev)
263 {
264 struct usb_cfg_descriptor *cfg_desc = udev->cfg_desc;
265 struct usb_association_descriptor *iad = NULL;
266 struct usb_if_descriptor *if_desc = NULL;
267 struct usb_ep_descriptor *ep_desc;
268 struct usb_desc_header *dhp;
269 uint8_t tmp_nif = 0;
270 void *desc_end;
271
272 dhp = (void *)((uint8_t *)udev->cfg_desc + cfg_desc->bLength);
273 desc_end = (void *)((uint8_t *)udev->cfg_desc + cfg_desc->wTotalLength);
274
275 while ((dhp->bDescriptorType != 0 || dhp->bLength != 0) && (void *)dhp < desc_end) {
276 if (dhp->bDescriptorType == USB_DESC_INTERFACE_ASSOC) {
277 iad = (struct usb_association_descriptor *)dhp;
278 LOG_DBG("bFirstInterface %u", iad->bFirstInterface);
279 }
280
281 if (dhp->bDescriptorType == USB_DESC_INTERFACE) {
282 if_desc = (struct usb_if_descriptor *)dhp;
283 LOG_DBG("bInterfaceNumber %u bAlternateSetting %u",
284 if_desc->bInterfaceNumber, if_desc->bAlternateSetting);
285
286 if (if_desc->bAlternateSetting == 0) {
287 if (tmp_nif >= UHC_INTERFACES_MAX) {
288 LOG_ERR("Unsupported number of interfaces");
289 return -EINVAL;
290 }
291
292 udev->ifaces[tmp_nif].dhp = dhp;
293 tmp_nif++;
294 }
295 }
296
297 if (dhp->bDescriptorType == USB_DESC_ENDPOINT) {
298 ep_desc = (struct usb_ep_descriptor *)dhp;
299
300 ep_desc->wMaxPacketSize = sys_le16_to_cpu(ep_desc->wMaxPacketSize);
301 LOG_DBG("bEndpointAddress 0x%02x wMaxPacketSize %u",
302 ep_desc->bEndpointAddress, ep_desc->wMaxPacketSize);
303
304 if (if_desc != NULL && if_desc->bAlternateSetting == 0) {
305 assign_ep_desc_ptr(udev, ep_desc->bEndpointAddress, ep_desc);
306 }
307 }
308
309 dhp = (void *)((uint8_t *)dhp + dhp->bLength);
310 }
311
312 if (cfg_desc->bNumInterfaces != tmp_nif) {
313 LOG_ERR("The configuration has an incorrect number of interfaces");
314 return -EINVAL;
315 }
316
317 return 0;
318 }
319
reset_configuration(struct usb_device * const udev)320 static void reset_configuration(struct usb_device *const udev)
321 {
322 /* Reset all endpoint pointers */
323 memset(udev->ep_in, 0, sizeof(udev->ep_in));
324 memset(udev->ep_out, 0, sizeof(udev->ep_out));
325
326 /* Reset all interface pointers */
327 memset(udev->ifaces, 0, sizeof(udev->ifaces));
328
329 udev->actual_cfg = 0;
330 udev->state = USB_STATE_ADDRESSED;
331 }
332
usbh_device_set_configuration(struct usb_device * const udev,const uint8_t num)333 int usbh_device_set_configuration(struct usb_device *const udev, const uint8_t num)
334 {
335 struct usb_cfg_descriptor cfg_desc;
336 uint8_t idx;
337 int err;
338
339 err = k_mutex_lock(&udev->mutex, K_NO_WAIT);
340 if (err) {
341 LOG_ERR("Failed to lock USB device");
342 return err;
343 }
344
345 if (udev->actual_cfg == num) {
346 LOG_INF("Already active device configuration");
347 goto error;
348 }
349
350 if (num == 0) {
351 reset_configuration(udev);
352 err = usbh_req_set_cfg(udev, num);
353 if (err) {
354 LOG_ERR("Set Configuration %u request failed", num);
355 }
356
357 goto error;
358 }
359
360 idx = num - 1;
361
362 err = usbh_req_desc_cfg(udev, idx, sizeof(cfg_desc), &cfg_desc);
363 if (err) {
364 LOG_ERR("Failed to read configuration %u descriptor", num);
365 goto error;
366 }
367
368 if (cfg_desc.bDescriptorType != USB_DESC_CONFIGURATION) {
369 LOG_ERR("Failed to read configuration descriptor");
370 err = -EINVAL;
371 goto error;
372 }
373
374 if (cfg_desc.bNumInterfaces == 0) {
375 LOG_ERR("Configuration %u has no interfaces", cfg_desc.bNumInterfaces);
376 err = -EINVAL;
377 goto error;
378 }
379
380 if (cfg_desc.bNumInterfaces >= UHC_INTERFACES_MAX) {
381 LOG_ERR("Unsupported number of interfaces");
382 err = -EINVAL;
383 goto error;
384 }
385
386 udev->cfg_desc = k_heap_alloc(&usb_device_heap,
387 cfg_desc.wTotalLength,
388 K_NO_WAIT);
389 if (udev->cfg_desc == NULL) {
390 LOG_ERR("Failed to allocate memory for configuration descriptor");
391 err = -ENOMEM;
392 goto error;
393 }
394
395 err = usbh_req_set_cfg(udev, num);
396 if (err) {
397 LOG_ERR("Set Configuration %u request failed", num);
398 goto error;
399 }
400
401 memset(udev->cfg_desc, 0, cfg_desc.wTotalLength);
402 if (udev->state == USB_STATE_CONFIGURED) {
403 reset_configuration(udev);
404 }
405
406 err = usbh_req_desc_cfg(udev, idx, cfg_desc.wTotalLength, udev->cfg_desc);
407 if (err) {
408 LOG_ERR("Failed to read configuration descriptor");
409 k_heap_free(&usb_device_heap, udev->cfg_desc);
410 goto error;
411 }
412
413 if (memcmp(udev->cfg_desc, &cfg_desc, sizeof(cfg_desc))) {
414 LOG_ERR("Configuration descriptor read mismatch");
415 k_heap_free(&usb_device_heap, udev->cfg_desc);
416 goto error;
417 }
418
419 LOG_INF("Configuration %u bNumInterfaces %u",
420 cfg_desc.bConfigurationValue, cfg_desc.bNumInterfaces);
421
422 err = parse_configuration_descriptor(udev);
423 if (err) {
424 k_heap_free(&usb_device_heap, udev->cfg_desc);
425 goto error;
426 }
427
428 udev->actual_cfg = num;
429 udev->state = USB_STATE_CONFIGURED;
430
431 error:
432 k_mutex_unlock(&udev->mutex);
433
434 return err;
435 }
436
usbh_device_init(struct usb_device * const udev)437 int usbh_device_init(struct usb_device *const udev)
438 {
439 struct usbh_contex *const uhs_ctx = udev->ctx;
440 uint8_t new_addr;
441 int err;
442
443 if (udev->state != USB_STATE_DEFAULT) {
444 LOG_ERR("USB device is not in default state");
445 return -EALREADY;
446 }
447
448 err = k_mutex_lock(&udev->mutex, K_NO_WAIT);
449 if (err) {
450 LOG_ERR("Failed to lock USB device");
451 return err;
452 }
453
454 /* FIXME: The port to which the device is connected should be reset. */
455 err = uhc_bus_reset(uhs_ctx->dev);
456 if (err) {
457 LOG_ERR("Failed to signal bus reset");
458 return err;
459 }
460
461 /*
462 * Limit mps0 to the minimum supported by full-speed devices until the
463 * device descriptor is read.
464 */
465 udev->dev_desc.bMaxPacketSize0 = 8;
466 err = usbh_req_desc_dev(udev, 8, &udev->dev_desc);
467 if (err) {
468 LOG_ERR("Failed to read device descriptor");
469 goto error;
470 }
471
472 err = validate_device_mps0(udev);
473 if (err) {
474 goto error;
475 }
476
477 err = usbh_req_desc_dev(udev, sizeof(udev->dev_desc), &udev->dev_desc);
478 if (err) {
479 LOG_ERR("Failed to read device descriptor");
480 goto error;
481 }
482
483 if (!udev->dev_desc.bNumConfigurations) {
484 LOG_ERR("Device has no configurations, bNumConfigurations %d",
485 udev->dev_desc.bNumConfigurations);
486 goto error;
487 }
488
489 err = alloc_device_address(udev, &new_addr);
490 if (err) {
491 LOG_ERR("Failed to allocate device address");
492 goto error;
493 }
494
495 err = usbh_req_set_address(udev, new_addr);
496 if (err) {
497 LOG_ERR("Failed to set device address");
498 udev->addr = 0;
499
500 goto error;
501 }
502
503 udev->addr = new_addr;
504 udev->state = USB_STATE_ADDRESSED;
505
506 LOG_INF("New device with address %u state %u", udev->addr, udev->state);
507
508 err = usbh_device_set_configuration(udev, 1);
509 if (err) {
510 LOG_ERR("Failed to configure new device with address %u", udev->addr);
511 }
512
513 error:
514 k_mutex_unlock(&udev->mutex);
515
516 return err;
517 }
518