Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
2a52c8dc
Commit
2a52c8dc
authored
Mar 22, 2022
by
Rémi Bernon
Committed by
Alexandre Julliard
Mar 22, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dinput/tests: Create a HID device from the Bus device.
Signed-off-by:
Rémi Bernon
<
rbernon@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
709e31ff
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1450 additions
and
16 deletions
+1450
-16
Makefile.in
dlls/dinput/tests/Makefile.in
+8
-0
dinput_test.h
dlls/dinput/tests/dinput_test.h
+1
-0
driver_bus.c
dlls/dinput/tests/driver_bus.c
+671
-12
driver_hid.c
dlls/dinput/tests/driver_hid.c
+282
-0
driver_hid.h
dlls/dinput/tests/driver_hid.h
+17
-2
driver_hid.spec
dlls/dinput/tests/driver_hid.spec
+1
-0
driver_hid_poll.c
dlls/dinput/tests/driver_hid_poll.c
+283
-0
driver_hid_poll.spec
dlls/dinput/tests/driver_hid_poll.spec
+1
-0
hid.c
dlls/dinput/tests/hid.c
+186
-2
No files found.
dlls/dinput/tests/Makefile.in
View file @
2a52c8dc
...
...
@@ -5,6 +5,10 @@ driver_IMPORTS = winecrt0 ntoskrnl hal hidclass
driver_EXTRADLLFLAGS
=
-nodefaultlibs
-nostartfiles
-Wl
,--subsystem,native
driver_bus_IMPORTS
=
winecrt0 ntoskrnl hal
driver_bus_EXTRADLLFLAGS
=
-nodefaultlibs
-nostartfiles
-Wl
,--subsystem,native
driver_hid_IMPORTS
=
winecrt0 ntoskrnl hal hidclass
driver_hid_EXTRADLLFLAGS
=
-nodefaultlibs
-nostartfiles
-Wl
,--subsystem,native
driver_hid_poll_IMPORTS
=
winecrt0 ntoskrnl hal hidclass
driver_hid_poll_EXTRADLLFLAGS
=
-nodefaultlibs
-nostartfiles
-Wl
,--subsystem,native
SOURCES
=
\
device.c
\
...
...
@@ -14,6 +18,10 @@ SOURCES = \
driver.spec
\
driver_bus.c
\
driver_bus.spec
\
driver_hid.c
\
driver_hid.spec
\
driver_hid_poll.c
\
driver_hid_poll.spec
\
force_feedback.c
\
hid.c
\
hotplug.c
\
...
...
dlls/dinput/tests/dinput_test.h
View file @
2a52c8dc
...
...
@@ -49,6 +49,7 @@ extern const GUID expect_guid_product;
extern
const
WCHAR
expect_path
[];
extern
const
WCHAR
expect_path_end
[];
extern
HANDLE
device_added
,
device_removed
;
extern
HINSTANCE
instance
;
extern
BOOL
localized
;
/* object names get translated */
...
...
dlls/dinput/tests/driver_bus.c
View file @
2a52c8dc
...
...
@@ -28,6 +28,8 @@
#include "winternl.h"
#include "winioctl.h"
#include "ddk/wdm.h"
#include "ddk/hidsdi.h"
#include "ddk/hidport.h"
#include "wine/list.h"
...
...
@@ -37,6 +39,369 @@
typedef
ULONG
PNP_DEVICE_STATE
;
#define PNP_DEVICE_REMOVED 8
#define check_buffer( a, b ) check_buffer_( __LINE__, a, b )
static
void
check_buffer_
(
int
line
,
HID_XFER_PACKET
*
packet
,
struct
hid_expect
*
expect
)
{
ULONG
match_len
,
i
;
match_len
=
RtlCompareMemory
(
packet
->
reportBuffer
,
expect
->
report_buf
,
expect
->
report_len
);
ok
(
match_len
==
expect
->
report_len
,
"unexpected data:
\n
"
);
if
(
match_len
==
expect
->
report_len
)
return
;
for
(
i
=
0
;
i
<
packet
->
reportBufferLen
;)
{
char
buffer
[
256
],
*
buf
=
buffer
;
buf
+=
sprintf
(
buf
,
"%08lx "
,
i
);
do
buf
+=
sprintf
(
buf
,
" %02x"
,
packet
->
reportBuffer
[
i
]
);
while
(
++
i
%
16
&&
i
<
packet
->
reportBufferLen
);
ok
(
0
,
" %s
\n
"
,
buffer
);
}
}
#define EXPECT_QUEUE_BUFFER_SIZE (64 * sizeof(struct hid_expect))
struct
expect_queue
{
KSPIN_LOCK
lock
;
struct
hid_expect
*
pos
;
struct
hid_expect
*
end
;
struct
hid_expect
spurious
;
struct
hid_expect
*
buffer
;
IRP
*
pending_wait
;
char
context
[
64
];
};
static
void
expect_queue_init
(
struct
expect_queue
*
queue
)
{
KeInitializeSpinLock
(
&
queue
->
lock
);
queue
->
buffer
=
ExAllocatePool
(
PagedPool
,
EXPECT_QUEUE_BUFFER_SIZE
);
RtlSecureZeroMemory
(
queue
->
buffer
,
EXPECT_QUEUE_BUFFER_SIZE
);
queue
->
pos
=
queue
->
buffer
;
queue
->
end
=
queue
->
buffer
;
}
static
void
expect_queue_cleanup
(
struct
expect_queue
*
queue
)
{
KIRQL
irql
;
IRP
*
irp
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
if
((
irp
=
queue
->
pending_wait
))
{
queue
->
pending_wait
=
NULL
;
if
(
!
IoSetCancelRoutine
(
irp
,
NULL
))
irp
=
NULL
;
}
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
if
(
irp
)
{
irp
->
IoStatus
.
Information
=
0
;
irp
->
IoStatus
.
Status
=
STATUS_DELETE_PENDING
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
ExFreePool
(
queue
->
buffer
);
}
static
void
expect_queue_reset
(
struct
expect_queue
*
queue
,
void
*
buffer
,
unsigned
int
size
)
{
struct
hid_expect
*
missing
,
*
missing_end
,
*
tmp
;
char
context
[
64
];
KIRQL
irql
;
missing
=
ExAllocatePool
(
PagedPool
,
EXPECT_QUEUE_BUFFER_SIZE
);
RtlSecureZeroMemory
(
missing
,
EXPECT_QUEUE_BUFFER_SIZE
);
missing_end
=
missing
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
tmp
=
queue
->
pos
;
while
(
tmp
<
queue
->
end
)
*
missing_end
++
=
*
tmp
++
;
queue
->
pos
=
queue
->
buffer
;
queue
->
end
=
queue
->
buffer
;
if
(
size
)
memcpy
(
queue
->
end
,
buffer
,
size
);
queue
->
end
=
queue
->
end
+
size
/
sizeof
(
struct
hid_expect
);
memcpy
(
context
,
queue
->
context
,
sizeof
(
context
)
);
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
tmp
=
missing
;
while
(
tmp
!=
missing_end
)
{
winetest_push_context
(
"%s expect[%Id]"
,
context
,
tmp
-
missing
);
if
(
tmp
->
broken
)
{
todo_wine_if
(
tmp
->
todo
)
win_skip
(
"broken (code %#lx id %u len %u)
\n
"
,
tmp
->
code
,
tmp
->
report_id
,
tmp
->
report_len
);
}
else
{
todo_wine_if
(
tmp
->
todo
)
ok
(
tmp
->
wine_only
,
"missing (code %#lx id %u len %u)
\n
"
,
tmp
->
code
,
tmp
->
report_id
,
tmp
->
report_len
);
}
winetest_pop_context
();
tmp
++
;
}
ExFreePool
(
missing
);
}
static
void
WINAPI
wait_cancel_routine
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
struct
expect_queue
*
queue
=
irp
->
Tail
.
Overlay
.
DriverContext
[
0
];
KIRQL
irql
;
IoReleaseCancelSpinLock
(
irp
->
CancelIrql
);
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
queue
->
pending_wait
=
NULL
;
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
irp
->
IoStatus
.
Information
=
0
;
irp
->
IoStatus
.
Status
=
STATUS_CANCELLED
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
static
NTSTATUS
expect_queue_wait
(
struct
expect_queue
*
queue
,
IRP
*
irp
)
{
NTSTATUS
status
;
KIRQL
irql
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
if
(
queue
->
pos
==
queue
->
end
)
status
=
STATUS_SUCCESS
;
else
{
IoSetCancelRoutine
(
irp
,
wait_cancel_routine
);
if
(
irp
->
Cancel
&&
!
IoSetCancelRoutine
(
irp
,
NULL
))
status
=
STATUS_CANCELLED
;
else
{
irp
->
Tail
.
Overlay
.
DriverContext
[
0
]
=
queue
;
IoMarkIrpPending
(
irp
);
queue
->
pending_wait
=
irp
;
status
=
STATUS_PENDING
;
}
}
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
return
status
;
}
static
void
expect_queue_next
(
struct
expect_queue
*
queue
,
ULONG
code
,
HID_XFER_PACKET
*
packet
,
LONG
*
index
,
struct
hid_expect
*
expect
,
BOOL
compare_buf
,
char
*
context
,
ULONG
context_size
)
{
struct
hid_expect
*
missing
,
*
missing_end
,
*
tmp
;
ULONG
len
=
packet
->
reportBufferLen
;
BYTE
*
buf
=
packet
->
reportBuffer
;
BYTE
id
=
packet
->
reportId
;
IRP
*
irp
=
NULL
;
KIRQL
irql
;
missing
=
ExAllocatePool
(
PagedPool
,
EXPECT_QUEUE_BUFFER_SIZE
);
RtlSecureZeroMemory
(
missing
,
EXPECT_QUEUE_BUFFER_SIZE
);
missing_end
=
missing
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
tmp
=
queue
->
pos
;
while
(
tmp
<
queue
->
end
)
{
if
(
running_under_wine
&&
!
tmp
->
todo
)
break
;
if
(
!
running_under_wine
&&
!
tmp
->
broken
&&
!
tmp
->
wine_only
)
break
;
if
(
tmp
->
code
==
code
&&
tmp
->
report_id
==
id
&&
tmp
->
report_len
==
len
&&
(
!
compare_buf
||
RtlCompareMemory
(
tmp
->
report_buf
,
buf
,
len
)
==
len
))
break
;
*
missing_end
++
=
*
tmp
++
;
}
*
index
=
tmp
-
queue
->
buffer
;
if
(
tmp
<
queue
->
end
)
queue
->
pos
=
tmp
+
1
;
else
tmp
=
&
queue
->
spurious
;
*
expect
=
*
tmp
;
while
(
queue
->
pos
<
queue
->
end
)
{
if
(
running_under_wine
||
!
queue
->
pos
->
wine_only
)
break
;
queue
->
pos
++
;
}
if
(
queue
->
pos
==
queue
->
end
&&
(
irp
=
queue
->
pending_wait
))
{
queue
->
pending_wait
=
NULL
;
if
(
!
IoSetCancelRoutine
(
irp
,
NULL
))
irp
=
NULL
;
}
memcpy
(
context
,
queue
->
context
,
context_size
);
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
if
(
irp
)
{
irp
->
IoStatus
.
Information
=
0
;
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
ok
(
tmp
!=
&
queue
->
spurious
,
"%s got spurious packet
\n
"
,
context
);
winetest_push_context
(
"%s expect[%Id]"
,
context
,
tmp
-
queue
->
buffer
);
todo_wine_if
(
tmp
->
todo
)
ok
(
!
tmp
->
wine_only
,
"found code %#lx id %u len %u
\n
"
,
tmp
->
code
,
tmp
->
report_id
,
tmp
->
report_len
);
winetest_pop_context
();
tmp
=
missing
;
while
(
tmp
!=
missing_end
)
{
winetest_push_context
(
"%s expect[%Id]"
,
context
,
tmp
-
missing
);
if
(
tmp
->
broken
)
{
todo_wine_if
(
tmp
->
todo
)
win_skip
(
"broken (code %#lx id %u len %u)
\n
"
,
tmp
->
code
,
tmp
->
report_id
,
tmp
->
report_len
);
}
else
{
todo_wine_if
(
tmp
->
todo
)
ok
(
tmp
->
wine_only
,
"missing (code %#lx id %u len %u)
\n
"
,
tmp
->
code
,
tmp
->
report_id
,
tmp
->
report_len
);
}
winetest_pop_context
();
tmp
++
;
}
ExFreePool
(
missing
);
}
struct
irp_queue
{
KSPIN_LOCK
lock
;
LIST_ENTRY
list
;
};
static
IRP
*
irp_queue_pop
(
struct
irp_queue
*
queue
)
{
KIRQL
irql
;
IRP
*
irp
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
if
(
IsListEmpty
(
&
queue
->
list
))
irp
=
NULL
;
else
irp
=
CONTAINING_RECORD
(
RemoveHeadList
(
&
queue
->
list
),
IRP
,
Tail
.
Overlay
.
ListEntry
);
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
return
irp
;
}
static
void
irp_queue_push
(
struct
irp_queue
*
queue
,
IRP
*
irp
)
{
KIRQL
irql
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
InsertTailList
(
&
queue
->
list
,
&
irp
->
Tail
.
Overlay
.
ListEntry
);
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
}
static
void
irp_queue_clear
(
struct
irp_queue
*
queue
)
{
IRP
*
irp
;
while
((
irp
=
irp_queue_pop
(
queue
)))
{
irp
->
IoStatus
.
Status
=
STATUS_DELETE_PENDING
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
}
static
void
irp_queue_init
(
struct
irp_queue
*
queue
)
{
KeInitializeSpinLock
(
&
queue
->
lock
);
InitializeListHead
(
&
queue
->
list
);
}
struct
input_queue
{
KSPIN_LOCK
lock
;
BOOL
is_polled
;
struct
hid_expect
*
pos
;
struct
hid_expect
*
end
;
struct
hid_expect
*
buffer
;
struct
irp_queue
pending
;
};
static
void
input_queue_init
(
struct
input_queue
*
queue
,
BOOL
is_polled
)
{
KeInitializeSpinLock
(
&
queue
->
lock
);
queue
->
is_polled
=
is_polled
;
queue
->
buffer
=
ExAllocatePool
(
PagedPool
,
EXPECT_QUEUE_BUFFER_SIZE
);
RtlSecureZeroMemory
(
queue
->
buffer
,
EXPECT_QUEUE_BUFFER_SIZE
);
queue
->
pos
=
queue
->
buffer
;
queue
->
end
=
queue
->
buffer
;
irp_queue_init
(
&
queue
->
pending
);
}
static
void
input_queue_cleanup
(
struct
input_queue
*
queue
)
{
ExFreePool
(
queue
->
buffer
);
}
static
BOOL
input_queue_read_locked
(
struct
input_queue
*
queue
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
ULONG
out_size
=
stack
->
Parameters
.
DeviceIoControl
.
OutputBufferLength
;
struct
hid_expect
*
tmp
=
queue
->
pos
;
if
(
tmp
>=
queue
->
end
)
return
FALSE
;
if
(
tmp
->
ret_length
)
out_size
=
tmp
->
ret_length
;
memcpy
(
irp
->
UserBuffer
,
tmp
->
report_buf
,
out_size
);
irp
->
IoStatus
.
Information
=
out_size
;
irp
->
IoStatus
.
Status
=
tmp
->
ret_status
;
if
(
tmp
<
queue
->
end
)
queue
->
pos
=
tmp
+
1
;
/* loop on the queue data in polled mode */
if
(
queue
->
is_polled
&&
queue
->
pos
==
queue
->
end
)
queue
->
pos
=
queue
->
buffer
;
return
TRUE
;
}
static
NTSTATUS
input_queue_read
(
struct
input_queue
*
queue
,
IRP
*
irp
)
{
NTSTATUS
status
;
KIRQL
irql
;
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
if
(
input_queue_read_locked
(
queue
,
irp
))
status
=
STATUS_SUCCESS
;
else
{
IoMarkIrpPending
(
irp
);
irp_queue_push
(
&
queue
->
pending
,
irp
);
status
=
STATUS_PENDING
;
}
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
return
status
;
}
static
void
input_queue_reset
(
struct
input_queue
*
queue
,
void
*
in_buf
,
ULONG
in_size
)
{
struct
irp_queue
completed
;
ULONG
remaining
;
KIRQL
irql
;
IRP
*
irp
;
irp_queue_init
(
&
completed
);
KeAcquireSpinLock
(
&
queue
->
lock
,
&
irql
);
remaining
=
queue
->
end
-
queue
->
pos
;
queue
->
pos
=
queue
->
buffer
;
queue
->
end
=
queue
->
buffer
;
memcpy
(
queue
->
end
,
in_buf
,
in_size
);
queue
->
end
+=
in_size
/
sizeof
(
struct
hid_expect
);
while
(
!
queue
->
is_polled
&&
queue
->
pos
<
queue
->
end
&&
(
irp
=
irp_queue_pop
(
&
queue
->
pending
)))
{
input_queue_read_locked
(
queue
,
irp
);
irp_queue_push
(
&
completed
,
irp
);
}
KeReleaseSpinLock
(
&
queue
->
lock
,
irql
);
if
(
!
queue
->
is_polled
)
ok
(
!
remaining
,
"unread input
\n
"
);
while
((
irp
=
irp_queue_pop
(
&
completed
)))
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
struct
device
{
KSPIN_LOCK
lock
;
...
...
@@ -56,6 +421,15 @@ struct phys_device
WCHAR
instance_id
[
MAX_PATH
];
WCHAR
device_id
[
MAX_PATH
];
BOOL
use_report_id
;
DWORD
report_descriptor_len
;
char
report_descriptor_buf
[
1024
];
HIDP_CAPS
caps
;
HID_DEVICE_ATTRIBUTES
attributes
;
struct
expect_queue
expect_queue
;
struct
input_queue
input_queue
;
};
static
inline
struct
phys_device
*
pdo_from_DEVICE_OBJECT
(
DEVICE_OBJECT
*
device
)
...
...
@@ -133,7 +507,9 @@ static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct bus_de
KIRQL
irql
;
ULONG
i
;
swprintf
(
device_id
,
MAX_PATH
,
L"WINETEST
\\
VID_%04X&PID_%04X"
,
desc
->
vid
,
desc
->
pid
);
swprintf
(
device_id
,
MAX_PATH
,
L"WINETEST
\\
VID_%04X&PID_%04X"
,
desc
->
attributes
.
VendorID
,
desc
->
attributes
.
ProductID
);
if
(
desc
->
is_polled
)
wcscat
(
device_id
,
L"&POLL"
);
KeAcquireSpinLock
(
&
impl
->
base
.
lock
,
&
irql
);
devices
=
impl
->
devices
->
Objects
;
...
...
@@ -206,11 +582,18 @@ static WCHAR *query_hardware_ids( DEVICE_OBJECT *device )
static
WCHAR
*
query_compatible_ids
(
DEVICE_OBJECT
*
device
)
{
DWORD
size
=
0
;
static
const
WCHAR
hid_compat_id
[]
=
L"WINETEST
\\
WINE_COMP_HID"
;
static
const
WCHAR
hid_poll_compat_id
[]
=
L"WINETEST
\\
WINE_COMP_POLLHID"
;
struct
phys_device
*
impl
=
pdo_from_DEVICE_OBJECT
(
device
);
const
WCHAR
*
compat_id
=
impl
->
input_queue
.
is_polled
?
hid_poll_compat_id
:
hid_compat_id
;
DWORD
size
=
(
wcslen
(
compat_id
)
+
1
)
*
sizeof
(
WCHAR
);
WCHAR
*
dst
;
if
((
dst
=
ExAllocatePool
(
PagedPool
,
size
+
sizeof
(
WCHAR
)
)))
{
memcpy
(
dst
,
compat_id
,
size
);
dst
[
size
/
sizeof
(
WCHAR
)]
=
0
;
}
return
dst
;
}
...
...
@@ -283,6 +666,7 @@ static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp )
state
=
(
code
==
IRP_MN_START_DEVICE
||
code
==
IRP_MN_CANCEL_REMOVE_DEVICE
)
?
0
:
PNP_DEVICE_REMOVED
;
KeAcquireSpinLock
(
&
impl
->
base
.
lock
,
&
irql
);
impl
->
base
.
state
=
state
;
irp_queue_clear
(
&
impl
->
input_queue
.
pending
);
KeReleaseSpinLock
(
&
impl
->
base
.
lock
,
irql
);
if
(
code
!=
IRP_MN_REMOVE_DEVICE
)
status
=
STATUS_SUCCESS
;
else
...
...
@@ -291,6 +675,8 @@ static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp )
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
if
(
remove_child_device
(
fdo
,
device
))
{
input_queue_cleanup
(
&
impl
->
input_queue
);
expect_queue_cleanup
(
&
impl
->
expect_queue
);
IoDeleteDevice
(
device
);
if
(
winetest_debug
>
1
)
trace
(
"Deleted Bus PDO %p
\n
"
,
device
);
}
...
...
@@ -410,6 +796,8 @@ static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct bus_device_desc
WCHAR
name
[
MAX_PATH
];
NTSTATUS
status
;
if
(
winetest_debug
>
1
)
trace
(
"polled %u, report_id %u
\n
"
,
desc
->
is_polled
,
desc
->
use_report_id
);
swprintf
(
name
,
MAX_PATH
,
L"
\\
Device
\\
WINETEST#%p&%p&%u"
,
device
->
DriverObject
,
device
,
index
++
);
RtlInitUnicodeString
(
&
name_str
,
name
);
...
...
@@ -421,11 +809,25 @@ static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct bus_device_desc
impl
=
pdo_from_DEVICE_OBJECT
(
child
);
KeInitializeSpinLock
(
&
impl
->
base
.
lock
);
swprintf
(
impl
->
device_id
,
MAX_PATH
,
L"WINETEST
\\
VID_%04X&PID_%04X"
,
desc
->
vid
,
desc
->
pid
);
swprintf
(
impl
->
device_id
,
MAX_PATH
,
L"WINETEST
\\
VID_%04X&PID_%04X"
,
desc
->
attributes
.
VendorID
,
desc
->
attributes
.
ProductID
);
/* use a different device ID so that driver cache select the polled driver */
if
(
desc
->
is_polled
)
wcscat
(
impl
->
device_id
,
L"&POLL"
);
swprintf
(
impl
->
instance_id
,
MAX_PATH
,
L"0&0000&0"
);
impl
->
base
.
is_phys
=
TRUE
;
impl
->
fdo
=
fdo
;
impl
->
use_report_id
=
desc
->
use_report_id
;
impl
->
caps
=
desc
->
caps
;
impl
->
attributes
=
desc
->
attributes
;
impl
->
report_descriptor_len
=
desc
->
report_descriptor_len
;
memcpy
(
impl
->
report_descriptor_buf
,
desc
->
report_descriptor_buf
,
desc
->
report_descriptor_len
);
input_queue_init
(
&
impl
->
input_queue
,
desc
->
is_polled
);
input_queue_reset
(
&
impl
->
input_queue
,
desc
->
input
,
desc
->
input_size
);
expect_queue_init
(
&
impl
->
expect_queue
);
expect_queue_reset
(
&
impl
->
expect_queue
,
desc
->
expect
,
desc
->
expect_size
);
memcpy
(
impl
->
expect_queue
.
context
,
desc
->
context
,
desc
->
context_size
);
if
(
winetest_debug
>
1
)
trace
(
"Created Bus PDO %p for Bus FDO %p
\n
"
,
child
,
device
);
append_child_device
(
fdo
,
child
);
...
...
@@ -541,14 +943,225 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
static
NTSTATUS
WINAPI
pdo_internal_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
struct
phys_device
*
impl
=
pdo_from_DEVICE_OBJECT
(
device
);
const
ULONG
in_size
=
stack
->
Parameters
.
DeviceIoControl
.
InputBufferLength
;
ULONG
out_size
=
stack
->
Parameters
.
DeviceIoControl
.
OutputBufferLength
;
const
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
struct
hid_expect
expect
=
{
0
};
char
context
[
64
];
NTSTATUS
status
;
BOOL
removed
;
KIRQL
irql
;
LONG
index
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_ioctl
(
code
)
);
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_NOT_SUPPORTED
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_NOT_SUPPORTED
;
KeAcquireSpinLock
(
&
impl
->
base
.
lock
,
&
irql
);
removed
=
impl
->
base
.
state
==
PNP_DEVICE_REMOVED
;
KeReleaseSpinLock
(
&
impl
->
base
.
lock
,
irql
);
if
(
removed
)
{
irp
->
IoStatus
.
Status
=
STATUS_DELETE_PENDING
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_DELETE_PENDING
;
}
winetest_push_context
(
"id %d%s"
,
impl
->
use_report_id
,
impl
->
input_queue
.
is_polled
?
" poll"
:
""
);
switch
(
code
)
{
case
IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
{
HID_DESCRIPTOR
*
desc
=
irp
->
UserBuffer
;
ok
(
!
in_size
,
"got input size %lu
\n
"
,
in_size
);
ok
(
out_size
==
sizeof
(
*
desc
),
"got output size %lu
\n
"
,
out_size
);
if
(
out_size
==
sizeof
(
*
desc
))
{
ok
(
!
desc
->
bLength
,
"got size %u
\n
"
,
desc
->
bLength
);
desc
->
bLength
=
sizeof
(
*
desc
);
desc
->
bDescriptorType
=
HID_HID_DESCRIPTOR_TYPE
;
desc
->
bcdHID
=
HID_REVISION
;
desc
->
bCountry
=
0
;
desc
->
bNumDescriptors
=
1
;
desc
->
DescriptorList
[
0
].
bReportType
=
HID_REPORT_DESCRIPTOR_TYPE
;
desc
->
DescriptorList
[
0
].
wReportLength
=
impl
->
report_descriptor_len
;
irp
->
IoStatus
.
Information
=
sizeof
(
*
desc
);
}
status
=
STATUS_SUCCESS
;
break
;
}
case
IOCTL_HID_GET_REPORT_DESCRIPTOR
:
ok
(
!
in_size
,
"got input size %lu
\n
"
,
in_size
);
ok
(
out_size
==
impl
->
report_descriptor_len
,
"got output size %lu
\n
"
,
out_size
);
if
(
out_size
==
impl
->
report_descriptor_len
)
{
memcpy
(
irp
->
UserBuffer
,
impl
->
report_descriptor_buf
,
impl
->
report_descriptor_len
);
irp
->
IoStatus
.
Information
=
impl
->
report_descriptor_len
;
}
status
=
STATUS_SUCCESS
;
break
;
case
IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
ok
(
!
in_size
,
"got input size %lu
\n
"
,
in_size
);
ok
(
out_size
==
sizeof
(
impl
->
attributes
),
"got output size %lu
\n
"
,
out_size
);
if
(
out_size
==
sizeof
(
impl
->
attributes
))
{
memcpy
(
irp
->
UserBuffer
,
&
impl
->
attributes
,
sizeof
(
impl
->
attributes
)
);
irp
->
IoStatus
.
Information
=
sizeof
(
impl
->
attributes
);
}
status
=
STATUS_SUCCESS
;
break
;
case
IOCTL_HID_READ_REPORT
:
{
ULONG
expected_size
=
impl
->
caps
.
InputReportByteLength
-
(
impl
->
use_report_id
?
0
:
1
);
ok
(
!
in_size
,
"got input size %lu
\n
"
,
in_size
);
ok
(
out_size
==
expected_size
,
"got output size %lu
\n
"
,
out_size
);
status
=
input_queue_read
(
&
impl
->
input_queue
,
irp
);
break
;
}
case
IOCTL_HID_WRITE_REPORT
:
{
HID_XFER_PACKET
*
packet
=
irp
->
UserBuffer
;
ULONG
expected_size
=
impl
->
caps
.
OutputReportByteLength
-
(
impl
->
use_report_id
?
0
:
1
);
ok
(
in_size
==
sizeof
(
*
packet
),
"got input size %lu
\n
"
,
in_size
);
ok
(
!
out_size
,
"got output size %lu
\n
"
,
out_size
);
ok
(
packet
->
reportBufferLen
>=
expected_size
,
"got report size %lu
\n
"
,
packet
->
reportBufferLen
);
expect_queue_next
(
&
impl
->
expect_queue
,
code
,
packet
,
&
index
,
&
expect
,
TRUE
,
context
,
sizeof
(
context
)
);
winetest_push_context
(
"%s expect[%ld]"
,
context
,
index
);
ok
(
code
==
expect
.
code
,
"got %#lx, expected %#lx
\n
"
,
code
,
expect
.
code
);
ok
(
packet
->
reportId
==
expect
.
report_id
,
"got id %u
\n
"
,
packet
->
reportId
);
ok
(
packet
->
reportBufferLen
==
expect
.
report_len
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
check_buffer
(
packet
,
&
expect
);
winetest_pop_context
();
irp
->
IoStatus
.
Information
=
expect
.
ret_length
?
expect
.
ret_length
:
expect
.
report_len
;
status
=
expect
.
ret_status
;
break
;
}
case
IOCTL_HID_GET_INPUT_REPORT
:
{
HID_XFER_PACKET
*
packet
=
irp
->
UserBuffer
;
ULONG
expected_size
=
impl
->
caps
.
InputReportByteLength
-
(
impl
->
use_report_id
?
0
:
1
);
ok
(
!
in_size
,
"got input size %lu
\n
"
,
in_size
);
ok
(
out_size
==
sizeof
(
*
packet
),
"got output size %lu
\n
"
,
out_size
);
ok
(
packet
->
reportBufferLen
>=
expected_size
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
ok
(
!!
packet
->
reportBuffer
,
"got buffer %p
\n
"
,
packet
->
reportBuffer
);
expect_queue_next
(
&
impl
->
expect_queue
,
code
,
packet
,
&
index
,
&
expect
,
FALSE
,
context
,
sizeof
(
context
)
);
winetest_push_context
(
"%s expect[%ld]"
,
context
,
index
);
ok
(
code
==
expect
.
code
,
"got %#lx, expected %#lx
\n
"
,
code
,
expect
.
code
);
ok
(
packet
->
reportId
==
expect
.
report_id
,
"got id %u
\n
"
,
packet
->
reportId
);
ok
(
packet
->
reportBufferLen
==
expect
.
report_len
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
winetest_pop_context
();
irp
->
IoStatus
.
Information
=
expect
.
ret_length
?
expect
.
ret_length
:
expect
.
report_len
;
memcpy
(
packet
->
reportBuffer
,
expect
.
report_buf
,
irp
->
IoStatus
.
Information
);
status
=
expect
.
ret_status
;
break
;
}
case
IOCTL_HID_SET_OUTPUT_REPORT
:
{
HID_XFER_PACKET
*
packet
=
irp
->
UserBuffer
;
ULONG
expected_size
=
impl
->
caps
.
OutputReportByteLength
-
(
impl
->
use_report_id
?
0
:
1
);
ok
(
in_size
==
sizeof
(
*
packet
),
"got input size %lu
\n
"
,
in_size
);
ok
(
!
out_size
,
"got output size %lu
\n
"
,
out_size
);
ok
(
packet
->
reportBufferLen
>=
expected_size
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
ok
(
!!
packet
->
reportBuffer
,
"got buffer %p
\n
"
,
packet
->
reportBuffer
);
expect_queue_next
(
&
impl
->
expect_queue
,
code
,
packet
,
&
index
,
&
expect
,
TRUE
,
context
,
sizeof
(
context
)
);
winetest_push_context
(
"%s expect[%ld]"
,
context
,
index
);
ok
(
code
==
expect
.
code
,
"got %#lx, expected %#lx
\n
"
,
code
,
expect
.
code
);
ok
(
packet
->
reportId
==
expect
.
report_id
,
"got id %u
\n
"
,
packet
->
reportId
);
ok
(
packet
->
reportBufferLen
==
expect
.
report_len
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
check_buffer
(
packet
,
&
expect
);
winetest_pop_context
();
irp
->
IoStatus
.
Information
=
expect
.
ret_length
?
expect
.
ret_length
:
expect
.
report_len
;
status
=
expect
.
ret_status
;
break
;
}
case
IOCTL_HID_GET_FEATURE
:
{
HID_XFER_PACKET
*
packet
=
irp
->
UserBuffer
;
ULONG
expected_size
=
impl
->
caps
.
FeatureReportByteLength
-
(
impl
->
use_report_id
?
0
:
1
);
ok
(
!
in_size
,
"got input size %lu
\n
"
,
in_size
);
ok
(
out_size
==
sizeof
(
*
packet
),
"got output size %lu
\n
"
,
out_size
);
ok
(
packet
->
reportBufferLen
>=
expected_size
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
ok
(
!!
packet
->
reportBuffer
,
"got buffer %p
\n
"
,
packet
->
reportBuffer
);
expect_queue_next
(
&
impl
->
expect_queue
,
code
,
packet
,
&
index
,
&
expect
,
FALSE
,
context
,
sizeof
(
context
)
);
winetest_push_context
(
"%s expect[%ld]"
,
context
,
index
);
ok
(
code
==
expect
.
code
,
"got %#lx, expected %#lx
\n
"
,
code
,
expect
.
code
);
ok
(
packet
->
reportId
==
expect
.
report_id
,
"got id %u
\n
"
,
packet
->
reportId
);
ok
(
packet
->
reportBufferLen
==
expect
.
report_len
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
winetest_pop_context
();
irp
->
IoStatus
.
Information
=
expect
.
ret_length
?
expect
.
ret_length
:
expect
.
report_len
;
memcpy
(
packet
->
reportBuffer
,
expect
.
report_buf
,
irp
->
IoStatus
.
Information
);
status
=
expect
.
ret_status
;
break
;
}
case
IOCTL_HID_SET_FEATURE
:
{
HID_XFER_PACKET
*
packet
=
irp
->
UserBuffer
;
ULONG
expected_size
=
impl
->
caps
.
FeatureReportByteLength
-
(
impl
->
use_report_id
?
0
:
1
);
ok
(
in_size
==
sizeof
(
*
packet
),
"got input size %lu
\n
"
,
in_size
);
ok
(
!
out_size
,
"got output size %lu
\n
"
,
out_size
);
ok
(
packet
->
reportBufferLen
>=
expected_size
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
ok
(
!!
packet
->
reportBuffer
,
"got buffer %p
\n
"
,
packet
->
reportBuffer
);
expect_queue_next
(
&
impl
->
expect_queue
,
code
,
packet
,
&
index
,
&
expect
,
TRUE
,
context
,
sizeof
(
context
)
);
winetest_push_context
(
"%s expect[%ld]"
,
context
,
index
);
ok
(
code
==
expect
.
code
,
"got %#lx, expected %#lx
\n
"
,
code
,
expect
.
code
);
ok
(
packet
->
reportId
==
expect
.
report_id
,
"got id %u
\n
"
,
packet
->
reportId
);
ok
(
packet
->
reportBufferLen
==
expect
.
report_len
,
"got len %lu
\n
"
,
packet
->
reportBufferLen
);
check_buffer
(
packet
,
&
expect
);
winetest_pop_context
();
irp
->
IoStatus
.
Information
=
expect
.
ret_length
?
expect
.
ret_length
:
expect
.
report_len
;
status
=
expect
.
ret_status
;
break
;
}
case
IOCTL_HID_GET_STRING
:
memcpy
(
irp
->
UserBuffer
,
L"Wine Test"
,
sizeof
(
L"Wine Test"
)
);
irp
->
IoStatus
.
Information
=
sizeof
(
L"Wine Test"
);
status
=
STATUS_SUCCESS
;
break
;
default:
ok
(
0
,
"unexpected call
\n
"
);
status
=
irp
->
IoStatus
.
Status
;
break
;
}
winetest_pop_context
();
if
(
status
!=
STATUS_PENDING
)
{
irp
->
IoStatus
.
Status
=
status
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
return
status
;
}
static
NTSTATUS
WINAPI
fdo_internal_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
...
...
@@ -574,14 +1187,56 @@ static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
static
NTSTATUS
WINAPI
pdo_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
struct
phys_device
*
impl
=
pdo_from_DEVICE_OBJECT
(
device
);
ULONG
in_size
=
stack
->
Parameters
.
DeviceIoControl
.
InputBufferLength
;
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
NTSTATUS
status
;
KIRQL
irql
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_ioctl
(
code
)
);
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_NOT_SUPPORTED
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_NOT_SUPPORTED
;
switch
(
code
)
{
case
IOCTL_WINETEST_HID_SET_EXPECT
:
expect_queue_reset
(
&
impl
->
expect_queue
,
irp
->
AssociatedIrp
.
SystemBuffer
,
in_size
);
status
=
STATUS_SUCCESS
;
break
;
case
IOCTL_WINETEST_HID_WAIT_EXPECT
:
status
=
expect_queue_wait
(
&
impl
->
expect_queue
,
irp
);
break
;
case
IOCTL_WINETEST_HID_SEND_INPUT
:
input_queue_reset
(
&
impl
->
input_queue
,
irp
->
AssociatedIrp
.
SystemBuffer
,
in_size
);
status
=
STATUS_SUCCESS
;
break
;
case
IOCTL_WINETEST_HID_SET_CONTEXT
:
KeAcquireSpinLock
(
&
impl
->
expect_queue
.
lock
,
&
irql
);
memcpy
(
impl
->
expect_queue
.
context
,
irp
->
AssociatedIrp
.
SystemBuffer
,
in_size
);
KeReleaseSpinLock
(
&
impl
->
expect_queue
.
lock
,
irql
);
status
=
STATUS_SUCCESS
;
break
;
case
IOCTL_WINETEST_REMOVE_DEVICE
:
KeAcquireSpinLock
(
&
impl
->
base
.
lock
,
&
irql
);
impl
->
base
.
state
=
PNP_DEVICE_REMOVED
;
irp_queue_clear
(
&
impl
->
input_queue
.
pending
);
KeReleaseSpinLock
(
&
impl
->
base
.
lock
,
irql
);
status
=
STATUS_SUCCESS
;
break
;
case
IOCTL_WINETEST_CREATE_DEVICE
:
ok
(
0
,
"unexpected call
\n
"
);
status
=
irp
->
IoStatus
.
Status
;
break
;
default:
ok
(
0
,
"unexpected call
\n
"
);
status
=
irp
->
IoStatus
.
Status
;
break
;
}
if
(
status
!=
STATUS_PENDING
)
{
irp
->
IoStatus
.
Status
=
status
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
return
status
;
}
static
NTSTATUS
WINAPI
fdo_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
...
...
@@ -603,7 +1258,11 @@ static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp )
case
IOCTL_WINETEST_REMOVE_DEVICE
:
if
((
device
=
find_child_device
(
impl
,
irp
->
AssociatedIrp
.
SystemBuffer
))
&&
!
remove_child_device
(
impl
,
device
))
{
status
=
pdo_ioctl
(
device
,
irp
);
IoInvalidateDeviceRelations
(
impl
->
pdo
,
BusRelations
);
return
status
;
}
status
=
STATUS_SUCCESS
;
break
;
default:
...
...
dlls/dinput/tests/driver_hid.c
0 → 100644
View file @
2a52c8dc
/*
* Copyright 2022 Rémi Bernon for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
#include "winioctl.h"
#include "ddk/wdm.h"
#include "hidusage.h"
#include "ddk/hidpi.h"
#include "ddk/hidport.h"
#include "wine/list.h"
#include "initguid.h"
#include "driver_hid.h"
static
DRIVER_OBJECT
*
expect_driver
;
struct
hid_device
{
DEVICE_OBJECT
*
expect_bus_pdo
;
DEVICE_OBJECT
*
expect_hid_fdo
;
struct
hid_device
*
expect_hid_ext
;
UNICODE_STRING
control_symlink
;
};
static
void
check_device
(
DEVICE_OBJECT
*
device
)
{
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
struct
hid_device
*
impl
=
ext
->
MiniDeviceExtension
;
ok
(
device
==
impl
->
expect_hid_fdo
,
"got device %p
\n
"
,
device
);
ok
(
device
->
DriverObject
==
expect_driver
,
"got DriverObject %p
\n
"
,
device
->
DriverObject
);
if
(
!
device
->
NextDevice
)
ok
(
device
==
impl
->
expect_hid_fdo
,
"got device %p
\n
"
,
device
);
else
ok
(
device
->
NextDevice
==
impl
->
expect_hid_fdo
,
"got NextDevice %p
\n
"
,
device
->
NextDevice
);
ok
(
!
device
->
AttachedDevice
,
"got AttachedDevice %p
\n
"
,
device
->
AttachedDevice
);
ok
(
ext
->
MiniDeviceExtension
==
impl
->
expect_hid_ext
,
"got MiniDeviceExtension %p
\n
"
,
ext
->
MiniDeviceExtension
);
ok
(
ext
->
PhysicalDeviceObject
==
impl
->
expect_bus_pdo
,
"got PhysicalDeviceObject %p
\n
"
,
ext
->
PhysicalDeviceObject
);
ok
(
ext
->
NextDeviceObject
==
impl
->
expect_bus_pdo
,
"got NextDeviceObject %p
\n
"
,
ext
->
NextDeviceObject
);
}
#ifdef __ASM_USE_FASTCALL_WRAPPER
extern
void
*
WINAPI
wrap_fastcall_func1
(
void
*
func
,
const
void
*
a
);
__ASM_STDCALL_FUNC
(
wrap_fastcall_func1
,
8
,
"popl %ecx
\n\t
"
"popl %eax
\n\t
"
"xchgl (%esp),%ecx
\n\t
"
"jmp *%eax"
);
#define call_fastcall_func1( func, a ) wrap_fastcall_func1( func, a )
#else
#define call_fastcall_func1( func, a ) func( a )
#endif
static
ULONG_PTR
get_device_relations
(
DEVICE_OBJECT
*
device
,
DEVICE_RELATIONS
*
previous
,
ULONG
count
,
DEVICE_OBJECT
**
devices
)
{
DEVICE_RELATIONS
*
relations
;
ULONG
new_count
=
count
;
if
(
previous
)
new_count
+=
previous
->
Count
;
if
(
!
(
relations
=
ExAllocatePool
(
PagedPool
,
offsetof
(
DEVICE_RELATIONS
,
Objects
[
new_count
]
)
)))
{
ok
(
0
,
"Failed to allocate memory
\n
"
);
return
(
ULONG_PTR
)
previous
;
}
if
(
!
previous
)
relations
->
Count
=
0
;
else
{
memcpy
(
relations
,
previous
,
offsetof
(
DEVICE_RELATIONS
,
Objects
[
previous
->
Count
]
)
);
ExFreePool
(
previous
);
}
while
(
count
--
)
{
call_fastcall_func1
(
ObfReferenceObject
,
*
devices
);
relations
->
Objects
[
relations
->
Count
++
]
=
*
devices
++
;
}
return
(
ULONG_PTR
)
relations
;
}
static
NTSTATUS
WINAPI
driver_pnp
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
struct
hid_device
*
impl
=
ext
->
MiniDeviceExtension
;
ULONG
code
=
stack
->
MinorFunction
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_pnp
(
code
)
);
switch
(
code
)
{
case
IRP_MN_START_DEVICE
:
IoSetDeviceInterfaceState
(
&
impl
->
control_symlink
,
TRUE
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
case
IRP_MN_REMOVE_DEVICE
:
IoSetDeviceInterfaceState
(
&
impl
->
control_symlink
,
FALSE
);
RtlFreeUnicodeString
(
&
impl
->
control_symlink
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
case
IRP_MN_STOP_DEVICE
:
case
IRP_MN_SURPRISE_REMOVAL
:
case
IRP_MN_CANCEL_REMOVE_DEVICE
:
case
IRP_MN_QUERY_REMOVE_DEVICE
:
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
case
IRP_MN_QUERY_DEVICE_RELATIONS
:
{
DEVICE_RELATION_TYPE
type
=
stack
->
Parameters
.
QueryDeviceRelations
.
Type
;
switch
(
type
)
{
case
BusRelations
:
case
EjectionRelations
:
if
(
winetest_debug
>
1
)
trace
(
"IRP_MN_QUERY_DEVICE_RELATIONS type %u not handled
\n
"
,
type
);
break
;
case
RemovalRelations
:
ok
(
!
irp
->
IoStatus
.
Information
,
"got unexpected RemovalRelations relations
\n
"
);
irp
->
IoStatus
.
Information
=
get_device_relations
(
device
,
(
void
*
)
irp
->
IoStatus
.
Information
,
1
,
&
ext
->
PhysicalDeviceObject
);
if
(
!
irp
->
IoStatus
.
Information
)
irp
->
IoStatus
.
Status
=
STATUS_NO_MEMORY
;
else
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
default:
ok
(
0
,
"got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x
\n
"
,
type
);
break
;
}
break
;
}
}
IoSkipCurrentIrpStackLocation
(
irp
);
return
IoCallDriver
(
ext
->
NextDeviceObject
,
irp
);
}
static
NTSTATUS
WINAPI
driver_internal_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
const
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_ioctl
(
code
)
);
check_device
(
device
);
IoSkipCurrentIrpStackLocation
(
irp
);
return
IoCallDriver
(
ext
->
PhysicalDeviceObject
,
irp
);
}
static
NTSTATUS
(
WINAPI
*
hidclass_driver_ioctl
)(
DEVICE_OBJECT
*
device
,
IRP
*
irp
);
static
NTSTATUS
WINAPI
driver_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_ioctl
(
code
)
);
switch
(
code
)
{
case
IOCTL_WINETEST_HID_SET_EXPECT
:
case
IOCTL_WINETEST_HID_WAIT_EXPECT
:
case
IOCTL_WINETEST_HID_SEND_INPUT
:
case
IOCTL_WINETEST_HID_SET_CONTEXT
:
IoSkipCurrentIrpStackLocation
(
irp
);
return
IoCallDriver
(
ext
->
PhysicalDeviceObject
,
irp
);
case
IOCTL_WINETEST_REMOVE_DEVICE
:
case
IOCTL_WINETEST_CREATE_DEVICE
:
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_NOT_SUPPORTED
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_NOT_SUPPORTED
;
}
return
hidclass_driver_ioctl
(
device
,
irp
);
}
static
NTSTATUS
WINAPI
driver_add_device
(
DRIVER_OBJECT
*
driver
,
DEVICE_OBJECT
*
device
)
{
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
struct
hid_device
*
impl
=
ext
->
MiniDeviceExtension
;
DEVICE_OBJECT
*
bus_pdo
=
ext
->
PhysicalDeviceObject
;
NTSTATUS
status
;
if
(
winetest_debug
>
1
)
trace
(
"%s: driver %p, device %p
\n
"
,
__func__
,
driver
,
device
);
impl
->
expect_hid_fdo
=
device
;
impl
->
expect_bus_pdo
=
ext
->
PhysicalDeviceObject
;
impl
->
expect_hid_ext
=
ext
->
MiniDeviceExtension
;
todo_wine
ok
(
impl
->
expect_bus_pdo
->
AttachedDevice
==
device
,
"got AttachedDevice %p
\n
"
,
bus_pdo
->
AttachedDevice
);
ok
(
driver
==
expect_driver
,
"got driver %p
\n
"
,
driver
);
check_device
(
device
);
status
=
IoRegisterDeviceInterface
(
ext
->
PhysicalDeviceObject
,
&
control_class
,
NULL
,
&
impl
->
control_symlink
);
ok
(
!
status
,
"IoRegisterDeviceInterface returned %#lx
\n
"
,
status
);
if
(
winetest_debug
>
1
)
trace
(
"Created HID FDO %p for Bus PDO %p
\n
"
,
device
,
ext
->
PhysicalDeviceObject
);
device
->
Flags
&=
~
DO_DEVICE_INITIALIZING
;
return
STATUS_SUCCESS
;
}
static
NTSTATUS
WINAPI
driver_create
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p
\n
"
,
__func__
,
device
);
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_SUCCESS
;
}
static
NTSTATUS
WINAPI
driver_close
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p
\n
"
,
__func__
,
device
);
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_SUCCESS
;
}
static
void
WINAPI
driver_unload
(
DRIVER_OBJECT
*
driver
)
{
if
(
winetest_debug
>
1
)
trace
(
"%s: driver %p
\n
"
,
__func__
,
driver
);
winetest_cleanup
();
}
NTSTATUS
WINAPI
DriverEntry
(
DRIVER_OBJECT
*
driver
,
UNICODE_STRING
*
registry
)
{
HID_MINIDRIVER_REGISTRATION
params
=
{
.
Revision
=
HID_REVISION
,
.
DriverObject
=
driver
,
.
DeviceExtensionSize
=
sizeof
(
struct
hid_device
),
.
RegistryPath
=
registry
,
};
NTSTATUS
status
;
expect_driver
=
driver
;
if
((
status
=
winetest_init
()))
return
status
;
if
(
winetest_debug
>
1
)
trace
(
"%s: driver %p
\n
"
,
__func__
,
driver
);
driver
->
DriverExtension
->
AddDevice
=
driver_add_device
;
driver
->
DriverUnload
=
driver_unload
;
driver
->
MajorFunction
[
IRP_MJ_PNP
]
=
driver_pnp
;
driver
->
MajorFunction
[
IRP_MJ_DEVICE_CONTROL
]
=
driver_ioctl
;
driver
->
MajorFunction
[
IRP_MJ_INTERNAL_DEVICE_CONTROL
]
=
driver_internal_ioctl
;
driver
->
MajorFunction
[
IRP_MJ_CREATE
]
=
driver_create
;
driver
->
MajorFunction
[
IRP_MJ_CLOSE
]
=
driver_close
;
status
=
HidRegisterMinidriver
(
&
params
);
ok
(
!
status
,
"got %#lx
\n
"
,
status
);
hidclass_driver_ioctl
=
driver
->
MajorFunction
[
IRP_MJ_DEVICE_CONTROL
];
driver
->
MajorFunction
[
IRP_MJ_DEVICE_CONTROL
]
=
driver_ioctl
;
return
STATUS_SUCCESS
;
}
dlls/dinput/tests/driver_hid.h
View file @
2a52c8dc
...
...
@@ -35,6 +35,8 @@
#include "winternl.h"
#include "ddk/wdm.h"
#include "ddk/hidsdi.h"
#include "ddk/hidport.h"
#include "ddk/hidclass.h"
DEFINE_GUID
(
control_class
,
0xdeadbeef
,
0x29ef
,
0x4538
,
0xa5
,
0xfd
,
0xb6
,
0x95
,
0x73
,
0xa3
,
0x62
,
0xc0
);
...
...
@@ -62,8 +64,21 @@ struct hid_expect
/* create/remove device */
struct
bus_device_desc
{
WORD
vid
;
WORD
pid
;
BOOL
is_polled
;
BOOL
use_report_id
;
DWORD
report_descriptor_len
;
char
report_descriptor_buf
[
1024
];
HIDP_CAPS
caps
;
HID_DEVICE_ATTRIBUTES
attributes
;
ULONG
input_size
;
struct
hid_expect
input
[
64
];
ULONG
expect_size
;
struct
hid_expect
expect
[
64
];
ULONG
context_size
;
char
context
[
64
];
};
/* kernel/user shared data */
...
...
dlls/dinput/tests/driver_hid.spec
0 → 100644
View file @
2a52c8dc
# nothing here yet
dlls/dinput/tests/driver_hid_poll.c
0 → 100644
View file @
2a52c8dc
/*
* Copyright 2022 Rémi Bernon for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
#include "winioctl.h"
#include "ddk/wdm.h"
#include "hidusage.h"
#include "ddk/hidpi.h"
#include "ddk/hidport.h"
#include "wine/list.h"
#include "initguid.h"
#include "driver_hid.h"
static
DRIVER_OBJECT
*
expect_driver
;
struct
hid_device
{
DEVICE_OBJECT
*
expect_bus_pdo
;
DEVICE_OBJECT
*
expect_hid_fdo
;
struct
hid_device
*
expect_hid_ext
;
UNICODE_STRING
control_symlink
;
};
static
void
check_device
(
DEVICE_OBJECT
*
device
)
{
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
struct
hid_device
*
impl
=
ext
->
MiniDeviceExtension
;
ok
(
device
==
impl
->
expect_hid_fdo
,
"got device %p
\n
"
,
device
);
ok
(
device
->
DriverObject
==
expect_driver
,
"got DriverObject %p
\n
"
,
device
->
DriverObject
);
if
(
!
device
->
NextDevice
)
ok
(
device
==
impl
->
expect_hid_fdo
,
"got device %p
\n
"
,
device
);
else
ok
(
device
->
NextDevice
==
impl
->
expect_hid_fdo
,
"got NextDevice %p
\n
"
,
device
->
NextDevice
);
ok
(
!
device
->
AttachedDevice
,
"got AttachedDevice %p
\n
"
,
device
->
AttachedDevice
);
ok
(
ext
->
MiniDeviceExtension
==
impl
->
expect_hid_ext
,
"got MiniDeviceExtension %p
\n
"
,
ext
->
MiniDeviceExtension
);
ok
(
ext
->
PhysicalDeviceObject
==
impl
->
expect_bus_pdo
,
"got PhysicalDeviceObject %p
\n
"
,
ext
->
PhysicalDeviceObject
);
ok
(
ext
->
NextDeviceObject
==
impl
->
expect_bus_pdo
,
"got NextDeviceObject %p
\n
"
,
ext
->
NextDeviceObject
);
}
#ifdef __ASM_USE_FASTCALL_WRAPPER
extern
void
*
WINAPI
wrap_fastcall_func1
(
void
*
func
,
const
void
*
a
);
__ASM_STDCALL_FUNC
(
wrap_fastcall_func1
,
8
,
"popl %ecx
\n\t
"
"popl %eax
\n\t
"
"xchgl (%esp),%ecx
\n\t
"
"jmp *%eax"
);
#define call_fastcall_func1( func, a ) wrap_fastcall_func1( func, a )
#else
#define call_fastcall_func1( func, a ) func( a )
#endif
static
ULONG_PTR
get_device_relations
(
DEVICE_OBJECT
*
device
,
DEVICE_RELATIONS
*
previous
,
ULONG
count
,
DEVICE_OBJECT
**
devices
)
{
DEVICE_RELATIONS
*
relations
;
ULONG
new_count
=
count
;
if
(
previous
)
new_count
+=
previous
->
Count
;
if
(
!
(
relations
=
ExAllocatePool
(
PagedPool
,
offsetof
(
DEVICE_RELATIONS
,
Objects
[
new_count
]
)
)))
{
ok
(
0
,
"Failed to allocate memory
\n
"
);
return
(
ULONG_PTR
)
previous
;
}
if
(
!
previous
)
relations
->
Count
=
0
;
else
{
memcpy
(
relations
,
previous
,
offsetof
(
DEVICE_RELATIONS
,
Objects
[
previous
->
Count
]
)
);
ExFreePool
(
previous
);
}
while
(
count
--
)
{
call_fastcall_func1
(
ObfReferenceObject
,
*
devices
);
relations
->
Objects
[
relations
->
Count
++
]
=
*
devices
++
;
}
return
(
ULONG_PTR
)
relations
;
}
static
NTSTATUS
WINAPI
driver_pnp
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
struct
hid_device
*
impl
=
ext
->
MiniDeviceExtension
;
ULONG
code
=
stack
->
MinorFunction
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_pnp
(
code
)
);
switch
(
code
)
{
case
IRP_MN_START_DEVICE
:
IoSetDeviceInterfaceState
(
&
impl
->
control_symlink
,
TRUE
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
case
IRP_MN_REMOVE_DEVICE
:
IoSetDeviceInterfaceState
(
&
impl
->
control_symlink
,
FALSE
);
RtlFreeUnicodeString
(
&
impl
->
control_symlink
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
case
IRP_MN_STOP_DEVICE
:
case
IRP_MN_SURPRISE_REMOVAL
:
case
IRP_MN_CANCEL_REMOVE_DEVICE
:
case
IRP_MN_QUERY_REMOVE_DEVICE
:
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
case
IRP_MN_QUERY_DEVICE_RELATIONS
:
{
DEVICE_RELATION_TYPE
type
=
stack
->
Parameters
.
QueryDeviceRelations
.
Type
;
switch
(
type
)
{
case
BusRelations
:
case
EjectionRelations
:
if
(
winetest_debug
>
1
)
trace
(
"IRP_MN_QUERY_DEVICE_RELATIONS type %u not handled
\n
"
,
type
);
break
;
case
RemovalRelations
:
ok
(
!
irp
->
IoStatus
.
Information
,
"got unexpected RemovalRelations relations
\n
"
);
irp
->
IoStatus
.
Information
=
get_device_relations
(
device
,
(
void
*
)
irp
->
IoStatus
.
Information
,
1
,
&
ext
->
PhysicalDeviceObject
);
if
(
!
irp
->
IoStatus
.
Information
)
irp
->
IoStatus
.
Status
=
STATUS_NO_MEMORY
;
else
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
break
;
default:
ok
(
0
,
"got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x
\n
"
,
type
);
break
;
}
break
;
}
}
IoSkipCurrentIrpStackLocation
(
irp
);
return
IoCallDriver
(
ext
->
NextDeviceObject
,
irp
);
}
static
NTSTATUS
WINAPI
driver_internal_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
const
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
if
(
code
!=
IOCTL_HID_READ_REPORT
&&
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_ioctl
(
code
)
);
check_device
(
device
);
IoSkipCurrentIrpStackLocation
(
irp
);
return
IoCallDriver
(
ext
->
PhysicalDeviceObject
,
irp
);
}
static
NTSTATUS
(
WINAPI
*
hidclass_driver_ioctl
)(
DEVICE_OBJECT
*
device
,
IRP
*
irp
);
static
NTSTATUS
WINAPI
driver_ioctl
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
IO_STACK_LOCATION
*
stack
=
IoGetCurrentIrpStackLocation
(
irp
);
ULONG
code
=
stack
->
Parameters
.
DeviceIoControl
.
IoControlCode
;
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p, code %#lx %s
\n
"
,
__func__
,
device
,
code
,
debugstr_ioctl
(
code
)
);
switch
(
code
)
{
case
IOCTL_WINETEST_HID_SET_EXPECT
:
case
IOCTL_WINETEST_HID_WAIT_EXPECT
:
case
IOCTL_WINETEST_HID_SEND_INPUT
:
case
IOCTL_WINETEST_HID_SET_CONTEXT
:
IoSkipCurrentIrpStackLocation
(
irp
);
return
IoCallDriver
(
ext
->
PhysicalDeviceObject
,
irp
);
case
IOCTL_WINETEST_REMOVE_DEVICE
:
case
IOCTL_WINETEST_CREATE_DEVICE
:
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_NOT_SUPPORTED
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_NOT_SUPPORTED
;
}
return
hidclass_driver_ioctl
(
device
,
irp
);
}
static
NTSTATUS
WINAPI
driver_add_device
(
DRIVER_OBJECT
*
driver
,
DEVICE_OBJECT
*
device
)
{
HID_DEVICE_EXTENSION
*
ext
=
device
->
DeviceExtension
;
struct
hid_device
*
impl
=
ext
->
MiniDeviceExtension
;
DEVICE_OBJECT
*
bus_pdo
=
ext
->
PhysicalDeviceObject
;
NTSTATUS
status
;
if
(
winetest_debug
>
1
)
trace
(
"%s: driver %p, device %p
\n
"
,
__func__
,
driver
,
device
);
impl
->
expect_hid_fdo
=
device
;
impl
->
expect_bus_pdo
=
ext
->
PhysicalDeviceObject
;
impl
->
expect_hid_ext
=
ext
->
MiniDeviceExtension
;
todo_wine
ok
(
impl
->
expect_bus_pdo
->
AttachedDevice
==
device
,
"got AttachedDevice %p
\n
"
,
bus_pdo
->
AttachedDevice
);
ok
(
driver
==
expect_driver
,
"got driver %p
\n
"
,
driver
);
check_device
(
device
);
status
=
IoRegisterDeviceInterface
(
ext
->
PhysicalDeviceObject
,
&
control_class
,
NULL
,
&
impl
->
control_symlink
);
ok
(
!
status
,
"IoRegisterDeviceInterface returned %#lx
\n
"
,
status
);
if
(
winetest_debug
>
1
)
trace
(
"Created HID FDO %p for Bus PDO %p
\n
"
,
device
,
ext
->
PhysicalDeviceObject
);
device
->
Flags
&=
~
DO_DEVICE_INITIALIZING
;
return
STATUS_SUCCESS
;
}
static
NTSTATUS
WINAPI
driver_create
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p
\n
"
,
__func__
,
device
);
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_SUCCESS
;
}
static
NTSTATUS
WINAPI
driver_close
(
DEVICE_OBJECT
*
device
,
IRP
*
irp
)
{
if
(
winetest_debug
>
1
)
trace
(
"%s: device %p
\n
"
,
__func__
,
device
);
ok
(
0
,
"unexpected call
\n
"
);
irp
->
IoStatus
.
Status
=
STATUS_SUCCESS
;
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
return
STATUS_SUCCESS
;
}
static
void
WINAPI
driver_unload
(
DRIVER_OBJECT
*
driver
)
{
if
(
winetest_debug
>
1
)
trace
(
"%s: driver %p
\n
"
,
__func__
,
driver
);
winetest_cleanup
();
}
NTSTATUS
WINAPI
DriverEntry
(
DRIVER_OBJECT
*
driver
,
UNICODE_STRING
*
registry
)
{
HID_MINIDRIVER_REGISTRATION
params
=
{
.
Revision
=
HID_REVISION
,
.
DriverObject
=
driver
,
.
DeviceExtensionSize
=
sizeof
(
struct
hid_device
),
.
RegistryPath
=
registry
,
.
DevicesArePolled
=
TRUE
,
};
NTSTATUS
status
;
expect_driver
=
driver
;
if
((
status
=
winetest_init
()))
return
status
;
if
(
winetest_debug
>
1
)
trace
(
"%s: driver %p
\n
"
,
__func__
,
driver
);
driver
->
DriverExtension
->
AddDevice
=
driver_add_device
;
driver
->
DriverUnload
=
driver_unload
;
driver
->
MajorFunction
[
IRP_MJ_PNP
]
=
driver_pnp
;
driver
->
MajorFunction
[
IRP_MJ_DEVICE_CONTROL
]
=
driver_ioctl
;
driver
->
MajorFunction
[
IRP_MJ_INTERNAL_DEVICE_CONTROL
]
=
driver_internal_ioctl
;
driver
->
MajorFunction
[
IRP_MJ_CREATE
]
=
driver_create
;
driver
->
MajorFunction
[
IRP_MJ_CLOSE
]
=
driver_close
;
status
=
HidRegisterMinidriver
(
&
params
);
ok
(
!
status
,
"got %#lx
\n
"
,
status
);
hidclass_driver_ioctl
=
driver
->
MajorFunction
[
IRP_MJ_DEVICE_CONTROL
];
driver
->
MajorFunction
[
IRP_MJ_DEVICE_CONTROL
]
=
driver_ioctl
;
return
STATUS_SUCCESS
;
}
dlls/dinput/tests/driver_hid_poll.spec
0 → 100644
View file @
2a52c8dc
# nothing here yet
dlls/dinput/tests/hid.c
View file @
2a52c8dc
...
...
@@ -39,6 +39,7 @@
#include "setupapi.h"
#include "cfgmgr32.h"
#include "newdev.h"
#include "dbt.h"
#include "objbase.h"
...
...
@@ -65,8 +66,11 @@ const WCHAR expect_vidpid_str[] = L"VID_1209&PID_0001";
const
GUID
expect_guid_product
=
{
EXPECT_VIDPID
,
0x0000
,
0x0000
,
{
0x00
,
0x00
,
'P'
,
'I'
,
'D'
,
'V'
,
'I'
,
'D'
}};
const
WCHAR
expect_path
[]
=
L"
\\\\
?
\\
hid#winetest#1&2fafeb0&"
;
const
WCHAR
expect_path_end
[]
=
L"&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
;
HANDLE
device_added
,
device_removed
;
static
BOOL
hid_device_created
;
static
struct
winetest_shared_data
*
test_data
;
static
HANDLE
monitor_thread
,
monitor_stop
;
static
HANDLE
test_data_mapping
;
static
HANDLE
okfile
;
...
...
@@ -316,6 +320,8 @@ static const char inf_text[] =
"[mfg_section.NT"
EXT
"]
\n
"
"Wine test root driver=device_section,test_hardware_id
\n
"
"Wine Test Bus Device=bus_section,WINETEST
\\
BUS
\n
"
"Wine Test HID Device=hid_section,WINETEST
\\
WINE_COMP_HID
\n
"
"Wine Test HID Polled Device=hid_poll_section,WINETEST
\\
WINE_COMP_POLLHID
\n
"
"[device_section.NT"
EXT
"]
\n
"
"CopyFiles=file_section
\n
"
...
...
@@ -329,17 +335,35 @@ static const char inf_text[] =
"[bus_section.NT"
EXT
".Services]
\n
"
"AddService=winetest_bus,0x2,bus_service
\n
"
"[hid_section.NT"
EXT
"]
\n
"
"CopyFiles=file_section
\n
"
"[hid_section.NT"
EXT
".Services]
\n
"
"AddService=winetest_hid,0x2,hid_service
\n
"
"[hid_poll_section.NT"
EXT
"]
\n
"
"CopyFiles=file_section
\n
"
"[hid_poll_section.NT"
EXT
".Services]
\n
"
"AddService=winetest_hid_poll,0x2,hid_poll_service
\n
"
"[file_section]
\n
"
"winetest.sys
\n
"
"winetest_bus.sys
\n
"
"winetest_hid.sys
\n
"
"winetest_hid_poll.sys
\n
"
"[SourceDisksFiles]
\n
"
"winetest.sys=1
\n
"
"winetest_bus.sys=1
\n
"
"winetest_hid.sys=1
\n
"
"winetest_hid_poll.sys=1
\n
"
"[SourceDisksNames]
\n
"
"1=,winetest.sys
\n
"
"1=,winetest_bus.sys
\n
"
"1=,winetest_hid.sys
\n
"
"1=,winetest_hid_poll.sys
\n
"
"[DestinationDirs]
\n
"
"DefaultDestDir=12
\n
"
...
...
@@ -359,6 +383,22 @@ static const char inf_text[] =
"ErrorControl=1
\n
"
"LoadOrderGroup=WinePlugPlay
\n
"
"DisplayName=
\"
Wine Test Bus Driver
\"\n
"
"[hid_service]
\n
"
"ServiceBinary=%12%
\\
winetest_hid.sys
\n
"
"ServiceType=1
\n
"
"StartType=3
\n
"
"ErrorControl=1
\n
"
"LoadOrderGroup=WinePlugPlay
\n
"
"DisplayName=
\"
Wine Test HID Driver
\"\n
"
"[hid_poll_service]
\n
"
"ServiceBinary=%12%
\\
winetest_hid_poll.sys
\n
"
"ServiceType=1
\n
"
"StartType=3
\n
"
"ErrorControl=1
\n
"
"LoadOrderGroup=WinePlugPlay
\n
"
"DisplayName=
\"
Wine Test HID Polled Driver
\"\n
"
"; they don't sleep anymore, on the beach
\n
"
;
static
void
add_file_to_catalog
(
HANDLE
catalog
,
const
WCHAR
*
file
)
...
...
@@ -505,11 +545,20 @@ static void pnp_driver_stop( BOOL bus )
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest_bus.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest_hid.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest_hid_poll.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
/* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */
ret
=
DeleteFileW
(
L"C:/windows/system32/drivers/winetest.sys"
);
ok
(
ret
||
GetLastError
()
==
ERROR_FILE_NOT_FOUND
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"C:/windows/system32/drivers/winetest_bus.sys"
);
ok
(
ret
||
GetLastError
()
==
ERROR_FILE_NOT_FOUND
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"C:/windows/system32/drivers/winetest_hid.sys"
);
todo_wine_if
(
!
ret
&&
GetLastError
()
==
ERROR_ACCESS_DENIED
)
/* Wine doesn't unload device drivers correctly */
ok
(
ret
||
GetLastError
()
==
ERROR_FILE_NOT_FOUND
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"C:/windows/system32/drivers/winetest_hid_poll.sys"
);
ok
(
ret
||
GetLastError
()
==
ERROR_FILE_NOT_FOUND
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
}
static
BOOL
find_hid_device_path
(
WCHAR
*
device_path
)
...
...
@@ -527,8 +576,11 @@ static BOOL find_hid_device_path( WCHAR *device_path )
for
(
i
=
0
;
SetupDiEnumDeviceInfo
(
set
,
i
,
&
device
);
++
i
)
{
SetLastError
(
0xdeadbeef
);
ret
=
SetupDiEnumDeviceInterfaces
(
set
,
&
device
,
&
GUID_DEVINTERFACE_HID
,
0
,
&
iface
);
todo_wine_if
(
!
ret
&&
GetLastError
()
==
ERROR_NO_MORE_ITEMS
)
/* Wine doesn't unload device drivers correctly */
ok
(
ret
,
"Failed to get interface, error %#lx
\n
"
,
GetLastError
()
);
if
(
!
ret
)
continue
;
ok
(
IsEqualGUID
(
&
iface
.
InterfaceClassGuid
,
&
GUID_DEVINTERFACE_HID
),
"wrong class %s
\n
"
,
debugstr_guid
(
&
iface
.
InterfaceClassGuid
)
);
ok
(
iface
.
Flags
==
SPINT_ACTIVE
,
"got flags %#lx
\n
"
,
iface
.
Flags
);
...
...
@@ -574,6 +626,14 @@ static BOOL pnp_driver_start( BOOL bus )
ret
=
MoveFileExW
(
filename
,
L"winetest_bus.sys"
,
MOVEFILE_COPY_ALLOWED
|
MOVEFILE_REPLACE_EXISTING
);
ok
(
ret
,
"failed to move file, error %lu
\n
"
,
GetLastError
()
);
load_resource
(
L"driver_hid.dll"
,
filename
);
ret
=
MoveFileExW
(
filename
,
L"winetest_hid.sys"
,
MOVEFILE_COPY_ALLOWED
|
MOVEFILE_REPLACE_EXISTING
);
ok
(
ret
,
"failed to move file, error %lu
\n
"
,
GetLastError
()
);
load_resource
(
L"driver_hid_poll.dll"
,
filename
);
ret
=
MoveFileExW
(
filename
,
L"winetest_hid_poll.sys"
,
MOVEFILE_COPY_ALLOWED
|
MOVEFILE_REPLACE_EXISTING
);
ok
(
ret
,
"failed to move file, error %lu
\n
"
,
GetLastError
()
);
f
=
fopen
(
"winetest.inf"
,
"w"
);
ok
(
!!
f
,
"failed to open winetest.inf: %s
\n
"
,
strerror
(
errno
)
);
fputs
(
inf_text
,
f
);
...
...
@@ -586,6 +646,8 @@ static BOOL pnp_driver_start( BOOL bus )
add_file_to_catalog
(
catalog
,
L"winetest.sys"
);
add_file_to_catalog
(
catalog
,
L"winetest_bus.sys"
);
add_file_to_catalog
(
catalog
,
L"winetest_hid.sys"
);
add_file_to_catalog
(
catalog
,
L"winetest_hid_poll.sys"
);
add_file_to_catalog
(
catalog
,
L"winetest.inf"
);
ret
=
CryptCATPersistStore
(
catalog
);
...
...
@@ -603,6 +665,10 @@ static BOOL pnp_driver_start( BOOL bus )
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest_bus.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest_hid.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest_hid_poll.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
ret
=
DeleteFileW
(
L"winetest.sys"
);
ok
(
ret
,
"Failed to delete file, error %lu
\n
"
,
GetLastError
()
);
winetest_mute_threshold
=
old_mute_threshold
;
...
...
@@ -3408,10 +3474,74 @@ BOOL dinput_driver_start_( const char *file, int line, const BYTE *desc_buf, ULO
return
hid_device_start
();
}
static
LRESULT
CALLBACK
monitor_wndproc
(
HWND
hwnd
,
UINT
msg
,
WPARAM
wparam
,
LPARAM
lparam
)
{
if
(
msg
==
WM_DEVICECHANGE
)
{
DEV_BROADCAST_DEVICEINTERFACE_W
*
iface
=
(
DEV_BROADCAST_DEVICEINTERFACE_W
*
)
lparam
;
if
(
wparam
==
DBT_DEVICEREMOVECOMPLETE
&&
IsEqualGUID
(
&
iface
->
dbcc_classguid
,
&
control_class
))
SetEvent
(
device_removed
);
if
(
wparam
==
DBT_DEVICEARRIVAL
&&
IsEqualGUID
(
&
iface
->
dbcc_classguid
,
&
GUID_DEVINTERFACE_HID
))
SetEvent
(
device_added
);
}
return
DefWindowProcW
(
hwnd
,
msg
,
wparam
,
lparam
);
}
DWORD
WINAPI
monitor_thread_proc
(
void
*
stop_event
)
{
DEV_BROADCAST_DEVICEINTERFACE_A
iface_filter_a
=
{
.
dbcc_size
=
sizeof
(
DEV_BROADCAST_DEVICEINTERFACE_A
),
.
dbcc_devicetype
=
DBT_DEVTYP_DEVICEINTERFACE
,
};
WNDCLASSEXW
class
=
{
.
cbSize
=
sizeof
(
WNDCLASSEXW
),
.
hInstance
=
GetModuleHandleW
(
NULL
),
.
lpszClassName
=
L"device_monitor"
,
.
lpfnWndProc
=
monitor_wndproc
,
};
HDEVNOTIFY
devnotify
;
HANDLE
hwnd
;
MSG
msg
;
RegisterClassExW
(
&
class
);
hwnd
=
CreateWindowW
(
class
.
lpszClassName
,
NULL
,
0
,
0
,
0
,
0
,
0
,
HWND_MESSAGE
,
NULL
,
NULL
,
NULL
);
ok
(
!!
hwnd
,
"CreateWindowW failed, error %lu
\n
"
,
GetLastError
()
);
devnotify
=
RegisterDeviceNotificationA
(
hwnd
,
&
iface_filter_a
,
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
);
ok
(
!!
devnotify
,
"RegisterDeviceNotificationA failed, error %lu
\n
"
,
GetLastError
()
);
do
{
while
(
PeekMessageW
(
&
msg
,
hwnd
,
0
,
0
,
PM_REMOVE
))
{
TranslateMessage
(
&
msg
);
DispatchMessageW
(
&
msg
);
}
}
while
(
MsgWaitForMultipleObjects
(
1
,
&
stop_event
,
FALSE
,
INFINITE
,
QS_ALLINPUT
));
UnregisterDeviceNotification
(
devnotify
);
DestroyWindow
(
hwnd
);
UnregisterClassW
(
class
.
lpszClassName
,
class
.
hInstance
);
CloseHandle
(
stop_event
);
return
0
;
}
BOOL
dinput_test_init_
(
const
char
*
file
,
int
line
)
{
BOOL
is_wow64
;
monitor_stop
=
CreateEventW
(
NULL
,
FALSE
,
FALSE
,
NULL
);
ok
(
!!
monitor_stop
,
"CreateEventW failed, error %lu
\n
"
,
GetLastError
()
);
device_added
=
CreateEventW
(
NULL
,
FALSE
,
FALSE
,
NULL
);
ok
(
!!
device_added
,
"CreateEventW failed, error %lu
\n
"
,
GetLastError
()
);
device_removed
=
CreateEventW
(
NULL
,
FALSE
,
FALSE
,
NULL
);
ok
(
!!
device_removed
,
"CreateEventW failed, error %lu
\n
"
,
GetLastError
()
);
monitor_thread
=
CreateThread
(
NULL
,
0
,
monitor_thread_proc
,
monitor_stop
,
0
,
NULL
);
ok
(
!!
monitor_thread
,
"CreateThread failed, error %lu
\n
"
,
GetLastError
()
);
subtest_
(
file
,
line
)(
"hid"
);
instance
=
GetModuleHandleW
(
NULL
);
localized
=
GetUserDefaultLCID
()
!=
MAKELANGID
(
LANG_ENGLISH
,
SUBLANG_DEFAULT
);
...
...
@@ -3442,6 +3572,8 @@ BOOL dinput_test_init_( const char *file, int line )
subtest
(
"driver"
);
subtest
(
"driver_bus"
);
subtest
(
"driver_hid"
);
subtest
(
"driver_hid_poll"
);
return
TRUE
;
}
...
...
@@ -3451,6 +3583,13 @@ void dinput_test_exit(void)
CloseHandle
(
test_data_mapping
);
CloseHandle
(
okfile
);
DeleteFileW
(
L"C:
\\
windows
\\
winetest_dinput_okfile"
);
SetEvent
(
monitor_stop
);
WaitForSingleObject
(
monitor_thread
,
INFINITE
);
CloseHandle
(
monitor_thread
);
CloseHandle
(
monitor_stop
);
CloseHandle
(
device_removed
);
CloseHandle
(
device_added
);
}
BOOL
CALLBACK
find_test_device
(
const
DIDEVICEINSTANCEW
*
devinst
,
void
*
context
)
...
...
@@ -3612,10 +3751,39 @@ DWORD WINAPI dinput_test_device_thread( void *stop_event )
static
void
test_bus_driver
(
void
)
{
struct
bus_device_desc
desc
=
#include "psh_hid_macros.h"
const
unsigned
char
report_desc
[]
=
{
USAGE_PAGE
(
1
,
HID_USAGE_PAGE_GENERIC
),
USAGE
(
1
,
HID_USAGE_GENERIC_JOYSTICK
),
COLLECTION
(
1
,
Application
),
USAGE
(
1
,
HID_USAGE_GENERIC_X
),
REPORT_SIZE
(
1
,
8
),
REPORT_COUNT
(
1
,
1
),
INPUT
(
1
,
Data
|
Var
|
Abs
),
END_COLLECTION
,
};
#include "pop_hid_macros.h"
static
const
HID_DEVICE_ATTRIBUTES
attributes
=
{
.
vid
=
LOWORD
(
EXPECT_VIDPID
),
.
pid
=
HIWORD
(
EXPECT_VIDPID
),
.
Size
=
sizeof
(
HID_DEVICE_ATTRIBUTES
),
.
VendorID
=
LOWORD
(
EXPECT_VIDPID
),
.
ProductID
=
HIWORD
(
EXPECT_VIDPID
),
.
VersionNumber
=
0x0100
,
};
const
HIDP_CAPS
caps
=
{
.
Usage
=
HID_USAGE_GENERIC_JOYSTICK
,
.
UsagePage
=
HID_USAGE_PAGE_GENERIC
,
.
InputReportByteLength
=
2
,
.
NumberLinkCollectionNodes
=
1
,
.
NumberInputValueCaps
=
1
,
.
NumberInputDataIndices
=
1
,
};
struct
bus_device_desc
desc
=
{
.
caps
=
caps
,
.
attributes
=
attributes
,
};
WCHAR
device_path
[
MAX_PATH
];
HANDLE
control
;
BOOL
ret
;
...
...
@@ -3634,16 +3802,32 @@ static void test_bus_driver(void)
bus_device_start
();
desc
.
report_descriptor_len
=
sizeof
(
report_desc
);
memcpy
(
desc
.
report_descriptor_buf
,
report_desc
,
sizeof
(
report_desc
)
);
ResetEvent
(
device_added
);
control
=
CreateFileW
(
L"
\\\\
?
\\
root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}"
,
0
,
0
,
NULL
,
OPEN_EXISTING
,
0
,
NULL
);
ok
(
control
!=
INVALID_HANDLE_VALUE
,
"CreateFile failed, error %lu
\n
"
,
GetLastError
()
);
ret
=
sync_ioctl
(
control
,
IOCTL_WINETEST_CREATE_DEVICE
,
&
desc
,
sizeof
(
desc
),
NULL
,
0
,
INFINITE
);
ok
(
ret
,
"IOCTL_WINETEST_CREATE_DEVICE failed, last error %lu
\n
"
,
GetLastError
()
);
WaitForSingleObject
(
device_added
,
INFINITE
);
hid_device_created
=
TRUE
;
swprintf
(
device_path
,
MAX_PATH
,
L"
\\\\
?
\\
hid#vid_%04x&pid_%04x"
,
LOWORD
(
EXPECT_VIDPID
),
HIWORD
(
EXPECT_VIDPID
)
);
ret
=
find_hid_device_path
(
device_path
);
ok
(
ret
,
"Failed to find HID device matching %s
\n
"
,
debugstr_w
(
device_path
)
);
ResetEvent
(
device_removed
);
ret
=
sync_ioctl
(
control
,
IOCTL_WINETEST_REMOVE_DEVICE
,
&
desc
,
sizeof
(
desc
),
NULL
,
0
,
INFINITE
);
ok
(
ret
,
"IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu
\n
"
,
GetLastError
()
);
CloseHandle
(
control
);
WaitForSingleObject
(
device_removed
,
INFINITE
);
done:
bus_device_stop
();
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment