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