2 * HID Plug and Play test driver
4 * Copyright 2021 Zebediah Figura
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define WIN32_NO_STATUS
32 #include "ddk/hidpi.h"
33 #include "ddk/hidport.h"
35 #include "wine/list.h"
40 static UNICODE_STRING control_symlink
;
42 static unsigned int got_start_device
;
43 static DWORD report_id
;
52 static IRP
*irp_queue_pop(struct irp_queue
*queue
)
57 KeAcquireSpinLock(&queue
->lock
, &irql
);
58 if (IsListEmpty(&queue
->list
)) irp
= NULL
;
59 else irp
= CONTAINING_RECORD(RemoveHeadList(&queue
->list
), IRP
, Tail
.Overlay
.ListEntry
);
60 KeReleaseSpinLock(&queue
->lock
, irql
);
65 static void irp_queue_push(struct irp_queue
*queue
, IRP
*irp
)
69 KeAcquireSpinLock(&queue
->lock
, &irql
);
70 InsertTailList(&queue
->list
, &irp
->Tail
.Overlay
.ListEntry
);
71 KeReleaseSpinLock(&queue
->lock
, irql
);
74 static void irp_queue_clear(struct irp_queue
*queue
)
78 while ((irp
= irp_queue_pop(queue
)))
80 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
81 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
85 static void irp_queue_init(struct irp_queue
*queue
)
87 KeInitializeSpinLock(&queue
->lock
);
88 InitializeListHead(&queue
->list
);
95 struct irp_queue irp_queue
;
98 static NTSTATUS WINAPI
driver_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
100 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
101 HID_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
102 struct hid_device
*impl
= ext
->MiniDeviceExtension
;
105 if (winetest_debug
> 1) trace("pnp %#x\n", stack
->MinorFunction
);
107 switch (stack
->MinorFunction
)
109 case IRP_MN_START_DEVICE
:
111 impl
->removed
= FALSE
;
112 KeInitializeSpinLock(&impl
->lock
);
113 irp_queue_init(&impl
->irp_queue
);
114 IoSetDeviceInterfaceState(&control_symlink
, TRUE
);
115 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
118 case IRP_MN_SURPRISE_REMOVAL
:
119 case IRP_MN_QUERY_REMOVE_DEVICE
:
120 KeAcquireSpinLock(&impl
->lock
, &irql
);
121 impl
->removed
= TRUE
;
122 KeReleaseSpinLock(&impl
->lock
, irql
);
123 irp_queue_clear(&impl
->irp_queue
);
124 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
127 case IRP_MN_CANCEL_REMOVE_DEVICE
:
128 KeAcquireSpinLock(&impl
->lock
, &irql
);
129 impl
->removed
= FALSE
;
130 KeReleaseSpinLock(&impl
->lock
, irql
);
131 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
134 case IRP_MN_STOP_DEVICE
:
135 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
138 case IRP_MN_REMOVE_DEVICE
:
139 irp_queue_clear(&impl
->irp_queue
);
140 IoSetDeviceInterfaceState(&control_symlink
, FALSE
);
141 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
145 IoSkipCurrentIrpStackLocation(irp
);
146 return IoCallDriver(ext
->NextDeviceObject
, irp
);
150 static NTSTATUS WINAPI
driver_power(DEVICE_OBJECT
*device
, IRP
*irp
)
152 HID_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
154 /* We do not expect power IRPs as part of normal operation. */
155 ok(0, "unexpected call\n");
157 PoStartNextPowerIrp(irp
);
158 IoSkipCurrentIrpStackLocation(irp
);
159 return PoCallDriver(ext
->NextDeviceObject
, irp
);
162 static NTSTATUS WINAPI
driver_internal_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
164 #include "psh_hid_macros.h"
165 /* Replace REPORT_ID with USAGE_PAGE when id is 0 */
166 #define REPORT_ID_OR_USAGE_PAGE(size, id, off) SHORT_ITEM_1((id ? 8 : 0), 1, (id + off))
167 const unsigned char report_descriptor
[] =
169 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
170 USAGE(1, HID_USAGE_GENERIC_JOYSTICK
),
171 COLLECTION(1, Application
),
172 USAGE(1, HID_USAGE_GENERIC_JOYSTICK
),
173 COLLECTION(1, Logical
),
174 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 0),
175 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
176 USAGE(1, HID_USAGE_GENERIC_X
),
177 USAGE(1, HID_USAGE_GENERIC_Y
),
178 LOGICAL_MINIMUM(1, -128),
179 LOGICAL_MAXIMUM(1, 127),
182 INPUT(1, Data
|Var
|Abs
),
184 USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON
),
187 LOGICAL_MINIMUM(1, 0),
188 LOGICAL_MAXIMUM(1, 1),
191 INPUT(1, Data
|Var
|Abs
),
193 USAGE_MINIMUM(1, 0x18),
194 USAGE_MAXIMUM(1, 0x1f),
195 LOGICAL_MINIMUM(1, 0),
196 LOGICAL_MAXIMUM(1, 1),
199 INPUT(1, Cnst
|Var
|Abs
),
202 INPUT(1, Cnst
|Var
|Abs
),
203 /* needs to be 8 bit aligned as next has Buff */
205 USAGE_MINIMUM(4, (HID_USAGE_PAGE_KEYBOARD
<<16)|0x8),
206 USAGE_MAXIMUM(4, (HID_USAGE_PAGE_KEYBOARD
<<16)|0xf),
207 LOGICAL_MINIMUM(1, 0),
208 LOGICAL_MAXIMUM(1, 8),
211 INPUT(2, Data
|Ary
|Rel
|Wrap
|Lin
|Pref
|Null
|Vol
|Buff
),
213 /* needs to be 8 bit aligned as previous has Buff */
215 LOGICAL_MINIMUM(1, 0),
216 LOGICAL_MAXIMUM(1, 1),
219 INPUT(1, Data
|Var
|Abs
),
220 USAGE_MINIMUM(1, 0x21),
221 USAGE_MAXIMUM(1, 0x22),
224 INPUT(1, Data
|Var
|Abs
),
228 INPUT(1, Data
|Var
|Abs
),
230 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
231 USAGE(1, HID_USAGE_GENERIC_HATSWITCH
),
232 LOGICAL_MINIMUM(1, 1),
233 LOGICAL_MAXIMUM(1, 8),
236 INPUT(1, Data
|Var
|Abs
),
238 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
239 USAGE(1, HID_USAGE_GENERIC_Z
),
240 LOGICAL_MINIMUM(4, 0x00000000),
241 LOGICAL_MAXIMUM(4, 0x3fffffff),
242 PHYSICAL_MINIMUM(4, 0x80000000),
243 PHYSICAL_MAXIMUM(4, 0x7fffffff),
246 INPUT(1, Data
|Var
|Abs
),
248 /* reset physical range to its default interpretation */
249 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
250 USAGE(1, HID_USAGE_GENERIC_RX
),
251 PHYSICAL_MINIMUM(4, 0),
252 PHYSICAL_MAXIMUM(4, 0),
255 INPUT(1, Data
|Var
|Abs
),
257 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
258 USAGE(1, HID_USAGE_GENERIC_RY
),
259 LOGICAL_MINIMUM(4, 0x7fff),
260 LOGICAL_MAXIMUM(4, 0x0000),
261 PHYSICAL_MINIMUM(4, 0x0000),
262 PHYSICAL_MAXIMUM(4, 0x7fff),
265 INPUT(1, Data
|Var
|Abs
),
268 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
269 USAGE(1, HID_USAGE_GENERIC_JOYSTICK
),
270 COLLECTION(1, Report
),
271 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 1),
272 USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON
),
274 USAGE_MAXIMUM(1, 10),
275 LOGICAL_MINIMUM(1, 0),
276 LOGICAL_MAXIMUM(1, 1),
279 INPUT(1, Data
|Var
|Abs
),
282 USAGE_PAGE(1, HID_USAGE_PAGE_LED
),
283 USAGE(1, HID_USAGE_LED_GREEN
),
284 COLLECTION(1, Report
),
285 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 0),
286 USAGE_PAGE(1, HID_USAGE_PAGE_LED
),
295 LOGICAL_MINIMUM(1, 0),
296 LOGICAL_MAXIMUM(1, 1),
297 PHYSICAL_MINIMUM(1, 0),
298 PHYSICAL_MAXIMUM(1, 1),
301 INPUT(1, Data
|Var
|Abs
),
304 USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS
),
305 USAGE(1, HID_USAGE_HAPTICS_SIMPLE_CONTROLLER
),
306 COLLECTION(1, Logical
),
307 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 0),
308 USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS
),
310 USAGE(1, HID_USAGE_HAPTICS_WAVEFORM_LIST
),
311 COLLECTION(1, NamedArray
),
312 USAGE_PAGE(1, HID_USAGE_PAGE_ORDINAL
),
313 USAGE(1, 3), /* HID_USAGE_HAPTICS_WAVEFORM_RUMBLE */
314 USAGE(1, 4), /* HID_USAGE_HAPTICS_WAVEFORM_BUZZ */
315 LOGICAL_MINIMUM(2, 0x0000),
316 LOGICAL_MAXIMUM(2, 0xffff),
319 FEATURE(1, Data
|Var
|Abs
|Null
),
322 USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS
),
323 USAGE(1, HID_USAGE_HAPTICS_DURATION_LIST
),
324 COLLECTION(1, NamedArray
),
325 USAGE_PAGE(1, HID_USAGE_PAGE_ORDINAL
),
326 USAGE(1, 3), /* 0 (HID_USAGE_HAPTICS_WAVEFORM_RUMBLE) */
327 USAGE(1, 4), /* 0 (HID_USAGE_HAPTICS_WAVEFORM_BUZZ) */
328 LOGICAL_MINIMUM(2, 0x0000),
329 LOGICAL_MAXIMUM(2, 0xffff),
332 FEATURE(1, Data
|Var
|Abs
|Null
),
335 USAGE_PAGE(2, HID_USAGE_PAGE_HAPTICS
),
336 USAGE(1, HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME
),
337 UNIT(2, 0x1001), /* seconds */
338 UNIT_EXPONENT(1, -3), /* 10^-3 */
339 LOGICAL_MINIMUM(2, 0x8000),
340 LOGICAL_MAXIMUM(2, 0x7fff),
341 PHYSICAL_MINIMUM(4, 0x00000000),
342 PHYSICAL_MAXIMUM(4, 0xffffffff),
345 FEATURE(1, Data
|Var
|Abs
),
346 /* reset global items */
347 UNIT(1, 0), /* None */
351 USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC
),
352 USAGE(1, HID_USAGE_GENERIC_JOYSTICK
),
353 COLLECTION(1, Report
),
354 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 1),
355 USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON
),
357 USAGE_MAXIMUM(1, 10),
358 LOGICAL_MINIMUM(1, 0),
359 LOGICAL_MAXIMUM(1, 1),
360 PHYSICAL_MINIMUM(1, 0),
361 PHYSICAL_MAXIMUM(1, 1),
364 FEATURE(1, Data
|Var
|Abs
),
367 USAGE_PAGE(1, HID_USAGE_PAGE_LED
),
368 USAGE(1, HID_USAGE_LED_GREEN
),
369 COLLECTION(1, Report
),
370 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 0),
371 USAGE_PAGE(1, HID_USAGE_PAGE_LED
),
374 OUTPUT(1, Cnst
|Var
|Abs
),
377 USAGE_PAGE(1, HID_USAGE_PAGE_LED
),
378 USAGE(1, HID_USAGE_LED_RED
),
379 COLLECTION(1, Report
),
380 REPORT_ID_OR_USAGE_PAGE(1, report_id
, 1),
381 USAGE_PAGE(1, HID_USAGE_PAGE_LED
),
384 OUTPUT(1, Cnst
|Var
|Abs
),
388 #undef REPORT_ID_OR_USAGE_PAGE
389 #include "pop_hid_macros.h"
391 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
392 HID_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
393 struct hid_device
*impl
= ext
->MiniDeviceExtension
;
394 const ULONG in_size
= stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
395 const ULONG out_size
= stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
396 const ULONG code
= stack
->Parameters
.DeviceIoControl
.IoControlCode
;
402 if (winetest_debug
> 1) trace("ioctl %#x\n", code
);
404 ok(got_start_device
, "expected IRP_MN_START_DEVICE before any ioctls\n");
406 irp
->IoStatus
.Information
= 0;
408 KeAcquireSpinLock(&impl
->lock
, &irql
);
409 removed
= impl
->removed
;
410 KeReleaseSpinLock(&impl
->lock
, irql
);
414 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
415 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
416 return STATUS_DELETE_PENDING
;
421 case IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
423 HID_DESCRIPTOR
*desc
= irp
->UserBuffer
;
425 ok(!in_size
, "got input size %u\n", in_size
);
426 ok(out_size
== sizeof(*desc
), "got output size %u\n", out_size
);
428 if (out_size
== sizeof(*desc
))
430 ok(!desc
->bLength
, "got size %u\n", desc
->bLength
);
432 desc
->bLength
= sizeof(*desc
);
433 desc
->bDescriptorType
= HID_HID_DESCRIPTOR_TYPE
;
434 desc
->bcdHID
= HID_REVISION
;
436 desc
->bNumDescriptors
= 1;
437 desc
->DescriptorList
[0].bReportType
= HID_REPORT_DESCRIPTOR_TYPE
;
438 desc
->DescriptorList
[0].wReportLength
= sizeof(report_descriptor
);
439 irp
->IoStatus
.Information
= sizeof(*desc
);
441 ret
= STATUS_SUCCESS
;
445 case IOCTL_HID_GET_REPORT_DESCRIPTOR
:
446 ok(!in_size
, "got input size %u\n", in_size
);
447 ok(out_size
== sizeof(report_descriptor
), "got output size %u\n", out_size
);
449 if (out_size
== sizeof(report_descriptor
))
451 memcpy(irp
->UserBuffer
, report_descriptor
, sizeof(report_descriptor
));
452 irp
->IoStatus
.Information
= sizeof(report_descriptor
);
454 ret
= STATUS_SUCCESS
;
457 case IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
459 HID_DEVICE_ATTRIBUTES
*attr
= irp
->UserBuffer
;
461 ok(!in_size
, "got input size %u\n", in_size
);
462 ok(out_size
== sizeof(*attr
), "got output size %u\n", out_size
);
464 if (out_size
== sizeof(*attr
))
466 ok(!attr
->Size
, "got size %u\n", attr
->Size
);
468 attr
->Size
= sizeof(*attr
);
469 attr
->VendorID
= 0x1209;
470 attr
->ProductID
= 0x0001;
471 attr
->VersionNumber
= 0xface;
472 irp
->IoStatus
.Information
= sizeof(*attr
);
474 ret
= STATUS_SUCCESS
;
478 case IOCTL_HID_READ_REPORT
:
480 ULONG expected_size
= 23;
481 ok(!in_size
, "got input size %u\n", in_size
);
482 ok(out_size
== expected_size
, "got output size %u\n", out_size
);
486 memset(irp
->UserBuffer
, 0xa5, expected_size
);
487 if (report_id
) ((char *)irp
->UserBuffer
)[0] = report_id
;
488 ((char *)irp
->UserBuffer
)[1] = seq
++;
489 irp
->IoStatus
.Information
= 3;
490 ret
= STATUS_SUCCESS
;
494 IoMarkIrpPending(irp
);
495 irp_queue_push(&impl
->irp_queue
, irp
);
496 ret
= STATUS_PENDING
;
501 case IOCTL_HID_WRITE_REPORT
:
503 HID_XFER_PACKET
*packet
= irp
->UserBuffer
;
504 ULONG expected_size
= 2;
507 ok(in_size
== sizeof(*packet
), "got input size %u\n", in_size
);
509 ok(!out_size
, "got output size %u\n", out_size
);
510 ok(packet
->reportBufferLen
>= expected_size
, "got report size %u\n", packet
->reportBufferLen
);
514 todo_wine_if(packet
->reportBuffer
[0] == 0xa5)
515 ok(packet
->reportBuffer
[0] == report_id
, "got report id %x\n", packet
->reportBuffer
[0]);
520 ok(packet
->reportBuffer
[0] == 0xcd, "got first byte %x\n", packet
->reportBuffer
[0]);
523 irp
->IoStatus
.Information
= 3;
524 ret
= STATUS_SUCCESS
;
528 case IOCTL_HID_GET_INPUT_REPORT
:
530 HID_XFER_PACKET
*packet
= irp
->UserBuffer
;
531 ULONG expected_size
= 23;
532 ok(!in_size
, "got input size %u\n", in_size
);
533 ok(out_size
== sizeof(*packet
), "got output size %u\n", out_size
);
535 ok(packet
->reportId
== report_id
, "got id %u\n", packet
->reportId
);
536 ok(packet
->reportBufferLen
>= expected_size
, "got len %u\n", packet
->reportBufferLen
);
537 ok(!!packet
->reportBuffer
, "got buffer %p\n", packet
->reportBuffer
);
539 memset(packet
->reportBuffer
, 0xa5, 3);
540 if (report_id
) ((char *)packet
->reportBuffer
)[0] = report_id
;
541 ((char *)packet
->reportBuffer
)[1] = seq
++;
542 irp
->IoStatus
.Information
= 3;
543 ret
= STATUS_SUCCESS
;
547 case IOCTL_HID_SET_OUTPUT_REPORT
:
549 HID_XFER_PACKET
*packet
= irp
->UserBuffer
;
550 ULONG expected_size
= 2;
551 ok(in_size
== sizeof(*packet
), "got input size %u\n", in_size
);
552 ok(!out_size
, "got output size %u\n", out_size
);
554 ok(packet
->reportId
== report_id
, "got id %u\n", packet
->reportId
);
555 ok(packet
->reportBufferLen
>= expected_size
, "got len %u\n", packet
->reportBufferLen
);
556 ok(!!packet
->reportBuffer
, "got buffer %p\n", packet
->reportBuffer
);
558 irp
->IoStatus
.Information
= 3;
559 ret
= STATUS_SUCCESS
;
563 case IOCTL_HID_GET_FEATURE
:
565 HID_XFER_PACKET
*packet
= irp
->UserBuffer
;
566 ULONG expected_size
= 17;
567 ok(!in_size
, "got input size %u\n", in_size
);
568 ok(out_size
== sizeof(*packet
), "got output size %u\n", out_size
);
570 ok(packet
->reportId
== report_id
, "got id %u\n", packet
->reportId
);
571 ok(packet
->reportBufferLen
>= expected_size
, "got len %u\n", packet
->reportBufferLen
);
572 ok(!!packet
->reportBuffer
, "got buffer %p\n", packet
->reportBuffer
);
574 memset(packet
->reportBuffer
, 0xa5, 3);
575 if (report_id
) ((char *)packet
->reportBuffer
)[0] = report_id
;
576 irp
->IoStatus
.Information
= 3;
577 ret
= STATUS_SUCCESS
;
581 case IOCTL_HID_SET_FEATURE
:
583 HID_XFER_PACKET
*packet
= irp
->UserBuffer
;
584 ULONG expected_size
= 17;
585 ok(in_size
== sizeof(*packet
), "got input size %u\n", in_size
);
586 ok(!out_size
, "got output size %u\n", out_size
);
588 ok(packet
->reportId
== report_id
, "got id %u\n", packet
->reportId
);
589 ok(packet
->reportBufferLen
>= expected_size
, "got len %u\n", packet
->reportBufferLen
);
590 ok(!!packet
->reportBuffer
, "got buffer %p\n", packet
->reportBuffer
);
592 irp
->IoStatus
.Information
= 3;
593 ret
= STATUS_SUCCESS
;
597 case IOCTL_HID_GET_STRING
:
598 ok(!in_size
, "got input size %u\n", in_size
);
599 ok(out_size
== 128, "got output size %u\n", out_size
);
601 memcpy(irp
->UserBuffer
, L
"Wine Test", sizeof(L
"Wine Test"));
602 irp
->IoStatus
.Information
= sizeof(L
"Wine Test");
603 ret
= STATUS_SUCCESS
;
607 ok(0, "unexpected ioctl %#x\n", code
);
608 ret
= STATUS_NOT_IMPLEMENTED
;
611 if (ret
!= STATUS_PENDING
)
613 irp
->IoStatus
.Status
= ret
;
614 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
619 static NTSTATUS WINAPI
driver_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
621 HID_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
623 ok(0, "unexpected call\n");
624 IoSkipCurrentIrpStackLocation(irp
);
625 return IoCallDriver(ext
->NextDeviceObject
, irp
);
628 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*fdo
)
630 HID_DEVICE_EXTENSION
*ext
= fdo
->DeviceExtension
;
633 /* We should be given the FDO, not the PDO. */
634 ok(!!ext
->PhysicalDeviceObject
, "expected non-NULL pdo\n");
635 ok(ext
->NextDeviceObject
== ext
->PhysicalDeviceObject
, "got pdo %p, next %p\n",
636 ext
->PhysicalDeviceObject
, ext
->NextDeviceObject
);
637 todo_wine
ok(ext
->NextDeviceObject
->AttachedDevice
== fdo
, "wrong attached device\n");
639 ret
= IoRegisterDeviceInterface(ext
->PhysicalDeviceObject
, &control_class
, NULL
, &control_symlink
);
640 ok(!ret
, "got %#x\n", ret
);
642 fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
643 return STATUS_SUCCESS
;
646 static NTSTATUS WINAPI
driver_create(DEVICE_OBJECT
*device
, IRP
*irp
)
648 ok(0, "unexpected call\n");
649 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
650 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
651 return STATUS_SUCCESS
;
654 static NTSTATUS WINAPI
driver_close(DEVICE_OBJECT
*device
, IRP
*irp
)
656 ok(0, "unexpected call\n");
657 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
658 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
659 return STATUS_SUCCESS
;
662 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
667 NTSTATUS WINAPI
DriverEntry(DRIVER_OBJECT
*driver
, UNICODE_STRING
*registry
)
669 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
670 char buffer
[offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
) + sizeof(DWORD
)];
671 HID_MINIDRIVER_REGISTRATION params
=
673 .Revision
= HID_REVISION
,
674 .DriverObject
= driver
,
675 .DeviceExtensionSize
= sizeof(struct hid_device
),
676 .RegistryPath
= registry
,
678 UNICODE_STRING name_str
;
679 OBJECT_ATTRIBUTES attr
;
684 if ((ret
= winetest_init()))
687 InitializeObjectAttributes(&attr
, registry
, 0, NULL
, NULL
);
688 ret
= ZwOpenKey(&hkey
, KEY_ALL_ACCESS
, &attr
);
689 ok(!ret
, "ZwOpenKey returned %#x\n", ret
);
691 RtlInitUnicodeString(&name_str
, L
"ReportID");
692 size
= info_size
+ sizeof(report_id
);
693 ret
= ZwQueryValueKey(hkey
, &name_str
, KeyValuePartialInformation
, buffer
, size
, &size
);
694 ok(!ret
, "ZwQueryValueKey returned %#x\n", ret
);
695 memcpy(&report_id
, buffer
+ info_size
, size
- info_size
);
697 RtlInitUnicodeString(&name_str
, L
"PolledMode");
698 size
= info_size
+ sizeof(polled
);
699 ret
= ZwQueryValueKey(hkey
, &name_str
, KeyValuePartialInformation
, buffer
, size
, &size
);
700 ok(!ret
, "ZwQueryValueKey returned %#x\n", ret
);
701 memcpy(&polled
, buffer
+ info_size
, size
- info_size
);
702 params
.DevicesArePolled
= polled
;
704 driver
->DriverExtension
->AddDevice
= driver_add_device
;
705 driver
->DriverUnload
= driver_unload
;
706 driver
->MajorFunction
[IRP_MJ_PNP
] = driver_pnp
;
707 driver
->MajorFunction
[IRP_MJ_POWER
] = driver_power
;
708 driver
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = driver_ioctl
;
709 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = driver_internal_ioctl
;
710 driver
->MajorFunction
[IRP_MJ_CREATE
] = driver_create
;
711 driver
->MajorFunction
[IRP_MJ_CLOSE
] = driver_close
;
713 ret
= HidRegisterMinidriver(¶ms
);
714 ok(!ret
, "got %#x\n", ret
);
716 return STATUS_SUCCESS
;