Skip to content

Commit 6acdb74

Browse files
committed
subsys: usb: host: new usb host hub class implementation
Introduce USB hub class support in the USB host stack. This includes: - Core hub handling logic (usbh_hub.c / usbh_hub.h) - Hub manager for port status and event handling (usbh_hub_mgr.c / usbh_hub_mgr.h) Signed-off-by: Aiden Hu <[email protected]>
1 parent c66cd2b commit 6acdb74

File tree

4 files changed

+1742
-0
lines changed

4 files changed

+1742
-0
lines changed

subsys/usb/host/class/usbh_hub.c

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/logging/log.h>
9+
#include <zephyr/usb/usbh.h>
10+
#include <zephyr/sys/byteorder.h>
11+
#include "usbh_device.h"
12+
#include "usbh_ch9.h"
13+
#include "usbh_hub.h"
14+
15+
LOG_MODULE_REGISTER(usbh_hub, CONFIG_USBH_LOG_LEVEL);
16+
17+
/**
18+
* @brief Common hub control request function
19+
*/
20+
static int usbh_hub_class_request_common(struct usbh_hub_instance *hub_instance,
21+
uint8_t bmRequestType, uint8_t bRequest,
22+
uint16_t wValue, uint16_t wIndex,
23+
struct net_buf *buf)
24+
{
25+
int ret;
26+
27+
if (!hub_instance || !hub_instance->hub_udev || !buf) {
28+
return -EINVAL;
29+
}
30+
31+
k_mutex_lock(&hub_instance->ctrl_lock, K_FOREVER);
32+
33+
/* Execute synchronous control transfer */
34+
ret = usbh_req_setup(hub_instance->hub_udev,
35+
bmRequestType,
36+
bRequest,
37+
wValue,
38+
wIndex,
39+
buf->size,
40+
buf);
41+
42+
if (ret < 0) {
43+
LOG_ERR("Hub control request failed: %d", ret);
44+
} else {
45+
LOG_DBG("Hub control request completed: type=0x%02x, req=0x%02x, len=%d",
46+
bmRequestType, bRequest, buf->len);
47+
}
48+
49+
k_mutex_unlock(&hub_instance->ctrl_lock);
50+
return ret;
51+
}
52+
53+
int usbh_hub_get_descriptor(struct usbh_hub_instance *hub_instance,
54+
uint8_t *buffer, uint16_t wLength)
55+
{
56+
struct net_buf *buf;
57+
int ret;
58+
59+
if (!hub_instance || !buffer || wLength == 0) {
60+
return -EINVAL;
61+
}
62+
63+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, wLength);
64+
if (NULL == buf) {
65+
LOG_ERR("Failed to allocate buffer for hub descriptor");
66+
return -ENOMEM;
67+
}
68+
69+
ret = usbh_hub_class_request_common(hub_instance,
70+
(USB_REQTYPE_DIR_TO_HOST << 7) |
71+
(USB_REQTYPE_TYPE_CLASS << 5) |
72+
(USB_REQTYPE_RECIPIENT_DEVICE << 0),
73+
USB_HUB_REQ_GET_DESCRIPTOR,
74+
(USB_HUB_DESCRIPTOR_TYPE << 8),
75+
0,
76+
buf);
77+
78+
if (ret == 0 && buf->len > 0) {
79+
memcpy(buffer, buf->data, MIN(wLength, buf->len));
80+
}
81+
82+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
83+
return ret;
84+
}
85+
86+
int usbh_hub_set_port_feature(struct usbh_hub_instance *hub_instance,
87+
uint8_t port_number, uint8_t feature)
88+
{
89+
struct net_buf *buf;
90+
int ret;
91+
92+
if (!hub_instance) {
93+
return -EINVAL;
94+
}
95+
96+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, 0);
97+
if (NULL == buf) {
98+
LOG_ERR("Failed to allocate buffer for set port feature");
99+
return -ENOMEM;
100+
}
101+
102+
ret = usbh_hub_class_request_common(hub_instance,
103+
(USB_REQTYPE_DIR_TO_DEVICE << 7) |
104+
(USB_REQTYPE_TYPE_CLASS << 5) |
105+
(USB_REQTYPE_RECIPIENT_OTHER << 0),
106+
USB_HUB_REQ_SET_FEATURE,
107+
feature,
108+
port_number,
109+
buf);
110+
111+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
112+
return ret;
113+
}
114+
115+
int usbh_hub_clear_port_feature(struct usbh_hub_instance *hub_instance,
116+
uint8_t port_number, uint8_t feature)
117+
{
118+
struct net_buf *buf;
119+
int ret;
120+
121+
if (!hub_instance) {
122+
return -EINVAL;
123+
}
124+
125+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, 0);
126+
if (NULL == buf) {
127+
LOG_ERR("Failed to allocate buffer for clear port feature");
128+
return -ENOMEM;
129+
}
130+
131+
ret = usbh_hub_class_request_common(hub_instance,
132+
(USB_REQTYPE_DIR_TO_DEVICE << 7) |
133+
(USB_REQTYPE_TYPE_CLASS << 5) |
134+
(USB_REQTYPE_RECIPIENT_OTHER << 0),
135+
USB_HUB_REQ_CLEAR_FEATURE,
136+
feature,
137+
port_number,
138+
buf);
139+
140+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
141+
return ret;
142+
}
143+
144+
int usbh_hub_get_port_status(struct usbh_hub_instance *hub_instance,
145+
uint8_t port_number,
146+
uint16_t *const wPortStatus,
147+
uint16_t *const wPortChange)
148+
{
149+
struct net_buf *buf;
150+
int ret;
151+
152+
if (!hub_instance || !wPortStatus || !wPortChange) {
153+
return -EINVAL;
154+
}
155+
156+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, 4);
157+
if (NULL == buf) {
158+
LOG_ERR("Failed to allocate buffer for port status");
159+
return -ENOMEM;
160+
}
161+
162+
ret = usbh_hub_class_request_common(hub_instance,
163+
(USB_REQTYPE_DIR_TO_HOST << 7) |
164+
(USB_REQTYPE_TYPE_CLASS << 5) |
165+
(USB_REQTYPE_RECIPIENT_OTHER << 0),
166+
USB_HUB_REQ_GET_STATUS,
167+
0,
168+
port_number,
169+
buf);
170+
171+
if (ret == 0 && buf->len >= 4) {
172+
*wPortStatus = net_buf_pull_le16(buf);
173+
*wPortChange = net_buf_pull_le16(buf);
174+
175+
LOG_DBG("Port %d status: wPortStatus=0x%04x, wPortChange=0x%04x",
176+
port_number, *wPortStatus, *wPortChange);
177+
} else {
178+
LOG_ERR("Failed to get port status or insufficient data (ret=%d, len=%d)",
179+
ret, buf ? buf->len : 0);
180+
*wPortStatus = 0;
181+
*wPortChange = 0;
182+
}
183+
184+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
185+
return ret;
186+
}
187+
188+
int usbh_hub_get_hub_status(struct usbh_hub_instance *hub_instance,
189+
uint16_t *const wHubStatus,
190+
uint16_t *const wHubChange)
191+
{
192+
struct net_buf *buf;
193+
int ret;
194+
195+
if (!hub_instance || !wHubStatus || !wHubChange) {
196+
return -EINVAL;
197+
}
198+
199+
/* Hub status response is always 4 bytes (2 bytes status + 2 bytes change) */
200+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, 4);
201+
if (NULL == buf) {
202+
LOG_ERR("Failed to allocate buffer for hub status");
203+
return -ENOMEM;
204+
}
205+
206+
ret = usbh_hub_class_request_common(hub_instance,
207+
(USB_REQTYPE_DIR_TO_HOST << 7) |
208+
(USB_REQTYPE_TYPE_CLASS << 5) |
209+
(USB_REQTYPE_RECIPIENT_DEVICE << 0),
210+
USB_HUB_REQ_GET_STATUS,
211+
0,
212+
0,
213+
buf);
214+
215+
if (ret == 0 && buf->len >= 4) {
216+
*wHubStatus = net_buf_remove_le16(buf);
217+
*wHubChange = net_buf_remove_le16(buf);
218+
219+
LOG_DBG("Hub status: wHubStatus=0x%04x, wHubChange=0x%04x",
220+
*wHubStatus, *wHubChange);
221+
} else {
222+
LOG_ERR("Failed to get hub status or insufficient data (ret=%d, len=%d)",
223+
ret, buf ? buf->len : 0);
224+
*wHubStatus = 0;
225+
*wHubChange = 0;
226+
}
227+
228+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
229+
return ret;
230+
}
231+
232+
int usbh_hub_clear_hub_feature(struct usbh_hub_instance *hub_instance, uint8_t feature)
233+
{
234+
struct net_buf *buf;
235+
int ret;
236+
237+
if (!hub_instance) {
238+
return -EINVAL;
239+
}
240+
241+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, 0);
242+
if (NULL == buf) {
243+
LOG_ERR("Failed to allocate buffer for clear hub feature");
244+
return -ENOMEM;
245+
}
246+
247+
ret = usbh_hub_class_request_common(hub_instance,
248+
(USB_REQTYPE_DIR_TO_DEVICE << 7) |
249+
(USB_REQTYPE_TYPE_CLASS << 5) |
250+
(USB_REQTYPE_RECIPIENT_DEVICE << 0),
251+
USB_HUB_REQ_CLEAR_FEATURE,
252+
feature,
253+
0,
254+
buf);
255+
256+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
257+
return ret;
258+
}
259+
260+
int usbh_hub_init_instance(struct usbh_hub_instance *hub_instance,
261+
struct usb_device *udev)
262+
{
263+
if (!hub_instance || !udev) {
264+
return -EINVAL;
265+
}
266+
267+
memset(hub_instance, 0, sizeof(*hub_instance));
268+
hub_instance->hub_udev = udev;
269+
270+
k_sem_init(&hub_instance->ctrl_sem, 0, 1);
271+
k_mutex_init(&hub_instance->ctrl_lock);
272+
273+
return 0;
274+
}
275+
276+
void usbh_hub_cleanup_instance(struct usbh_hub_instance *hub_instance)
277+
{
278+
if (hub_instance) {
279+
/* Clean up any pending operations */
280+
memset(hub_instance, 0, sizeof(*hub_instance));
281+
}
282+
}

0 commit comments

Comments
 (0)