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
3334struct 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
3941int 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+
6595hid_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+
95138void test_virtual_device_destroy (test_virtual_device * dev )
96139{
97140 /* The harness uninstalls the driver/device after the test. */
0 commit comments