Skip to content

Commit 9ea6f7c

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 cc56c94 commit 9ea6f7c

File tree

4 files changed

+1756
-0
lines changed

4 files changed

+1756
-0
lines changed

subsys/usb/host/class/usbh_hub.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
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 request_type, uint8_t request,
22+
uint16_t wvalue, uint16_t windex,
23+
uint8_t *buffer, uint16_t buffer_length,
24+
usbh_hub_callback_t callback_fn,
25+
void *callback_param)
26+
{
27+
struct net_buf *buf;
28+
int ret;
29+
30+
if (!hub_instance || !hub_instance->hub_udev) {
31+
return -EINVAL;
32+
}
33+
34+
k_mutex_lock(&hub_instance->ctrl_lock, K_FOREVER);
35+
36+
/* Allocate buffer for transfer */
37+
if (buffer_length > 0) {
38+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, buffer_length);
39+
if (!buf) {
40+
LOG_ERR("Failed to allocate buffer for hub control request");
41+
k_mutex_unlock(&hub_instance->ctrl_lock);
42+
return -ENOMEM;
43+
}
44+
45+
/* For OUT transfers, copy data to buffer */
46+
if (!(request_type & 0x80) && buffer) {
47+
memcpy(buf->data, buffer, buffer_length);
48+
net_buf_add(buf, buffer_length);
49+
}
50+
} else {
51+
buf = usbh_xfer_buf_alloc(hub_instance->hub_udev, 0);
52+
if (!buf) {
53+
LOG_ERR("Failed to allocate zero-length buffer");
54+
k_mutex_unlock(&hub_instance->ctrl_lock);
55+
return -ENOMEM;
56+
}
57+
}
58+
59+
/* Execute synchronous control transfer - 参考CDC ECM的方式 */
60+
ret = usbh_req_setup(hub_instance->hub_udev,
61+
request_type,
62+
request,
63+
wvalue,
64+
windex,
65+
buffer_length,
66+
buf);
67+
68+
if (ret < 0) {
69+
LOG_ERR("Hub control request failed: %d", ret);
70+
goto cleanup;
71+
}
72+
73+
/* For IN transfers, copy data back to user buffer */
74+
if ((request_type & 0x80) &&
75+
buffer_length > 0 && buffer && buf->len > 0) {
76+
memcpy(buffer, buf->data, MIN(buffer_length, buf->len));
77+
}
78+
79+
/* Call callback if provided */
80+
if (callback_fn) {
81+
callback_fn(callback_param, buffer,
82+
(ret == 0) ? buf->len : 0, ret);
83+
}
84+
85+
LOG_DBG("Hub control request completed: type=0x%02x, req=0x%02x, status=%d",
86+
request_type, request, ret);
87+
88+
cleanup:
89+
usbh_xfer_buf_free(hub_instance->hub_udev, buf);
90+
k_mutex_unlock(&hub_instance->ctrl_lock);
91+
return ret;
92+
}
93+
94+
int usbh_hub_init_instance(struct usbh_hub_instance *hub_instance,
95+
struct usb_device *udev)
96+
{
97+
if (!hub_instance || !udev) {
98+
return -EINVAL;
99+
}
100+
101+
memset(hub_instance, 0, sizeof(*hub_instance));
102+
hub_instance->hub_udev = udev;
103+
104+
k_sem_init(&hub_instance->ctrl_sem, 0, 1);
105+
k_mutex_init(&hub_instance->ctrl_lock);
106+
107+
return 0;
108+
}
109+
110+
int usbh_hub_get_descriptor(struct usbh_hub_instance *hub_instance,
111+
uint8_t *buffer, uint16_t buffer_length,
112+
usbh_hub_callback_t callback_fn, void *callback_param)
113+
{
114+
return usbh_hub_class_request_common(hub_instance,
115+
(USB_REQTYPE_DIR_TO_HOST << 7) |
116+
(USB_REQTYPE_TYPE_CLASS << 5) |
117+
(USB_REQTYPE_RECIPIENT_DEVICE << 0),
118+
USB_HUB_REQ_GET_DESCRIPTOR,
119+
(USB_HUB_DESCRIPTOR_TYPE << 8),
120+
0,
121+
buffer, buffer_length, callback_fn, callback_param);
122+
}
123+
124+
int usbh_hub_set_port_feature(struct usbh_hub_instance *hub_instance,
125+
uint8_t port_number, uint8_t feature,
126+
usbh_hub_callback_t callback_fn, void *callback_param)
127+
{
128+
return usbh_hub_class_request_common(hub_instance,
129+
(USB_REQTYPE_DIR_TO_DEVICE << 7) |
130+
(USB_REQTYPE_TYPE_CLASS << 5) |
131+
(USB_REQTYPE_RECIPIENT_OTHER << 0),
132+
USB_HUB_REQ_SET_FEATURE,
133+
feature,
134+
port_number,
135+
NULL, 0, callback_fn, callback_param);
136+
}
137+
138+
int usbh_hub_clear_port_feature(struct usbh_hub_instance *hub_instance,
139+
uint8_t port_number, uint8_t feature,
140+
usbh_hub_callback_t callback_fn, void *callback_param)
141+
{
142+
return usbh_hub_class_request_common(hub_instance,
143+
(USB_REQTYPE_DIR_TO_DEVICE << 7) |
144+
(USB_REQTYPE_TYPE_CLASS << 5) |
145+
(USB_REQTYPE_RECIPIENT_OTHER << 0),
146+
USB_HUB_REQ_CLEAR_FEATURE,
147+
feature,
148+
port_number,
149+
NULL, 0, callback_fn, callback_param);
150+
}
151+
152+
int usbh_hub_get_port_status(struct usbh_hub_instance *hub_instance,
153+
uint8_t port_number, uint8_t *buffer, uint16_t buffer_length,
154+
usbh_hub_callback_t callback_fn, void *callback_param)
155+
{
156+
return usbh_hub_class_request_common(hub_instance,
157+
(USB_REQTYPE_DIR_TO_HOST << 7) |
158+
(USB_REQTYPE_TYPE_CLASS << 5) |
159+
(USB_REQTYPE_RECIPIENT_OTHER << 0),
160+
USB_HUB_REQ_GET_STATUS,
161+
0,
162+
port_number,
163+
buffer, buffer_length, callback_fn, callback_param);
164+
}
165+
166+
int usbh_hub_get_hub_status(struct usbh_hub_instance *hub_instance,
167+
uint8_t *buffer, uint16_t buffer_length,
168+
usbh_hub_callback_t callback_fn, void *callback_param)
169+
{
170+
return usbh_hub_class_request_common(hub_instance,
171+
(USB_REQTYPE_DIR_TO_HOST << 7) |
172+
(USB_REQTYPE_TYPE_CLASS << 5) |
173+
(USB_REQTYPE_RECIPIENT_DEVICE << 0),
174+
USB_HUB_REQ_GET_STATUS,
175+
0,
176+
0,
177+
buffer, buffer_length, callback_fn, callback_param);
178+
}
179+
180+
void usbh_hub_cleanup_instance(struct usbh_hub_instance *hub_instance)
181+
{
182+
if (hub_instance) {
183+
/* Clean up any pending operations */
184+
memset(hub_instance, 0, sizeof(*hub_instance));
185+
}
186+
}

subsys/usb/host/class/usbh_hub.h

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef _USBH_HUB_H_
8+
#define _USBH_HUB_H_
9+
10+
#include <zephyr/usb/usb_ch9.h>
11+
12+
/* USB HUB Class-specific requests */
13+
#define USB_HUB_REQ_GET_STATUS 0x00
14+
#define USB_HUB_REQ_CLEAR_FEATURE 0x01
15+
#define USB_HUB_REQ_SET_FEATURE 0x03
16+
#define USB_HUB_REQ_GET_DESCRIPTOR 0x06
17+
18+
/* USB HUB Descriptor Type */
19+
#define USB_HUB_DESCRIPTOR_TYPE 0x29
20+
21+
/* USB HUB Port Features */
22+
#define USB_HUB_FEATURE_PORT_CONNECTION 0x00
23+
#define USB_HUB_FEATURE_PORT_ENABLE 0x01
24+
#define USB_HUB_FEATURE_PORT_SUSPEND 0x02
25+
#define USB_HUB_FEATURE_PORT_OVER_CURRENT 0x03
26+
#define USB_HUB_FEATURE_PORT_RESET 0x04
27+
#define USB_HUB_FEATURE_PORT_POWER 0x08
28+
#define USB_HUB_FEATURE_PORT_LOW_SPEED 0x09
29+
#define USB_HUB_FEATURE_PORT_HIGH_SPEED 0x0A
30+
31+
/* USB HUB Port Change Features */
32+
#define USB_HUB_FEATURE_C_PORT_CONNECTION 0x10
33+
#define USB_HUB_FEATURE_C_PORT_ENABLE 0x11
34+
#define USB_HUB_FEATURE_C_PORT_SUSPEND 0x12
35+
#define USB_HUB_FEATURE_C_PORT_OVER_CURRENT 0x13
36+
#define USB_HUB_FEATURE_C_PORT_RESET 0x14
37+
38+
/* USB HUB Class codes */
39+
#define USB_HUB_CLASS_CODE 0x09
40+
#define USB_HUB_SUBCLASS_CODE 0x00
41+
#define USB_HUB_PROTOCOL_CODE 0x00
42+
43+
/* Maximum ports per hub */
44+
#define USB_HUB_MAX_PORTS 7
45+
46+
/* USB HUB descriptor structure */
47+
struct usb_hub_descriptor {
48+
uint8_t bDescLength;
49+
uint8_t bDescriptorType;
50+
uint8_t bNbrPorts;
51+
uint16_t wHubCharacteristics;
52+
uint8_t bPwrOn2PwrGood;
53+
uint8_t bHubContrCurrent;
54+
uint8_t DeviceRemovable[];
55+
} __packed;
56+
57+
/* USB HUB status structure */
58+
struct usb_hub_status {
59+
uint16_t wHubStatus;
60+
uint16_t wHubChange;
61+
} __packed;
62+
63+
/* USB HUB port status structure */
64+
struct usb_hub_port_status {
65+
uint16_t wPortStatus;
66+
uint16_t wPortChange;
67+
} __packed;
68+
69+
/* Hub state enumeration */
70+
enum usbh_hub_state {
71+
HUB_STATE_INIT,
72+
HUB_STATE_GET_DESCRIPTOR,
73+
HUB_STATE_POWER_PORTS,
74+
HUB_STATE_OPERATIONAL,
75+
HUB_STATE_ERROR,
76+
};
77+
78+
/* Port state enumeration */
79+
enum usbh_port_state {
80+
PORT_STATE_DISCONNECTED,
81+
PORT_STATE_CONNECTED,
82+
PORT_STATE_RESETTING,
83+
PORT_STATE_ENABLED,
84+
PORT_STATE_SUSPENDED,
85+
PORT_STATE_ERROR,
86+
};
87+
88+
/**
89+
* @brief Hub statistics information
90+
*/
91+
struct usbh_hub_stats {
92+
uint16_t total_hubs;
93+
uint16_t operational_hubs;
94+
uint16_t total_ports;
95+
uint16_t active_ports;
96+
uint8_t max_level;
97+
uint8_t hubs_by_level[8];
98+
};
99+
100+
/* Hub instance structure */
101+
struct usbh_hub_instance {
102+
struct usb_device *hub_udev;
103+
struct usbh_context *uhs_ctx;
104+
105+
/* Hub properties */
106+
uint8_t num_ports;
107+
uint8_t hub_level;
108+
uint16_t think_time;
109+
110+
/* Control transfer handling */
111+
struct k_sem ctrl_sem;
112+
struct k_mutex ctrl_lock;
113+
int ctrl_status;
114+
115+
/* Hub descriptor buffer */
116+
uint8_t hub_desc_buf[64];
117+
118+
/* Status buffers */
119+
struct usb_hub_status hub_status;
120+
struct usb_hub_port_status port_status;
121+
};
122+
123+
/* Hub transfer callback function type */
124+
typedef void (*usbh_hub_callback_t)(void *param, uint8_t *data,
125+
uint32_t data_len, int status);
126+
127+
/* Function declarations - matched with implementation */
128+
int usbh_hub_init_instance(struct usbh_hub_instance *hub_instance,
129+
struct usb_device *udev);
130+
131+
int usbh_hub_get_descriptor(struct usbh_hub_instance *hub_instance,
132+
uint8_t *buffer, uint16_t buffer_length,
133+
usbh_hub_callback_t callback_fn, void *callback_param);
134+
135+
int usbh_hub_set_port_feature(struct usbh_hub_instance *hub_instance,
136+
uint8_t port_number, uint8_t feature,
137+
usbh_hub_callback_t callback_fn, void *callback_param);
138+
139+
int usbh_hub_clear_port_feature(struct usbh_hub_instance *hub_instance,
140+
uint8_t port_number, uint8_t feature,
141+
usbh_hub_callback_t callback_fn, void *callback_param);
142+
143+
int usbh_hub_get_port_status(struct usbh_hub_instance *hub_instance,
144+
uint8_t port_number, uint8_t *buffer, uint16_t buffer_length,
145+
usbh_hub_callback_t callback_fn, void *callback_param);
146+
147+
int usbh_hub_get_hub_status(struct usbh_hub_instance *hub_instance,
148+
uint8_t *buffer, uint16_t buffer_length,
149+
usbh_hub_callback_t callback_fn, void *callback_param);
150+
151+
void usbh_hub_cleanup_instance(struct usbh_hub_instance *hub_instance);
152+
153+
/* Public API function declarations */
154+
void usbh_hub_mgr_print_topology(void);
155+
void usbh_hub_mgr_get_stats(struct usbh_hub_stats *stats);
156+
157+
/* Additional function declaration */
158+
int usbh_hub_submit_interrupt_in(struct usbh_hub_instance *hub_instance,
159+
struct usb_ep_descriptor *int_ep,
160+
int (*callback)(struct usb_device *const dev,
161+
struct uhc_transfer *const xfer),
162+
void *callback_param);
163+
164+
#endif /* _USBH_HUB_H_ */

0 commit comments

Comments
 (0)