hidclass.sys: Adjust buffer length according to report IDs usage.
[wine.git] / dlls / ntoskrnl.exe / tests / driver_hid.c
blob831b08c5c97a743d93d3dcd2079a7544b7bb69c0
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 todo_wine_if(packet->reportId == 0x5a)
536 ok(packet->reportId == report_id, "got id %u\n", packet->reportId);
537 ok(packet->reportBufferLen >= expected_size, "got len %u\n", packet->reportBufferLen);
538 ok(!!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer);
540 memset(packet->reportBuffer, 0xa5, 3);
541 if (report_id) ((char *)packet->reportBuffer)[0] = report_id;
542 ((char *)packet->reportBuffer)[1] = seq++;
543 irp->IoStatus.Information = 3;
544 ret = STATUS_SUCCESS;
545 break;
548 case IOCTL_HID_SET_OUTPUT_REPORT:
550 HID_XFER_PACKET *packet = irp->UserBuffer;
551 ULONG expected_size = 2;
552 todo_wine ok(in_size == sizeof(*packet), "got input size %u\n", in_size);
553 todo_wine ok(!out_size, "got output size %u\n", out_size);
555 todo_wine_if(packet->reportId != report_id)
556 ok(packet->reportId == report_id, "got id %u\n", packet->reportId);
557 todo_wine_if(packet->reportBufferLen == 0 || packet->reportBufferLen == 1)
558 ok(packet->reportBufferLen >= expected_size, "got len %u\n", packet->reportBufferLen);
559 ok(!!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer);
561 irp->IoStatus.Information = 3;
562 ret = STATUS_SUCCESS;
563 break;
566 case IOCTL_HID_GET_FEATURE:
568 HID_XFER_PACKET *packet = irp->UserBuffer;
569 ULONG expected_size = 17;
570 ok(!in_size, "got input size %u\n", in_size);
571 ok(out_size == sizeof(*packet), "got output size %u\n", out_size);
573 todo_wine_if(packet->reportId == 0x5a || packet->reportId == 0xa5)
574 ok(packet->reportId == report_id, "got id %u\n", packet->reportId);
575 todo_wine_if(packet->reportBufferLen == 16)
576 ok(packet->reportBufferLen >= expected_size, "got len %u\n", packet->reportBufferLen);
577 ok(!!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer);
579 memset(packet->reportBuffer, 0xa5, 3);
580 if (report_id) ((char *)packet->reportBuffer)[0] = report_id;
581 irp->IoStatus.Information = 3;
582 ret = STATUS_SUCCESS;
583 break;
586 case IOCTL_HID_SET_FEATURE:
588 HID_XFER_PACKET *packet = irp->UserBuffer;
589 ULONG expected_size = 17;
590 todo_wine ok(in_size == sizeof(*packet), "got input size %u\n", in_size);
591 todo_wine ok(!out_size, "got output size %u\n", out_size);
593 todo_wine_if(packet->reportId != report_id)
594 ok(packet->reportId == report_id, "got id %u\n", packet->reportId);
595 todo_wine_if(packet->reportBufferLen == 0 || packet->reportBufferLen == 16)
596 ok(packet->reportBufferLen >= expected_size, "got len %u\n", packet->reportBufferLen);
597 ok(!!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer);
599 irp->IoStatus.Information = 3;
600 ret = STATUS_SUCCESS;
601 break;
604 case IOCTL_HID_GET_STRING:
605 ok(!in_size, "got input size %u\n", in_size);
606 ok(out_size == 128, "got output size %u\n", out_size);
608 memcpy(irp->UserBuffer, L"Wine Test", sizeof(L"Wine Test"));
609 irp->IoStatus.Information = sizeof(L"Wine Test");
610 ret = STATUS_SUCCESS;
611 break;
613 default:
614 ok(0, "unexpected ioctl %#x\n", code);
615 ret = STATUS_NOT_IMPLEMENTED;
618 if (ret != STATUS_PENDING)
620 irp->IoStatus.Status = ret;
621 IoCompleteRequest(irp, IO_NO_INCREMENT);
623 return ret;
626 static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp)
628 HID_DEVICE_EXTENSION *ext = device->DeviceExtension;
630 ok(0, "unexpected call\n");
631 IoSkipCurrentIrpStackLocation(irp);
632 return IoCallDriver(ext->NextDeviceObject, irp);
635 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *fdo)
637 HID_DEVICE_EXTENSION *ext = fdo->DeviceExtension;
638 NTSTATUS ret;
640 /* We should be given the FDO, not the PDO. */
641 ok(!!ext->PhysicalDeviceObject, "expected non-NULL pdo\n");
642 ok(ext->NextDeviceObject == ext->PhysicalDeviceObject, "got pdo %p, next %p\n",
643 ext->PhysicalDeviceObject, ext->NextDeviceObject);
644 todo_wine ok(ext->NextDeviceObject->AttachedDevice == fdo, "wrong attached device\n");
646 ret = IoRegisterDeviceInterface(ext->PhysicalDeviceObject, &control_class, NULL, &control_symlink);
647 ok(!ret, "got %#x\n", ret);
649 fdo->Flags &= ~DO_DEVICE_INITIALIZING;
650 return STATUS_SUCCESS;
653 static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp)
655 ok(0, "unexpected call\n");
656 irp->IoStatus.Status = STATUS_SUCCESS;
657 IoCompleteRequest(irp, IO_NO_INCREMENT);
658 return STATUS_SUCCESS;
661 static NTSTATUS WINAPI driver_close(DEVICE_OBJECT *device, IRP *irp)
663 ok(0, "unexpected call\n");
664 irp->IoStatus.Status = STATUS_SUCCESS;
665 IoCompleteRequest(irp, IO_NO_INCREMENT);
666 return STATUS_SUCCESS;
669 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
671 winetest_cleanup();
674 NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *registry)
676 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
677 char buffer[offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ) + sizeof(DWORD)];
678 HID_MINIDRIVER_REGISTRATION params =
680 .Revision = HID_REVISION,
681 .DriverObject = driver,
682 .DeviceExtensionSize = sizeof(struct hid_device),
683 .RegistryPath = registry,
685 UNICODE_STRING name_str;
686 OBJECT_ATTRIBUTES attr;
687 NTSTATUS ret;
688 HANDLE hkey;
689 DWORD size;
691 if ((ret = winetest_init()))
692 return ret;
694 InitializeObjectAttributes(&attr, registry, 0, NULL, NULL);
695 ret = ZwOpenKey(&hkey, KEY_ALL_ACCESS, &attr);
696 ok(!ret, "ZwOpenKey returned %#x\n", ret);
698 RtlInitUnicodeString(&name_str, L"ReportID");
699 size = info_size + sizeof(report_id);
700 ret = ZwQueryValueKey(hkey, &name_str, KeyValuePartialInformation, buffer, size, &size);
701 ok(!ret, "ZwQueryValueKey returned %#x\n", ret);
702 memcpy(&report_id, buffer + info_size, size - info_size);
704 RtlInitUnicodeString(&name_str, L"PolledMode");
705 size = info_size + sizeof(polled);
706 ret = ZwQueryValueKey(hkey, &name_str, KeyValuePartialInformation, buffer, size, &size);
707 ok(!ret, "ZwQueryValueKey returned %#x\n", ret);
708 memcpy(&polled, buffer + info_size, size - info_size);
709 params.DevicesArePolled = polled;
711 driver->DriverExtension->AddDevice = driver_add_device;
712 driver->DriverUnload = driver_unload;
713 driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
714 driver->MajorFunction[IRP_MJ_POWER] = driver_power;
715 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl;
716 driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl;
717 driver->MajorFunction[IRP_MJ_CREATE] = driver_create;
718 driver->MajorFunction[IRP_MJ_CLOSE] = driver_close;
720 ret = HidRegisterMinidriver(&params);
721 ok(!ret, "got %#x\n", ret);
723 return STATUS_SUCCESS;