Skip to content

Commit 89bbf63

Browse files
committed
WIP win-vhid iter7: provider-based trigger using device FeatureReportByteLength
1 parent 00324ea commit 89bbf63

5 files changed

Lines changed: 81 additions & 30 deletions

File tree

src/tests/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ set_target_properties(test_read_interrupt
4242
C_STANDARD_REQUIRED TRUE
4343
)
4444
target_link_libraries(test_read_interrupt PRIVATE ${HIDAPI_TEST_BACKEND} Threads::Threads)
45+
if(WIN32)
46+
# HidD_GetPreparsedData / HidP_GetCaps used by the Windows provider.
47+
target_link_libraries(test_read_interrupt PRIVATE hid)
48+
endif()
4549

4650
add_test(NAME ReadInterrupt COMMAND test_read_interrupt)
4751
set_tests_properties(ReadInterrupt

src/tests/test_read_interrupt.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,7 @@ static int test_normal_read(test_virtual_device *vdev)
7777
unsigned char buf[64];
7878
int n;
7979

80-
int tr = test_virtual_device_trigger(h, TEST_VDEV_CMD_EMIT_A);
81-
if (tr < 0)
82-
printf(" trigger A returned %d, hid_error: %ls\n", tr, hid_error(h));
83-
CHECK(tr >= 0);
80+
CHECK(test_virtual_device_trigger(vdev, h, TEST_VDEV_CMD_EMIT_A) >= 0);
8481
n = hid_read_timeout(h, buf, sizeof(buf), 2000);
8582
CHECK(n == (int)sizeof(expected));
8683
CHECK(memcmp(buf, expected, sizeof(expected)) == 0);
@@ -221,7 +218,7 @@ static int test_clear_resumes_reads(test_virtual_device *vdev)
221218
CHECK(n == 0);
222219

223220
const unsigned char expected[TEST_VDEV_REPORT_SIZE] = TEST_VDEV_INPUT_B;
224-
CHECK(test_virtual_device_trigger(h, TEST_VDEV_CMD_EMIT_B) >= 0);
221+
CHECK(test_virtual_device_trigger(vdev, h, TEST_VDEV_CMD_EMIT_B) >= 0);
225222
n = hid_read_timeout(h, buf, sizeof(buf), 2000);
226223
CHECK(n == (int)sizeof(expected));
227224
CHECK(memcmp(buf, expected, sizeof(expected)) == 0);

src/tests/test_virtual_device.h

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,15 @@ void test_virtual_device_destroy(test_virtual_device *dev);
9393

9494
/*
9595
* Trigger a pre-recorded scenario on the device by sending the given command
96-
* as the first byte of a Feature report. This is implemented purely on top of
97-
* the public HIDAPI API, so it is identical for every backend.
96+
* as the first byte of a Feature report, using the ordinary public HIDAPI
97+
* hid_send_feature_report(). The exact wire length of a feature report is
98+
* platform-specific (Windows requires the buffer to be exactly the device's
99+
* FeatureReportByteLength), so this is implemented per-provider.
98100
*
99-
* Returns the hid_send_feature_report() result (>= 0 on success, -1 on error).
101+
* Returns >= 0 on success, -1 on error.
100102
*/
101-
static inline int test_virtual_device_trigger(hid_device *handle, unsigned char command)
102-
{
103-
unsigned char feature[1 + TEST_VDEV_REPORT_SIZE];
104-
memset(feature, 0, sizeof(feature));
105-
feature[0] = 0x00; /* Report ID (the device has no numbered reports) */
106-
feature[1] = command; /* scenario command, first byte of the payload */
107-
return hid_send_feature_report(handle, feature, sizeof(feature));
108-
}
103+
int test_virtual_device_trigger(test_virtual_device *dev, hid_device *handle,
104+
unsigned char command);
109105

110106
#ifdef __cplusplus
111107
}

src/tests/test_virtual_device_uhid.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,17 @@ hid_device *test_virtual_device_open_hidapi(test_virtual_device *dev, int timeou
317317
}
318318
}
319319

320+
int test_virtual_device_trigger(test_virtual_device *dev, hid_device *handle,
321+
unsigned char command)
322+
{
323+
unsigned char feature[1 + TEST_VDEV_REPORT_SIZE];
324+
(void)dev;
325+
memset(feature, 0, sizeof(feature));
326+
feature[0] = 0x00; /* Report ID (the device has no numbered reports) */
327+
feature[1] = command; /* scenario command, first byte of the payload */
328+
return hid_send_feature_report(handle, feature, sizeof(feature));
329+
}
330+
320331
void test_virtual_device_destroy(test_virtual_device *dev)
321332
{
322333
struct uhid_event ev;

src/tests/test_virtual_device_win.c

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,31 @@
1111

1212
/*
1313
* On Windows there is no userspace facility to create a HID device on the fly
14-
* (unlike Linux /dev/uhid). Instead, a small UMDF virtual HID driver
14+
* (unlike Linux /dev/uhid). A small UMDF virtual HID driver
1515
* (src/tests/windows/driver, a modified vhidmini2) is built, signed and
16-
* installed out-of-band - by the CI job - before the test runs, and removed
16+
* installed out-of-band by the CI job before the test runs, and removed
1717
* afterwards. That driver implements the same pre-recorded scenario protocol
1818
* as the Linux uhid provider (see test_virtual_device.h).
1919
*
20-
* Therefore this provider does not itself create the device: create() simply
21-
* records the ids, and presence is confirmed by open_hidapi() (and the test's
22-
* own probe), which polls HIDAPI enumeration. If the device isn't present
23-
* (driver not installed, e.g. a normal dev machine) the test skips.
20+
* create() just records the ids; presence is confirmed by open_hidapi(), which
21+
* also caches the device's feature-report length so that trigger() can send a
22+
* feature report of exactly the size Windows requires.
2423
*/
2524

2625
#include "test_virtual_device.h"
2726

27+
#include <stdio.h>
2828
#include <stdlib.h>
2929
#include <string.h>
30-
#include <wchar.h>
3130
#include <windows.h>
31+
#include <hidsdi.h>
32+
#include <hidpi.h>
3233

3334
struct test_virtual_device {
3435
unsigned short vendor_id;
3536
unsigned short product_id;
3637
char serial[64];
38+
ULONG feature_len; /* FeatureReportByteLength of the opened device */
3739
};
3840

3941
int test_virtual_device_create(test_virtual_device **out_dev,
@@ -62,6 +64,34 @@ int test_virtual_device_create(test_virtual_device **out_dev,
6264
return TEST_VDEV_OK;
6365
}
6466

67+
/* Query the device's HID caps (report byte lengths) directly from Windows. */
68+
static ULONG query_feature_len(const char *path)
69+
{
70+
HANDLE h;
71+
PHIDP_PREPARSED_DATA pp = NULL;
72+
ULONG feat = 0;
73+
74+
h = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
75+
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
76+
OPEN_EXISTING, 0, NULL);
77+
if (h == INVALID_HANDLE_VALUE)
78+
return 0;
79+
80+
if (HidD_GetPreparsedData(h, &pp)) {
81+
HIDP_CAPS caps;
82+
if (HidP_GetCaps(pp, &caps) == HIDP_STATUS_SUCCESS) {
83+
printf(" device caps: input=%u output=%u feature=%u\n",
84+
(unsigned)caps.InputReportByteLength,
85+
(unsigned)caps.OutputReportByteLength,
86+
(unsigned)caps.FeatureReportByteLength);
87+
feat = caps.FeatureReportByteLength;
88+
}
89+
HidD_FreePreparsedData(pp);
90+
}
91+
CloseHandle(h);
92+
return feat;
93+
}
94+
6595
hid_device *test_virtual_device_open_hidapi(test_virtual_device *dev, int timeout_ms)
6696
{
6797
int waited = 0;
@@ -71,16 +101,13 @@ hid_device *test_virtual_device_open_hidapi(test_virtual_device *dev, int timeou
71101

72102
for (;;) {
73103
struct hid_device_info *infos = hid_enumerate(dev->vendor_id, dev->product_id);
74-
struct hid_device_info *cur;
75-
struct hid_device_info *first = NULL;
76104
hid_device *h = NULL;
77105

78-
for (cur = infos; cur; cur = cur->next) {
79-
if (!first)
80-
first = cur;
106+
if (infos) {
107+
if (dev->feature_len == 0)
108+
dev->feature_len = query_feature_len(infos->path);
109+
h = hid_open_path(infos->path);
81110
}
82-
if (first)
83-
h = hid_open_path(first->path);
84111
hid_free_enumeration(infos);
85112
if (h)
86113
return h;
@@ -92,6 +119,22 @@ hid_device *test_virtual_device_open_hidapi(test_virtual_device *dev, int timeou
92119
}
93120
}
94121

122+
int test_virtual_device_trigger(test_virtual_device *dev, hid_device *handle,
123+
unsigned char command)
124+
{
125+
unsigned char feature[256];
126+
size_t len = (1 + TEST_VDEV_REPORT_SIZE);
127+
128+
/* Windows requires the feature buffer to be exactly FeatureReportByteLength. */
129+
if (dev && dev->feature_len > 0 && dev->feature_len <= sizeof(feature))
130+
len = dev->feature_len;
131+
132+
memset(feature, 0, sizeof(feature));
133+
feature[0] = 0x00; /* Report ID (the device has no numbered reports) */
134+
feature[1] = command; /* scenario command, first byte of the payload */
135+
return hid_send_feature_report(handle, feature, len);
136+
}
137+
95138
void test_virtual_device_destroy(test_virtual_device *dev)
96139
{
97140
/* The harness uninstalls the driver/device after the test. */

0 commit comments

Comments
 (0)