Skip to content

Commit 7f7ae73

Browse files
author
Josuah Demangeon
committed
tests: usb: host: test basic API functionality
Add tests making sure the USB Host class APIs introduced build and run as expected. Signed-off-by: Josuah Demangeon <[email protected]>
1 parent aa2bcac commit 7f7ae73

File tree

9 files changed

+332
-0
lines changed

9 files changed

+332
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
6+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
7+
project(test_usb_host)
8+
9+
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/usb/host)
10+
11+
target_sources(app PRIVATE src/main.c)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000000
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (c) 2023 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/delete-node/ &zephyr_udc0;
8+
9+
/ {
10+
zephyr_uhc0: uhc_vrt0 {
11+
compatible = "zephyr,uhc-virtual";
12+
13+
zephyr_udc0: udc_vrt0 {
14+
compatible = "zephyr,udc-virtual";
15+
num-bidir-endpoints = <8>;
16+
maximum-speed = "high-speed";
17+
};
18+
};
19+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000000
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "native_sim.overlay"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) 2023 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
zephyr_uhc0: uhc_vrt0 {
9+
compatible = "zephyr,uhc-virtual";
10+
11+
zephyr_udc0: udc_vrt0 {
12+
compatible = "zephyr,udc-virtual";
13+
num-bidir-endpoints = <8>;
14+
maximum-speed = "high-speed";
15+
};
16+
};
17+
};

tests/subsys/usb/host/prj.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
CONFIG_LOG=y
5+
CONFIG_ZTEST=y
6+
7+
CONFIG_USB_HOST_STACK=y
8+
CONFIG_UHC_DRIVER=y

tests/subsys/usb/host/src/main.c

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/ztest.h>
8+
#include <zephyr/usb/usbh.h>
9+
#include <zephyr/usb/usbh.h>
10+
11+
#include "usbh_ch9.h"
12+
#include "usbh_host.h"
13+
#include "usbh_class_api.h"
14+
15+
#include <zephyr/logging/log.h>
16+
LOG_MODULE_REGISTER(usb_test, LOG_LEVEL_DBG);
17+
18+
USBH_CONTROLLER_DEFINE(uhs_ctx, DEVICE_DT_GET(DT_NODELABEL(zephyr_uhc0)));
19+
20+
/* Utility for USB descriptors */
21+
#define _LE16(n) ((n) & 0xff), ((n) >> 8)
22+
23+
/* Private class data, here just an integer but usually a custom struct. */
24+
static struct test_class_priv {
25+
enum {
26+
/* Test value stored before the class is initialized */
27+
TEST_CLASS_PRIV_NOT_INIT,
28+
/* Test value stored after the class is initialized */
29+
TEST_CLASS_PRIV_INIT_OK,
30+
} state;
31+
} test_class_priv = {
32+
.state = TEST_CLASS_PRIV_NOT_INIT,
33+
};
34+
35+
static int test_class_init(struct usbh_class_data *const c_data,
36+
struct usbh_context *const uhs_ctx)
37+
{
38+
struct test_class_priv *priv = c_data->priv;
39+
40+
LOG_DBG("initializing %p, priv value 0x%x", c_data, *priv);
41+
42+
zassert_equal(priv->state, TEST_CLASS_PRIV_NOT_INIT,
43+
"Class should be initialized only once");
44+
45+
priv->state = TEST_CLASS_PRIV_INIT_OK;
46+
47+
return 0;
48+
}
49+
50+
static int test_class_completion_cb(struct usbh_class_data *const c_data,
51+
struct usb_device *const udev,
52+
struct uhc_transfer *const xfer)
53+
{
54+
struct test_class_priv *priv = c_data->priv;
55+
56+
LOG_DBG("completion callback for %p, transfer %p", c_data, xfer);
57+
58+
zassert_equal(priv->state, TEST_CLASS_PRIV_INIT_OK);
59+
60+
return 0;
61+
}
62+
63+
static int test_class_probe(struct usbh_class_data *const c_data,
64+
struct usb_device *const udev,
65+
void *const desc_beg,
66+
void *const desc_end)
67+
{
68+
struct test_class_priv *priv = c_data->priv;
69+
70+
zassert_equal(priv->state, TEST_CLASS_PRIV_INIT_OK);
71+
72+
return 0;
73+
}
74+
75+
static int test_class_removed(struct usbh_class_data *const c_data,
76+
struct usb_device *const udev)
77+
{
78+
struct test_class_priv *priv = c_data->priv;
79+
80+
zassert_equal(priv->state, TEST_CLASS_PRIV_INIT_OK);
81+
82+
return 0;
83+
}
84+
85+
static int test_class_rwup(struct usbh_class_data *const c_data,
86+
struct usb_device *const udev)
87+
{
88+
struct test_class_priv *priv = c_data->priv;
89+
90+
zassert_equal(priv->state, TEST_CLASS_PRIV_INIT_OK);
91+
92+
return 0;
93+
}
94+
95+
static int test_class_suspended(struct usbh_class_data *const c_data,
96+
struct usb_device *const udev)
97+
{
98+
struct test_class_priv *priv = c_data->priv;
99+
100+
zassert_equal(priv->state, TEST_CLASS_PRIV_INIT_OK);
101+
102+
return 0;
103+
}
104+
105+
static int test_class_resumed(struct usbh_class_data *const c_data,
106+
struct usb_device *const udev)
107+
{
108+
struct test_class_priv *priv = c_data->priv;
109+
110+
zassert_equal(priv->state, TEST_CLASS_PRIV_INIT_OK);
111+
112+
return 0;
113+
}
114+
115+
static struct usbh_class_api test_class_api = {
116+
.init = &test_class_init,
117+
.completion_cb = &test_class_completion_cb,
118+
.probe = &test_class_probe,
119+
.removed = &test_class_removed,
120+
.rwup = &test_class_rwup,
121+
.suspended = &test_class_suspended,
122+
.resumed = &test_class_resumed,
123+
};
124+
125+
/* Define a class used in the tests */
126+
USBH_DEFINE_CLASS(test_class, &test_class_api, &test_class_priv);
127+
128+
/* Obtained with lsusb then verified against the USB 2.0 standard's sample HUB descriptor */
129+
const uint8_t test_hub_descriptor[] = {
130+
/* Device Descriptor: */
131+
18, /* bLength */
132+
1, /* bDescriptorType */
133+
_LE16(0x0200), /* bcdUSB */
134+
0x09, /* bDeviceClass */
135+
0x00, /* bDeviceSubClass */
136+
0x02, /* bDeviceProtocol */
137+
64, /* bMaxPacketSize0 */
138+
_LE16(0x0bda), /* idVendor */
139+
_LE16(0x5411), /* idProduct */
140+
_LE16(0x0001), /* bcdDevice */
141+
0, /* iManufacturer */
142+
0, /* iProduct */
143+
0, /* iSerial */
144+
1, /* bNumConfigurations */
145+
146+
/* Device Qualifier Descriptor: */
147+
10, /* bLength */
148+
6, /* bDescriptorType */
149+
_LE16(0x0200), /* bcdUSB */
150+
0x09, /* bDeviceClass */
151+
0x00, /* bDeviceSubClass */
152+
1, /* bDeviceProtocol */
153+
64, /* bMaxPacketSize0 */
154+
1, /* bNumConfigurations */
155+
156+
/* Configuration Descriptor: */
157+
9, /* bLength */
158+
2, /* bDescriptorType */
159+
_LE16(0x0029), /* wTotalLength */
160+
1, /* bNumInterfaces */
161+
1, /* bConfigurationValue */
162+
0, /* iConfiguration */
163+
0xe0, /* bmAttributes */
164+
0, /* MaxPower */
165+
166+
/* Interface Descriptor: */
167+
9, /* bLength */
168+
4, /* bDescriptorType */
169+
0, /* bInterfaceNumber */
170+
0, /* bAlternateSetting */
171+
1, /* bNumEndpoints */
172+
9, /* bInterfaceClass */
173+
0, /* bInterfaceSubClass */
174+
1, /* bInterfaceProtocol */
175+
0, /* iInterface */
176+
177+
/* Endpoint Descriptor: */
178+
7, /* bLength */
179+
5, /* bDescriptorType */
180+
0x81, /* bEndpointAddress */
181+
0x03, /* bmAttributes */
182+
_LE16(1), /* wMaxPacketSize */
183+
12, /* bInterval */
184+
185+
/* Interface Descriptor: */
186+
9, /* bLength */
187+
4, /* bDescriptorType */
188+
0, /* bInterfaceNumber */
189+
1, /* bAlternateSetting */
190+
1, /* bNumEndpoints */
191+
9, /* bInterfaceClass */
192+
0, /* bInterfaceSubClass */
193+
2, /* bInterfaceProtocol */
194+
0, /* iInterface */
195+
196+
/* Endpoint Descriptor: */
197+
7, /* bLength */
198+
5, /* bDescriptorType */
199+
0x81, /* bEndpointAddress */
200+
0x03, /* bmAttributes */
201+
_LE16(1), /* wMaxPacketSize */
202+
12, /* bInterval */
203+
};
204+
205+
ZTEST(host, test_class_fake_device)
206+
{
207+
zassert_equal(test_class_priv.state, TEST_CLASS_PRIV_INIT_OK,
208+
"The class should have been initialized by usbh_init()");
209+
}
210+
211+
static void *usb_test_enable(void)
212+
{
213+
int ret;
214+
215+
ret = usbh_init(&uhs_ctx);
216+
zassert_ok(ret, "Failed to initialize USB host (%d)", ret);
217+
218+
ret = usbh_enable(&uhs_ctx);
219+
zassert_ok(ret, "Failed to enable USB host (%d)", ret);
220+
221+
ret = uhc_bus_reset(uhs_ctx.dev);
222+
zassert_ok(ret, "Failed to signal bus reset (%d)", ret);
223+
224+
ret = uhc_bus_resume(uhs_ctx.dev);
225+
zassert_ok(ret, "Failed to signal bus resume (%d)", ret);
226+
227+
ret = uhc_sof_enable(uhs_ctx.dev);
228+
zassert_ok(ret, "Failed to enable SoF generator (%d)", ret);
229+
230+
LOG_INF("Host controller enabled");
231+
232+
/* Allow the host time to reset the host. */
233+
k_msleep(200);
234+
235+
return NULL;
236+
}
237+
238+
static void usb_test_shutdown(void *f)
239+
{
240+
int ret;
241+
242+
ret = usbh_disable(&uhs_ctx);
243+
zassert_ok(ret, "Failed to enable host support (%d)", ret);
244+
245+
ret = usbh_shutdown(&uhs_ctx);
246+
zassert_ok(ret, "Failed to shutdown host support (%d)", ret);
247+
248+
LOG_INF("Host controller disabled");
249+
}
250+
251+
ZTEST_SUITE(host, NULL, usb_test_enable, NULL, NULL, usb_test_shutdown);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests:
2+
usb.host:
3+
platform_allow:
4+
- native_sim
5+
- native_sim/native/64
6+
- qemu_cortex_m3
7+
integration_platforms:
8+
- native_sim
9+
tags: usb
10+
usb.host.build_all:
11+
platform_allow:
12+
- native_sim
13+
- native_sim/native/64
14+
integration_platforms:
15+
- native_sim
16+
tags: usb
17+
build_only: true

0 commit comments

Comments
 (0)