Skip to content

Commit 3570940

Browse files
Josuah DemangeonAidenHu
andcommitted
usb: host: implement class filtering and descriptor browsing
Add utilities to filter a class and search the next descriptor of a given type. This can be used to in combination to seek device information from the USB descriptors and try to match a host class instance given a set of filters. Co-authored-by: Aiden Hu <[email protected]> Signed-off-by: Josuah Demangeon <[email protected]>
1 parent aa8ad95 commit 3570940

File tree

5 files changed

+213
-15
lines changed

5 files changed

+213
-15
lines changed

include/zephyr/usb/usbh.h

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
2-
* Copyright (c) 2022 Nordic Semiconductor ASA
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* Copyright 2025 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -72,18 +73,6 @@ struct usbh_context {
7273
.addr_ba = &ba_##device_name, \
7374
}
7475

75-
/**
76-
* @brief USB Class Code triple
77-
*/
78-
struct usbh_code_triple {
79-
/** Device Class Code */
80-
uint8_t dclass;
81-
/** Class Subclass Code */
82-
uint8_t sub;
83-
/** Class Protocol Code */
84-
uint8_t proto;
85-
};
86-
8776
struct usbh_class_data;
8877

8978
/**
@@ -120,8 +109,6 @@ struct usbh_class_data {
120109
const char *name;
121110
/** Pointer to USB host stack context structure */
122111
struct usbh_context *uhs_ctx;
123-
/** Class code supported by this instance */
124-
struct usbh_code_triple code;
125112
/** Pointer to host support class API */
126113
struct usbh_class_api *api;
127114
/** Pointer to private data */

subsys/usb/host/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ zephyr_library_sources(
99
usbh_ch9.c
1010
usbh_class.c
1111
usbh_core.c
12+
usbh_desc.c
1213
usbh_device.c
1314
)
1415

subsys/usb/host/usbh_class.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* Copyright 2025 NXP
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#ifndef ZEPHYR_INCLUDE_USBD_CLASS_H
9+
#define ZEPHYR_INCLUDE_USBD_CLASS_H
10+
11+
#include <zephyr/usb/usbh.h>
12+
13+
/**
14+
* @brief Information about a device, which is relevant for matching a particular class.
15+
*/
16+
struct usbh_class_filter {
17+
/** Vendor ID */
18+
uint16_t vid;
19+
/** Product ID */
20+
uint16_t pid;
21+
/** Device Class Code */
22+
uint8_t dclass;
23+
/** Class Subclass Code */
24+
uint8_t sub;
25+
/** Class Protocol Code */
26+
uint8_t proto;
27+
/** Flags that tell which field to match */
28+
uint8_t flags;
29+
};
30+
31+
/** Match a device's vendor ID */
32+
#define USBH_CLASS_MATCH_VID BIT(1)
33+
34+
/** Match a device's product ID */
35+
#define USBH_CLASS_MATCH_PID BIT(2)
36+
37+
/** Match a class code */
38+
#define USBH_CLASS_MATCH_DCLASS BIT(3)
39+
40+
/** Match a subclass code */
41+
#define USBH_CLASS_MATCH_SUB BIT(4)
42+
43+
/** Match a protocol code */
44+
#define USBH_CLASS_MATCH_PROTO BIT(5)
45+
46+
/** Match a code triple */
47+
#define USBH_CLASS_MATCH_CODE_TRIPLE \
48+
(USBH_CLASS_MATCH_DCLASS | USBH_CLASS_MATCH_SUB | USBH_CLASS_MATCH_PROTO)
49+
50+
/**
51+
* @brief Match an USB host class (a driver) against a device descriptor.
52+
*
53+
* @param[in] filters Array of filter rules to match
54+
* @param[in] n_filters Number of rules in the array.
55+
* @param[in] desc USB Device descriptor to match against each rule
56+
* @retval true if the USB Device descriptor matches at least one rule.
57+
*/
58+
bool usbh_class_is_matching(struct usbh_class_filter *const filters, size_t n_filters,
59+
struct usb_device_descriptor *const desc);
60+
61+
#endif /* ZEPHYR_INCLUDE_USBD_CLASS_H */

subsys/usb/host/usbh_desc.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* Copyright NXP
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/usb/usb_ch9.h>
9+
#include "usbh_desc.h"
10+
11+
const struct usb_desc_header *usbh_desc_get_next(const struct usb_desc_header *const desc,
12+
const void *const desc_end)
13+
{
14+
const struct usb_desc_header *next;
15+
16+
if (desc == NULL) {
17+
return NULL;
18+
}
19+
20+
next = (const struct usb_desc_header *)((uint8_t *)desc + desc->bLength);
21+
22+
/* Validate the bLength field to make sure it does not point past the end */
23+
if ((uint8_t *)next >= (uint8_t *)desc_end ||
24+
(uint8_t *)next + next->bLength > (uint8_t *)desc_end ||
25+
desc->bLength == 0) {
26+
return NULL;
27+
}
28+
29+
return next;
30+
}
31+
32+
const struct usb_desc_header *usbh_desc_get_by_type(const void *const desc_beg,
33+
const void *const desc_end,
34+
uint32_t type_mask)
35+
{
36+
const struct usb_desc_header *desc;
37+
38+
if (desc_beg == NULL) {
39+
return NULL;
40+
}
41+
42+
for (desc = desc_beg; desc != NULL; desc = usbh_desc_get_next(desc, desc_end)) {
43+
if ((BIT(desc->bDescriptorType) & type_mask) != 0) {
44+
return desc;
45+
}
46+
}
47+
48+
return NULL;
49+
}
50+
51+
const struct usb_desc_header *usbh_desc_get_by_ifnum(const void *const desc_beg,
52+
const void *const desc_end,
53+
const uint8_t ifnum)
54+
{
55+
const struct usb_desc_header *desc;
56+
57+
if (desc_beg == NULL) {
58+
return NULL;
59+
}
60+
61+
for (desc = desc_beg; desc != NULL; desc = usbh_desc_get_next(desc, desc_end)) {
62+
if (desc->bDescriptorType == USB_DESC_INTERFACE &&
63+
((struct usb_if_descriptor *)desc)->bInterfaceNumber == ifnum) {
64+
return desc;
65+
}
66+
if (desc->bDescriptorType == USB_DESC_INTERFACE_ASSOC &&
67+
((struct usb_association_descriptor *)desc)->bFirstInterface == ifnum) {
68+
return desc;
69+
}
70+
}
71+
72+
return NULL;
73+
}

subsys/usb/host/usbh_desc.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief Descriptor matching and searching utilities
10+
*
11+
* This file contains utilities to browse USB descriptors returned by a device
12+
* according to the USB Specification 2.0 Chapter 9.
13+
*/
14+
15+
#ifndef ZEPHYR_INCLUDE_USBH_DESC_H
16+
#define ZEPHYR_INCLUDE_USBH_DESC_H
17+
18+
#include <stdint.h>
19+
20+
#include <zephyr/usb/usbh.h>
21+
22+
/**
23+
* @brief Get the next descriptor in an array of descriptors.
24+
*
25+
* This
26+
* to search either an interface or interface association descriptor:
27+
*
28+
* @code{.c}
29+
* BIT(USB_DESC_INTERFACE) | BIT(USB_DESC_INTERFACE_ASSOC)
30+
* @endcode
31+
*
32+
* @param[in] desc_beg Pointer to the beginning of the descriptor array; to search. May be NULL.
33+
* @param[in] desc_end Pointer after the end of the descriptor array to search
34+
* @param[in] type_mask Bitmask of bDescriptorType values to match
35+
* @return A pointer to the first descriptor matching
36+
*/
37+
const struct usb_desc_header *usbh_desc_get_next(const struct usb_desc_header *const desc,
38+
const void *const desc_end);
39+
40+
/**
41+
* @brief Search the first descriptor matching the selected type(s).
42+
*
43+
* As an example, the @p type_mask argument can be constructed this way
44+
* to search either an interface or interface association descriptor:
45+
*
46+
* @code{.c}
47+
* BIT(USB_DESC_INTERFACE) | BIT(USB_DESC_INTERFACE_ASSOC)
48+
* @endcode
49+
*
50+
* @param[in] desc_beg Pointer to the beginning of the descriptor array; to search. May be NULL.
51+
* @param[in] desc_end Pointer after the end of the descriptor array to search
52+
* @param[in] type_mask Bitmask of bDescriptorType values to match
53+
* @return A pointer to the first descriptor matching
54+
*/
55+
const struct usb_desc_header *usbh_desc_get_by_type(const void *const desc_beg,
56+
const void *const desc_end,
57+
uint32_t type_mask);
58+
59+
/**
60+
* @brief Search the first descriptor with the interace number wanted.
61+
*
62+
* The descriptors are going to be scanned until either an interface association
63+
* @c bFirstInterface field or an interface @c bInterfaceNumber field match.
64+
*
65+
* The descriptors following it can be browsed using @ref usbh_desc_get_next
66+
*
67+
* @param[in] desc_beg Pointer to the beginning of the descriptor array; to search. May be NULL.
68+
* @param[in] desc_end Pointer after the end of the descriptor array to search
69+
* @param[in] ifnum The interface number to search
70+
* @return A pointer to the first descriptor matching
71+
*/
72+
const struct usb_desc_header *usbh_desc_get_by_ifnum(const void *const desc_beg,
73+
const void *const desc_end,
74+
const uint8_t ifnum);
75+
76+
#endif /* ZEPHYR_INCLUDE_USBH_DESC_H */

0 commit comments

Comments
 (0)