hidclass.sys: Validate report IDs in hid_device_xfer_report.
[wine.git] / dlls / ntoskrnl.exe / tests / driver_hid.c
blob83f546aa972d9cda7fee8a1d8b1f365f6e88448b
1 /*
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
21 #include <stdarg.h>
22 #include <stdio.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #include "winioctl.h"
30 #include "ddk/wdm.h"
31 #include "hidusage.h"
32 #include "ddk/hidpi.h"
33 #include "ddk/hidport.h"
35 #include "wine/list.h"
37 #include "driver.h"
38 #include "utils.h"
40 static UNICODE_STRING control_symlink;
42 static unsigned int got_start_device;
43 static DWORD report_id;
44 static DWORD polled;
46 struct irp_queue
48 KSPIN_LOCK lock;
49 LIST_ENTRY list;
52 static IRP *irp_queue_pop(struct irp_queue *queue)
54 KIRQL irql;
55 IRP *irp;
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);
62 return irp;
65 static void irp_queue_push(struct irp_queue *queue, IRP *irp)
67 KIRQL irql;
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)
76 IRP *irp;
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);
91 struct hid_device
93 BOOL removed;
94 KSPIN_LOCK lock;
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;
103 KIRQL irql;
105 if (winetest_debug > 1) trace("pnp %#x\n", stack->MinorFunction);
107 switch (stack->MinorFunction)
109 case IRP_MN_START_DEVICE:
110 ++got_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;
116 break;
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;
125 break;
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;
132 break;
134 case IRP_MN_STOP_DEVICE:
135 irp->IoStatus.Status = STATUS_SUCCESS;
136 break;
138 case IRP_MN_REMOVE_DEVICE:
139 irp_queue_clear(&impl->irp_queue);
140 IoSetDeviceInterfaceState(&control_symlink, FALSE);
141 irp->IoStatus.Status = STATUS_SUCCESS;
142 break;
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),
180 REPORT_SIZE(1, 8),
181 REPORT_COUNT(1, 2),
182 INPUT(1, Data|Var|Abs),
184 USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON),
185 USAGE_MINIMUM(1, 1),
186 USAGE_MAXIMUM(1, 8),
187 LOGICAL_MINIMUM(1, 0),
188 LOGICAL_MAXIMUM(1, 1),
189 REPORT_COUNT(1, 8),
190 REPORT_SIZE(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),
197 REPORT_COUNT(1, 8),
198 REPORT_SIZE(1, 1),
199 INPUT(1, Cnst|Var|Abs),
200 REPORT_COUNT(1, 8),
201 REPORT_SIZE(1, 1),
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),
209 REPORT_COUNT(1, 2),
210 REPORT_SIZE(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 */
214 USAGE(1, 0x20),
215 LOGICAL_MINIMUM(1, 0),
216 LOGICAL_MAXIMUM(1, 1),
217 REPORT_COUNT(1, 8),
218 REPORT_SIZE(1, 1),
219 INPUT(1, Data|Var|Abs),
220 USAGE_MINIMUM(1, 0x21),
221 USAGE_MAXIMUM(1, 0x22),
222 REPORT_COUNT(1, 2),
223 REPORT_SIZE(1, 0),
224 INPUT(1, Data|Var|Abs),
225 USAGE(1, 0x23),
226 REPORT_COUNT(1, 0),
227 REPORT_SIZE(1, 1),
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),
234 REPORT_SIZE(1, 4),
235 REPORT_COUNT(1, 2),
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),
244 REPORT_SIZE(1, 32),
245 REPORT_COUNT(1, 1),
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),
253 REPORT_SIZE(1, 32),
254 REPORT_COUNT(1, 1),
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),
263 REPORT_SIZE(1, 32),
264 REPORT_COUNT(1, 1),
265 INPUT(1, Data|Var|Abs),
266 END_COLLECTION,
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),
273 USAGE_MINIMUM(1, 9),
274 USAGE_MAXIMUM(1, 10),
275 LOGICAL_MINIMUM(1, 0),
276 LOGICAL_MAXIMUM(1, 1),
277 REPORT_COUNT(1, 8),
278 REPORT_SIZE(1, 1),
279 INPUT(1, Data|Var|Abs),
280 END_COLLECTION,
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),
287 USAGE(1, 1),
288 USAGE(1, 2),
289 USAGE(1, 3),
290 USAGE(1, 4),
291 USAGE(1, 5),
292 USAGE(1, 6),
293 USAGE(1, 7),
294 USAGE(1, 8),
295 LOGICAL_MINIMUM(1, 0),
296 LOGICAL_MAXIMUM(1, 1),
297 PHYSICAL_MINIMUM(1, 0),
298 PHYSICAL_MAXIMUM(1, 1),
299 REPORT_COUNT(1, 8),
300 REPORT_SIZE(1, 1),
301 INPUT(1, Data|Var|Abs),
302 END_COLLECTION,
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),
317 REPORT_COUNT(1, 2),
318 REPORT_SIZE(1, 16),
319 FEATURE(1, Data|Var|Abs|Null),
320 END_COLLECTION,
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),
330 REPORT_COUNT(1, 2),
331 REPORT_SIZE(1, 16),
332 FEATURE(1, Data|Var|Abs|Null),
333 END_COLLECTION,
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),
343 REPORT_SIZE(1, 32),
344 REPORT_COUNT(1, 2),
345 FEATURE(1, Data|Var|Abs),
346 /* reset global items */
347 UNIT(1, 0), /* None */
348 UNIT_EXPONENT(1, 0),
349 END_COLLECTION,
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),
356 USAGE_MINIMUM(1, 9),
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),
362 REPORT_COUNT(1, 8),
363 REPORT_SIZE(1, 1),
364 FEATURE(1, Data|Var|Abs),
365 END_COLLECTION,
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),
372 REPORT_COUNT(1, 8),
373 REPORT_SIZE(1, 1),
374 OUTPUT(1, Cnst|Var|Abs),
375 END_COLLECTION,
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),
382 REPORT_COUNT(1, 8),
383 REPORT_SIZE(1, 1),
384 OUTPUT(1, Cnst|Var|Abs),
385 END_COLLECTION,
386 END_COLLECTION,
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;
397 static BYTE seq = 0;
398 NTSTATUS ret;
399 BOOL removed;
400 KIRQL irql;
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);
412 if (removed)
414 irp->IoStatus.Status = STATUS_DELETE_PENDING;
415 IoCompleteRequest(irp, IO_NO_INCREMENT);
416 return STATUS_DELETE_PENDING;
419 switch (code)
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;
435 desc->bCountry = 0;
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;
442 break;
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;
455 break;
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;
475 break;
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);
484 if (polled)
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;
492 else
494 IoMarkIrpPending(irp);
495 irp_queue_push(&impl->irp_queue, irp);
496 ret = STATUS_PENDING;
498 break;
501 case IOCTL_HID_WRITE_REPORT:
503 HID_XFER_PACKET *packet = irp->UserBuffer;
504 ULONG expected_size = 2;
506 todo_wine
507 ok(in_size == sizeof(*packet), "got input size %u\n", in_size);
508 todo_wine
509 ok(!out_size, "got output size %u\n", out_size);
510 ok(packet->reportBufferLen >= expected_size, "got report size %u\n", packet->reportBufferLen);
512 if (report_id)
514 todo_wine_if(packet->reportBuffer[0] == 0xa5)
515 ok(packet->reportBuffer[0] == report_id, "got report id %x\n", packet->reportBuffer[0]);
517 else
519 todo_wine
520 ok(packet->reportBuffer[0] == 0xcd, "got first byte %x\n", packet->reportBuffer[0]);
523 irp->IoStatus.Information = 3;
524 ret = STATUS_SUCCESS;
525 break;
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;
544 break;
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;
560 break;
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;
578 break;
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;
594 break;
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;
604 break;
606 default:
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);
616 return ret;
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;
631 NTSTATUS ret;
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)
664 winetest_cleanup();
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;
680 NTSTATUS ret;
681 HANDLE hkey;
682 DWORD size;
684 if ((ret = winetest_init()))
685 return ret;
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(&params);
714 ok(!ret, "got %#x\n", ret);
716 return STATUS_SUCCESS;