dinput/tests: Wait for the expected report to actually be pending.
[wine.git] / dlls / dinput / tests / driver_bus.c
blob6a1994e509c2bded6ecf8c37750859efc1475d1d
1 /*
2 * Plug and Play test driver
4 * Copyright 2022 RĂ©mi Bernon for CodeWeavers
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 "ddk/hidsdi.h"
32 #include "ddk/hidport.h"
34 #include "wine/list.h"
36 #include "initguid.h"
37 #include "driver_hid.h"
39 typedef ULONG PNP_DEVICE_STATE;
40 #define PNP_DEVICE_REMOVED 8
42 #define check_buffer( a, b ) check_buffer_( __LINE__, a, b )
43 static void check_buffer_( int line, HID_XFER_PACKET *packet, struct hid_expect *expect )
45 ULONG match_len, i;
47 match_len = RtlCompareMemory( packet->reportBuffer, expect->report_buf, expect->report_len );
48 ok( match_len == expect->report_len, "unexpected data:\n" );
49 if (match_len == expect->report_len) return;
51 for (i = 0; i < packet->reportBufferLen;)
53 char buffer[256], *buf = buffer;
54 buf += sprintf( buf, "%08lx ", i );
55 do buf += sprintf( buf, " %02x", packet->reportBuffer[i] );
56 while (++i % 16 && i < packet->reportBufferLen);
57 ok( 0, " %s\n", buffer );
61 #define EXPECT_QUEUE_BUFFER_SIZE (64 * sizeof(struct hid_expect))
63 struct expect_queue
65 KSPIN_LOCK lock;
66 struct hid_expect *pos;
67 struct hid_expect *end;
68 struct hid_expect spurious;
69 struct hid_expect *buffer;
70 IRP *pending_wait;
71 char context[64];
74 static void expect_queue_init( struct expect_queue *queue )
76 KeInitializeSpinLock( &queue->lock );
77 queue->buffer = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE );
78 RtlSecureZeroMemory( queue->buffer, EXPECT_QUEUE_BUFFER_SIZE );
79 queue->pos = queue->buffer;
80 queue->end = queue->buffer;
83 static void expect_queue_cleanup( struct expect_queue *queue )
85 KIRQL irql;
86 IRP *irp;
88 KeAcquireSpinLock( &queue->lock, &irql );
89 if ((irp = queue->pending_wait))
91 queue->pending_wait = NULL;
92 if (!IoSetCancelRoutine( irp, NULL )) irp = NULL;
94 KeReleaseSpinLock( &queue->lock, irql );
96 if (irp)
98 irp->IoStatus.Status = STATUS_DELETE_PENDING;
99 IoCompleteRequest( irp, IO_NO_INCREMENT );
102 ExFreePool( queue->buffer );
105 static void expect_queue_reset( struct expect_queue *queue, void *buffer, unsigned int size )
107 struct hid_expect *missing, *missing_end, *tmp;
108 char context[64];
109 KIRQL irql;
111 missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE );
112 RtlSecureZeroMemory( missing, EXPECT_QUEUE_BUFFER_SIZE );
113 missing_end = missing;
115 KeAcquireSpinLock( &queue->lock, &irql );
116 tmp = queue->pos;
117 while (tmp < queue->end) *missing_end++ = *tmp++;
119 queue->pos = queue->buffer;
120 queue->end = queue->buffer;
122 if (size) memcpy( queue->end, buffer, size );
123 queue->end = queue->end + size / sizeof(struct hid_expect);
124 memcpy( context, queue->context, sizeof(context) );
125 KeReleaseSpinLock( &queue->lock, irql );
127 tmp = missing;
128 while (tmp != missing_end)
130 winetest_push_context( "%s expect[%Id]", context, tmp - missing );
131 if (tmp->broken)
133 todo_wine_if( tmp->todo )
134 win_skip( "broken (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len );
136 else
138 todo_wine_if( tmp->todo )
139 ok( tmp->wine_only, "missing (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len );
141 winetest_pop_context();
142 tmp++;
145 ExFreePool( missing );
148 static void WINAPI wait_cancel_routine( DEVICE_OBJECT *device, IRP *irp )
150 struct expect_queue *queue = irp->Tail.Overlay.DriverContext[0];
151 KIRQL irql;
153 IoReleaseCancelSpinLock( irp->CancelIrql );
155 KeAcquireSpinLock( &queue->lock, &irql );
156 queue->pending_wait = NULL;
157 KeReleaseSpinLock( &queue->lock, irql );
159 irp->IoStatus.Information = 0;
160 irp->IoStatus.Status = STATUS_CANCELLED;
161 IoCompleteRequest( irp, IO_NO_INCREMENT );
164 static NTSTATUS expect_queue_add_pending_locked( struct expect_queue *queue, IRP *irp )
166 if (queue->pending_wait) return STATUS_INVALID_PARAMETER;
168 IoSetCancelRoutine( irp, wait_cancel_routine );
169 if (irp->Cancel && !IoSetCancelRoutine( irp, NULL ))
170 return STATUS_CANCELLED;
172 irp->Tail.Overlay.DriverContext[0] = queue;
173 IoMarkIrpPending( irp );
174 queue->pending_wait = irp;
176 return STATUS_PENDING;
179 static NTSTATUS expect_queue_add_pending( struct expect_queue *queue, IRP *irp )
181 NTSTATUS status;
182 KIRQL irql;
184 KeAcquireSpinLock( &queue->lock, &irql );
185 status = expect_queue_add_pending_locked( queue, irp );
186 KeReleaseSpinLock( &queue->lock, irql );
188 return status;
191 /* complete an expect report previously marked as pending, or wait for one and then for the queue to empty */
192 static NTSTATUS expect_queue_wait_pending( struct expect_queue *queue, IRP *irp )
194 NTSTATUS status;
195 IRP *pending;
196 KIRQL irql;
198 KeAcquireSpinLock( &queue->lock, &irql );
199 if ((pending = queue->pending_wait))
201 queue->pending_wait = NULL;
202 if (!IoSetCancelRoutine( pending, NULL )) pending = NULL;
205 if (pending && queue->pos == queue->end) status = STATUS_SUCCESS;
206 else status = expect_queue_add_pending_locked( queue, irp );
207 KeReleaseSpinLock( &queue->lock, irql );
209 if (pending)
211 pending->IoStatus.Status = STATUS_SUCCESS;
212 IoCompleteRequest( pending, IO_NO_INCREMENT );
215 return status;
218 /* wait for the expect queue to empty */
219 static NTSTATUS expect_queue_wait( struct expect_queue *queue, IRP *irp )
221 NTSTATUS status;
222 KIRQL irql;
224 irp->IoStatus.Information = 0;
225 KeAcquireSpinLock( &queue->lock, &irql );
226 if (queue->pos == queue->end) status = STATUS_SUCCESS;
227 else status = expect_queue_add_pending_locked( queue, irp );
228 KeReleaseSpinLock( &queue->lock, irql );
230 return status;
233 static void expect_queue_next( struct expect_queue *queue, ULONG code, HID_XFER_PACKET *packet, LONG *index,
234 struct hid_expect *expect, BOOL compare_buf, char *context, ULONG context_size )
236 struct hid_expect *missing, *missing_end, *tmp;
237 ULONG len = packet->reportBufferLen;
238 BYTE *buf = packet->reportBuffer;
239 BYTE id = packet->reportId;
240 IRP *irp = NULL;
241 KIRQL irql;
243 missing = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE );
244 RtlSecureZeroMemory( missing, EXPECT_QUEUE_BUFFER_SIZE );
245 missing_end = missing;
247 KeAcquireSpinLock( &queue->lock, &irql );
248 tmp = queue->pos;
249 while (tmp < queue->end)
251 if (running_under_wine && !tmp->todo) break;
252 if (!running_under_wine && !tmp->broken && !tmp->wine_only) break;
253 if (tmp->code == code && tmp->report_id == id && tmp->report_len == len &&
254 (!compare_buf || RtlCompareMemory( tmp->report_buf, buf, len ) == len))
255 break;
256 *missing_end++ = *tmp++;
258 *index = tmp - queue->buffer;
259 if (tmp < queue->end) queue->pos = tmp + 1;
260 else tmp = &queue->spurious;
261 *expect = *tmp;
263 while (queue->pos < queue->end)
265 if (running_under_wine || !queue->pos->wine_only) break;
266 queue->pos++;
269 if ((irp = queue->pending_wait))
271 /* don't mark the IRP as pending if someone's already waiting */
272 if (expect->ret_status == STATUS_PENDING) expect->ret_status = STATUS_SUCCESS;
274 /* complete the pending wait IRP if the queue is now empty */
275 if (queue->pos != queue->end) irp = NULL;
276 else
278 queue->pending_wait = NULL;
279 if (!IoSetCancelRoutine( irp, NULL )) irp = NULL;
283 memcpy( context, queue->context, context_size );
284 KeReleaseSpinLock( &queue->lock, irql );
286 if (irp)
288 irp->IoStatus.Status = STATUS_SUCCESS;
289 IoCompleteRequest( irp, IO_NO_INCREMENT );
292 ok( tmp != &queue->spurious, "%s got spurious packet\n", context );
294 winetest_push_context( "%s expect[%Id]", context, tmp - queue->buffer );
295 todo_wine_if( tmp->todo )
296 ok( !tmp->wine_only, "found code %#lx id %u len %u\n", tmp->code, tmp->report_id, tmp->report_len );
297 winetest_pop_context();
299 tmp = missing;
300 while (tmp != missing_end)
302 winetest_push_context( "%s expect[%Id]", context, tmp - missing );
303 if (tmp->broken)
305 todo_wine_if( tmp->todo )
306 win_skip( "broken (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len );
308 else
310 todo_wine_if( tmp->todo )
311 ok( tmp->wine_only, "missing (code %#lx id %u len %u)\n", tmp->code, tmp->report_id, tmp->report_len );
313 winetest_pop_context();
314 tmp++;
317 ExFreePool( missing );
320 struct irp_queue
322 KSPIN_LOCK lock;
323 LIST_ENTRY list;
326 static IRP *irp_queue_pop( struct irp_queue *queue )
328 KIRQL irql;
329 IRP *irp;
331 KeAcquireSpinLock( &queue->lock, &irql );
332 if (IsListEmpty( &queue->list )) irp = NULL;
333 else irp = CONTAINING_RECORD( RemoveHeadList( &queue->list ), IRP, Tail.Overlay.ListEntry );
334 KeReleaseSpinLock( &queue->lock, irql );
336 return irp;
339 static void irp_queue_push( struct irp_queue *queue, IRP *irp )
341 KIRQL irql;
343 KeAcquireSpinLock( &queue->lock, &irql );
344 InsertTailList( &queue->list, &irp->Tail.Overlay.ListEntry );
345 KeReleaseSpinLock( &queue->lock, irql );
348 static void irp_queue_clear( struct irp_queue *queue )
350 IRP *irp;
352 while ((irp = irp_queue_pop( queue )))
354 irp->IoStatus.Status = STATUS_DELETE_PENDING;
355 IoCompleteRequest( irp, IO_NO_INCREMENT );
359 static void irp_queue_init( struct irp_queue *queue )
361 KeInitializeSpinLock( &queue->lock );
362 InitializeListHead( &queue->list );
365 struct input_queue
367 KSPIN_LOCK lock;
368 BOOL is_polled;
369 struct hid_expect *pos;
370 struct hid_expect *end;
371 struct hid_expect *buffer;
372 struct irp_queue pending;
375 static void input_queue_init( struct input_queue *queue, BOOL is_polled )
377 KeInitializeSpinLock( &queue->lock );
378 queue->is_polled = is_polled;
379 queue->buffer = ExAllocatePool( PagedPool, EXPECT_QUEUE_BUFFER_SIZE );
380 RtlSecureZeroMemory( queue->buffer, EXPECT_QUEUE_BUFFER_SIZE );
381 queue->pos = queue->buffer;
382 queue->end = queue->buffer;
383 irp_queue_init( &queue->pending );
386 static void input_queue_cleanup( struct input_queue *queue )
388 ExFreePool( queue->buffer );
391 static BOOL input_queue_read_locked( struct input_queue *queue, IRP *irp )
393 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
394 ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength;
395 struct hid_expect *tmp = queue->pos;
397 if (tmp >= queue->end) return FALSE;
398 if (tmp->ret_length) out_size = tmp->ret_length;
400 memcpy( irp->UserBuffer, tmp->report_buf, out_size );
401 irp->IoStatus.Information = out_size;
402 irp->IoStatus.Status = tmp->ret_status;
403 if (tmp < queue->end) queue->pos = tmp + 1;
405 /* loop on the queue data in polled mode */
406 if (queue->is_polled && queue->pos == queue->end) queue->pos = queue->buffer;
407 return TRUE;
410 static NTSTATUS input_queue_read( struct input_queue *queue, IRP *irp )
412 NTSTATUS status;
413 KIRQL irql;
415 KeAcquireSpinLock( &queue->lock, &irql );
416 if (input_queue_read_locked( queue, irp )) status = STATUS_SUCCESS;
417 else
419 IoMarkIrpPending( irp );
420 irp_queue_push( &queue->pending, irp );
421 status = STATUS_PENDING;
423 KeReleaseSpinLock( &queue->lock, irql );
425 return status;
428 static void input_queue_reset( struct input_queue *queue, void *in_buf, ULONG in_size )
430 struct irp_queue completed;
431 ULONG remaining;
432 KIRQL irql;
433 IRP *irp;
435 irp_queue_init( &completed );
437 KeAcquireSpinLock( &queue->lock, &irql );
438 remaining = queue->end - queue->pos;
439 queue->pos = queue->buffer;
440 queue->end = queue->buffer;
441 memcpy( queue->end, in_buf, in_size );
442 queue->end += in_size / sizeof(struct hid_expect);
444 while (!queue->is_polled && queue->pos < queue->end && (irp = irp_queue_pop( &queue->pending )))
446 input_queue_read_locked( queue, irp );
447 irp_queue_push( &completed, irp );
449 KeReleaseSpinLock( &queue->lock, irql );
451 if (!queue->is_polled) ok( !remaining, "unread input\n" );
453 while ((irp = irp_queue_pop( &completed ))) IoCompleteRequest( irp, IO_NO_INCREMENT );
456 struct device
458 KSPIN_LOCK lock;
459 PNP_DEVICE_STATE state;
460 BOOL is_phys;
463 static inline struct device *impl_from_DEVICE_OBJECT( DEVICE_OBJECT *device )
465 return (struct device *)device->DeviceExtension;
468 struct phys_device
470 struct device base;
471 struct func_device *fdo; /* parent FDO */
473 WCHAR instance_id[MAX_PATH];
474 WCHAR device_id[MAX_PATH];
475 IRP *pending_remove;
477 BOOL use_report_id;
478 DWORD report_descriptor_len;
479 char report_descriptor_buf[MAX_HID_DESCRIPTOR_LEN];
481 HIDP_CAPS caps;
482 HID_DEVICE_ATTRIBUTES attributes;
483 struct expect_queue expect_queue;
484 struct input_queue input_queue;
487 static inline struct phys_device *pdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device )
489 struct device *impl = impl_from_DEVICE_OBJECT( device );
490 return CONTAINING_RECORD( impl, struct phys_device, base );
493 struct func_device
495 struct device base;
496 DEVICE_OBJECT *pdo; /* lower PDO */
497 UNICODE_STRING control_iface;
498 char devices_buffer[offsetof( DEVICE_RELATIONS, Objects[128] )];
499 DEVICE_RELATIONS *devices;
502 static inline struct func_device *fdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device )
504 struct device *impl = impl_from_DEVICE_OBJECT( device );
505 if (impl->is_phys) return CONTAINING_RECORD( impl, struct phys_device, base )->fdo;
506 return CONTAINING_RECORD( impl, struct func_device, base );
509 #ifdef __ASM_USE_FASTCALL_WRAPPER
510 extern void *WINAPI wrap_fastcall_func1( void *func, const void *a );
511 __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8,
512 "popl %ecx\n\t"
513 "popl %eax\n\t"
514 "xchgl (%esp),%ecx\n\t"
515 "jmp *%eax" );
516 #define call_fastcall_func1( func, a ) wrap_fastcall_func1( func, a )
517 #else
518 #define call_fastcall_func1( func, a ) func( a )
519 #endif
521 static NTSTATUS remove_child_device( struct func_device *impl, DEVICE_OBJECT *device )
523 NTSTATUS status = STATUS_SUCCESS;
524 KIRQL irql;
525 ULONG i;
527 KeAcquireSpinLock( &impl->base.lock, &irql );
528 for (i = 0; i < impl->devices->Count; ++i)
529 if (impl->devices->Objects[i] == device) break;
530 if (i == impl->devices->Count) status = STATUS_NOT_FOUND;
531 else impl->devices->Objects[i] = impl->devices->Objects[impl->devices->Count--];
532 KeReleaseSpinLock( &impl->base.lock, irql );
534 return status;
537 static NTSTATUS append_child_device( struct func_device *impl, DEVICE_OBJECT *device )
539 NTSTATUS status;
540 KIRQL irql;
542 KeAcquireSpinLock( &impl->base.lock, &irql );
543 if (offsetof( DEVICE_RELATIONS, Objects[impl->devices->Count + 1] ) > sizeof(impl->devices_buffer))
544 status = STATUS_NO_MEMORY;
545 else
547 impl->devices->Objects[impl->devices->Count++] = device;
548 status = STATUS_SUCCESS;
550 KeReleaseSpinLock( &impl->base.lock, irql );
552 return status;
555 static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct hid_device_desc *desc )
557 DEVICE_OBJECT *device = NULL, **devices;
558 WCHAR device_id[MAX_PATH];
559 KIRQL irql;
560 ULONG i;
562 swprintf( device_id, MAX_PATH, L"WINETEST\\VID_%04X&PID_%04X", desc->attributes.VendorID,
563 desc->attributes.ProductID );
564 if (desc->is_polled) wcscat( device_id, L"&POLL" );
566 KeAcquireSpinLock( &impl->base.lock, &irql );
567 devices = impl->devices->Objects;
568 for (i = 0; i < impl->devices->Count; ++i)
570 struct phys_device *phys = pdo_from_DEVICE_OBJECT( (device = devices[i]) );
571 if (!wcscmp( phys->device_id, device_id )) break;
572 else device = NULL;
574 KeReleaseSpinLock( &impl->base.lock, irql );
576 return device;
579 static ULONG_PTR get_device_relations( DEVICE_OBJECT *device, DEVICE_RELATIONS *previous,
580 ULONG count, DEVICE_OBJECT **devices )
582 DEVICE_RELATIONS *relations;
583 ULONG new_count = count;
585 if (previous) new_count += previous->Count;
586 if (!(relations = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[new_count] ) )))
588 ok( 0, "Failed to allocate memory\n" );
589 return (ULONG_PTR)previous;
592 if (!previous) relations->Count = 0;
593 else
595 memcpy( relations, previous, offsetof( DEVICE_RELATIONS, Objects[previous->Count] ) );
596 ExFreePool( previous );
599 while (count--)
601 call_fastcall_func1( ObfReferenceObject, *devices );
602 relations->Objects[relations->Count++] = *devices++;
605 return (ULONG_PTR)relations;
608 static WCHAR *query_instance_id( DEVICE_OBJECT *device )
610 struct phys_device *impl = pdo_from_DEVICE_OBJECT( device );
611 DWORD size = (wcslen( impl->instance_id ) + 1) * sizeof(WCHAR);
612 WCHAR *dst;
614 if ((dst = ExAllocatePool( PagedPool, size )))
615 memcpy( dst, impl->instance_id, size );
617 return dst;
620 static WCHAR *query_hardware_ids( DEVICE_OBJECT *device )
622 struct phys_device *impl = pdo_from_DEVICE_OBJECT( device );
623 DWORD size = (wcslen( impl->device_id ) + 1) * sizeof(WCHAR);
624 WCHAR *dst;
626 if ((dst = ExAllocatePool( PagedPool, size + sizeof(WCHAR) )))
628 memcpy( dst, impl->device_id, size );
629 dst[size / sizeof(WCHAR)] = 0;
632 return dst;
635 static WCHAR *query_compatible_ids( DEVICE_OBJECT *device )
637 static const WCHAR hid_compat_id[] = L"WINETEST\\WINE_COMP_HID";
638 static const WCHAR hid_poll_compat_id[] = L"WINETEST\\WINE_COMP_POLLHID";
639 struct phys_device *impl = pdo_from_DEVICE_OBJECT( device );
640 const WCHAR *compat_id = impl->input_queue.is_polled ? hid_poll_compat_id : hid_compat_id;
641 DWORD size = (wcslen( compat_id ) + 1) * sizeof(WCHAR);
642 WCHAR *dst;
644 if ((dst = ExAllocatePool( PagedPool, size + sizeof(WCHAR) )))
646 memcpy( dst, compat_id, size );
647 dst[size / sizeof(WCHAR)] = 0;
650 return dst;
653 static WCHAR *query_container_id( DEVICE_OBJECT *device )
655 static const WCHAR winetest_id[] = L"WINETEST";
656 DWORD size = sizeof(winetest_id);
657 WCHAR *dst;
659 if ((dst = ExAllocatePool( PagedPool, size )))
660 memcpy( dst, winetest_id, sizeof(winetest_id) );
662 return dst;
665 typedef struct _PNP_BUS_INFORMATION
667 GUID BusTypeGuid;
668 INTERFACE_TYPE LegacyBusType;
669 ULONG BusNumber;
670 } PNP_BUS_INFORMATION, *PPNP_BUS_INFORMATION;
672 static PNP_BUS_INFORMATION *query_bus_information( DEVICE_OBJECT *device )
674 DWORD size = sizeof(PNP_BUS_INFORMATION);
675 PNP_BUS_INFORMATION *dst;
677 if ((dst = ExAllocatePool( PagedPool, size )))
679 memset( &dst->BusTypeGuid, 0, sizeof(dst->BusTypeGuid) );
680 dst->LegacyBusType = PNPBus;
681 dst->BusNumber = 0;
684 return dst;
687 static WCHAR *query_device_text( DEVICE_OBJECT *device )
689 static const WCHAR device_text[] = L"Wine Test HID device";
690 DWORD size = sizeof(device_text);
691 WCHAR *dst;
693 if ((dst = ExAllocatePool( PagedPool, size )))
694 memcpy( dst, device_text, size );
696 return dst;
699 static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp )
701 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
702 struct phys_device *impl = pdo_from_DEVICE_OBJECT( device );
703 struct func_device *fdo = fdo_from_DEVICE_OBJECT( device );
704 ULONG code = stack->MinorFunction;
705 PNP_DEVICE_STATE state;
706 NTSTATUS status;
707 KIRQL irql;
709 if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) );
711 switch (code)
713 case IRP_MN_START_DEVICE:
714 case IRP_MN_CANCEL_REMOVE_DEVICE:
715 case IRP_MN_SURPRISE_REMOVAL:
716 case IRP_MN_QUERY_REMOVE_DEVICE:
717 case IRP_MN_REMOVE_DEVICE:
718 state = (code == IRP_MN_START_DEVICE || code == IRP_MN_CANCEL_REMOVE_DEVICE) ? 0 : PNP_DEVICE_REMOVED;
719 KeAcquireSpinLock( &impl->base.lock, &irql );
720 impl->base.state = state;
721 irp_queue_clear( &impl->input_queue.pending );
722 KeReleaseSpinLock( &impl->base.lock, irql );
723 if (code != IRP_MN_REMOVE_DEVICE) status = STATUS_SUCCESS;
724 else
726 irp->IoStatus.Status = STATUS_SUCCESS;
727 IoCompleteRequest( irp, IO_NO_INCREMENT );
728 if (remove_child_device( fdo, device ))
730 input_queue_cleanup( &impl->input_queue );
731 expect_queue_cleanup( &impl->expect_queue );
732 irp = impl->pending_remove;
733 IoDeleteDevice( device );
734 if (winetest_debug > 1) trace( "Deleted Bus PDO %p\n", device );
735 if (irp)
737 irp->IoStatus.Status = STATUS_SUCCESS;
738 IoCompleteRequest( irp, IO_NO_INCREMENT );
741 return STATUS_SUCCESS;
743 break;
744 case IRP_MN_QUERY_CAPABILITIES:
746 DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities;
747 caps->Removable = 1;
748 caps->SilentInstall = 1;
749 caps->SurpriseRemovalOK = 1;
750 /* caps->RawDeviceOK = 1; */
751 status = STATUS_SUCCESS;
752 break;
754 case IRP_MN_QUERY_ID:
756 BUS_QUERY_ID_TYPE type = stack->Parameters.QueryId.IdType;
757 switch (type)
759 case BusQueryDeviceID:
760 case BusQueryHardwareIDs:
761 irp->IoStatus.Information = (ULONG_PTR)query_hardware_ids( device );
762 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
763 else status = STATUS_SUCCESS;
764 break;
765 case BusQueryInstanceID:
766 irp->IoStatus.Information = (ULONG_PTR)query_instance_id( device );
767 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
768 else status = STATUS_SUCCESS;
769 break;
770 case BusQueryCompatibleIDs:
771 irp->IoStatus.Information = (ULONG_PTR)query_compatible_ids( device );
772 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
773 else status = STATUS_SUCCESS;
774 break;
775 case BusQueryContainerID:
776 irp->IoStatus.Information = (ULONG_PTR)query_container_id( device );
777 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
778 else status = STATUS_SUCCESS;
779 break;
780 default:
781 ok( 0, "IRP_MN_QUERY_ID type %u, not implemented!\n", type );
782 status = STATUS_NOT_SUPPORTED;
783 break;
785 break;
787 case IRP_MN_QUERY_BUS_INFORMATION:
788 irp->IoStatus.Information = (ULONG_PTR)query_bus_information( device );
789 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
790 else status = STATUS_SUCCESS;
791 break;
792 case IRP_MN_QUERY_DEVICE_TEXT:
793 irp->IoStatus.Information = (ULONG_PTR)query_device_text( device );
794 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
795 else status = STATUS_SUCCESS;
796 break;
797 case IRP_MN_QUERY_PNP_DEVICE_STATE:
798 irp->IoStatus.Information = impl->base.state;
799 status = STATUS_SUCCESS;
800 break;
801 case IRP_MN_QUERY_DEVICE_RELATIONS:
803 DEVICE_RELATION_TYPE type = stack->Parameters.QueryDeviceRelations.Type;
804 switch (type)
806 case BusRelations:
807 if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS BusRelations\n" );
808 ok( irp->IoStatus.Information, "got unexpected BusRelations relations\n" );
809 status = irp->IoStatus.Status;
810 break;
811 case EjectionRelations:
812 if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS EjectionRelations\n" );
813 ok( !irp->IoStatus.Information, "got unexpected EjectionRelations relations\n" );
814 status = irp->IoStatus.Status;
815 break;
816 case RemovalRelations:
817 if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS RemovalRelations\n" );
818 ok( irp->IoStatus.Information, "got unexpected RemovalRelations relations\n" );
819 status = irp->IoStatus.Status;
820 break;
821 case TargetDeviceRelation:
822 if (winetest_debug > 1) trace( "pdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS TargetDeviceRelations\n" );
823 ok( !irp->IoStatus.Information, "got unexpected TargetDeviceRelations relations\n" );
824 irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information, 1, &device );
825 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
826 else status = STATUS_SUCCESS;
827 break;
828 default:
829 ok( 0, "got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x\n", type );
830 status = irp->IoStatus.Status;
831 break;
833 break;
835 default:
836 if (winetest_debug > 1) trace( "pdo_pnp code %#lx %s, not implemented!\n", code, debugstr_pnp(code) );
837 status = irp->IoStatus.Status;
838 break;
841 irp->IoStatus.Status = status;
842 IoCompleteRequest( irp, IO_NO_INCREMENT );
843 return status;
846 static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct hid_device_desc *desc )
848 static ULONG index;
850 struct func_device *fdo = fdo_from_DEVICE_OBJECT( device );
851 struct phys_device *impl;
852 UNICODE_STRING name_str;
853 DEVICE_OBJECT *child;
854 WCHAR name[MAX_PATH];
855 NTSTATUS status;
857 if (winetest_debug > 1) trace( "polled %u, report_id %u\n", desc->is_polled, desc->use_report_id );
859 swprintf( name, MAX_PATH, L"\\Device\\WINETEST#%p&%p&%u", device->DriverObject, device, index++ );
860 RtlInitUnicodeString( &name_str, name );
862 if ((status = IoCreateDevice( device->DriverObject, sizeof(struct phys_device), &name_str, 0, 0, FALSE, &child )))
864 ok( 0, "Failed to create gamepad device, status %#lx\n", status );
865 return status;
868 impl = pdo_from_DEVICE_OBJECT( child );
869 KeInitializeSpinLock( &impl->base.lock );
870 swprintf( impl->device_id, MAX_PATH, L"WINETEST\\VID_%04X&PID_%04X", desc->attributes.VendorID,
871 desc->attributes.ProductID );
872 /* use a different device ID so that driver cache select the polled driver */
873 if (desc->is_polled) wcscat( impl->device_id, L"&POLL" );
874 swprintf( impl->instance_id, MAX_PATH, L"0&0000&0" );
875 impl->base.is_phys = TRUE;
876 impl->fdo = fdo;
878 impl->use_report_id = desc->use_report_id;
879 impl->caps = desc->caps;
880 impl->attributes = desc->attributes;
881 impl->report_descriptor_len = desc->report_descriptor_len;
882 memcpy( impl->report_descriptor_buf, desc->report_descriptor_buf, desc->report_descriptor_len );
883 input_queue_init( &impl->input_queue, desc->is_polled );
884 input_queue_reset( &impl->input_queue, desc->input, desc->input_size );
885 expect_queue_init( &impl->expect_queue );
886 expect_queue_reset( &impl->expect_queue, desc->expect, desc->expect_size );
887 memcpy( impl->expect_queue.context, desc->context, desc->context_size );
889 if (winetest_debug > 1) trace( "Created Bus PDO %p for Bus FDO %p\n", child, device );
891 append_child_device( fdo, child );
892 IoInvalidateDeviceRelations( fdo->pdo, BusRelations );
893 return STATUS_SUCCESS;
896 static NTSTATUS fdo_pnp( DEVICE_OBJECT *device, IRP *irp )
898 struct func_device *impl = fdo_from_DEVICE_OBJECT( device );
899 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
900 char relations_buffer[sizeof(impl->devices_buffer)];
901 DEVICE_RELATIONS *relations = (void *)relations_buffer;
902 ULONG code = stack->MinorFunction;
903 PNP_DEVICE_STATE state;
904 NTSTATUS status;
905 KIRQL irql;
907 if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_pnp(code) );
909 switch (code)
911 case IRP_MN_START_DEVICE:
912 case IRP_MN_CANCEL_REMOVE_DEVICE:
913 case IRP_MN_QUERY_REMOVE_DEVICE:
914 case IRP_MN_SURPRISE_REMOVAL:
915 case IRP_MN_REMOVE_DEVICE:
916 state = (code == IRP_MN_START_DEVICE || code == IRP_MN_CANCEL_REMOVE_DEVICE) ? 0 : PNP_DEVICE_REMOVED;
917 KeAcquireSpinLock( &impl->base.lock, &irql );
918 impl->base.state = state;
919 if (code == IRP_MN_REMOVE_DEVICE) memcpy( relations, impl->devices, sizeof(relations_buffer) );
920 impl->devices->Count = 0;
921 KeReleaseSpinLock( &impl->base.lock, irql );
922 IoSetDeviceInterfaceState( &impl->control_iface, state != PNP_DEVICE_REMOVED );
923 if (code != IRP_MN_REMOVE_DEVICE) status = STATUS_SUCCESS;
924 else
926 while (relations->Count--) IoDeleteDevice( relations->Objects[relations->Count] );
927 IoSkipCurrentIrpStackLocation( irp );
928 status = IoCallDriver( impl->pdo, irp );
929 IoDetachDevice( impl->pdo );
930 RtlFreeUnicodeString( &impl->control_iface );
931 IoDeleteDevice( device );
932 if (winetest_debug > 1) trace( "Deleted Bus FDO %p from PDO %p, status %#lx\n", impl, impl->pdo, status );
933 return status;
935 break;
936 case IRP_MN_QUERY_PNP_DEVICE_STATE:
937 KeAcquireSpinLock( &impl->base.lock, &irql );
938 irp->IoStatus.Information = impl->base.state;
939 KeReleaseSpinLock( &impl->base.lock, irql );
940 status = STATUS_SUCCESS;
941 break;
942 case IRP_MN_QUERY_DEVICE_RELATIONS:
944 DEVICE_RELATION_TYPE type = stack->Parameters.QueryDeviceRelations.Type;
945 switch (type)
947 case BusRelations:
948 if (winetest_debug > 1) trace( "fdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS BusRelations\n" );
949 ok( !irp->IoStatus.Information, "got unexpected BusRelations relations\n" );
950 KeAcquireSpinLock( &impl->base.lock, &irql );
951 memcpy( relations, impl->devices, sizeof(relations_buffer) );
952 KeReleaseSpinLock( &impl->base.lock, irql );
953 irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information,
954 relations->Count, relations->Objects );
955 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
956 else status = STATUS_SUCCESS;
957 break;
958 case RemovalRelations:
959 if (winetest_debug > 1) trace( "fdo_pnp IRP_MN_QUERY_DEVICE_RELATIONS RemovalRelations\n" );
960 ok( !irp->IoStatus.Information, "got unexpected RemovalRelations relations\n" );
961 irp->IoStatus.Information = get_device_relations( device, (void *)irp->IoStatus.Information,
962 1, &impl->pdo );
963 if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY;
964 else status = STATUS_SUCCESS;
965 break;
966 default:
967 ok( 0, "got unexpected IRP_MN_QUERY_DEVICE_RELATIONS type %#x\n", type );
968 status = irp->IoStatus.Status;
969 break;
971 break;
973 case IRP_MN_QUERY_CAPABILITIES:
975 DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities;
976 caps->EjectSupported = TRUE;
977 caps->Removable = TRUE;
978 caps->SilentInstall = TRUE;
979 caps->SurpriseRemovalOK = TRUE;
980 status = STATUS_SUCCESS;
981 break;
983 default:
984 if (winetest_debug > 1) trace( "fdo_pnp code %#lx %s, not implemented!\n", code, debugstr_pnp(code) );
985 status = irp->IoStatus.Status;
986 break;
989 irp->IoStatus.Status = status;
990 IoSkipCurrentIrpStackLocation( irp );
991 return IoCallDriver( impl->pdo, irp );
994 static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
996 struct device *impl = impl_from_DEVICE_OBJECT( device );
997 if (impl->is_phys) return pdo_pnp( device, irp );
998 return fdo_pnp( device, irp );
1001 static NTSTATUS WINAPI pdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
1003 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
1004 struct phys_device *impl = pdo_from_DEVICE_OBJECT( device );
1005 const ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength;
1006 ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength;
1007 const ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
1008 struct hid_expect expect = {0};
1009 char context[64];
1010 NTSTATUS status;
1011 BOOL removed;
1012 KIRQL irql;
1013 LONG index;
1015 if ((!impl->input_queue.is_polled || code != IOCTL_HID_READ_REPORT) && winetest_debug > 1)
1016 trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) );
1018 KeAcquireSpinLock( &impl->base.lock, &irql );
1019 removed = impl->base.state == PNP_DEVICE_REMOVED;
1020 KeReleaseSpinLock( &impl->base.lock, irql );
1022 if (removed)
1024 irp->IoStatus.Status = STATUS_DELETE_PENDING;
1025 IoCompleteRequest( irp, IO_NO_INCREMENT );
1026 return STATUS_DELETE_PENDING;
1029 winetest_push_context( "id %d%s", impl->use_report_id, impl->input_queue.is_polled ? " poll" : "" );
1031 switch (code)
1033 case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
1035 HID_DESCRIPTOR *desc = irp->UserBuffer;
1037 ok( !in_size, "got input size %lu\n", in_size );
1038 ok( out_size == sizeof(*desc), "got output size %lu\n", out_size );
1040 if (out_size == sizeof(*desc))
1042 ok( !desc->bLength, "got size %u\n", desc->bLength );
1044 desc->bLength = sizeof(*desc);
1045 desc->bDescriptorType = HID_HID_DESCRIPTOR_TYPE;
1046 desc->bcdHID = HID_REVISION;
1047 desc->bCountry = 0;
1048 desc->bNumDescriptors = 1;
1049 desc->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE;
1050 desc->DescriptorList[0].wReportLength = impl->report_descriptor_len;
1051 irp->IoStatus.Information = sizeof(*desc);
1053 status = STATUS_SUCCESS;
1054 break;
1057 case IOCTL_HID_GET_REPORT_DESCRIPTOR:
1058 ok( !in_size, "got input size %lu\n", in_size );
1059 ok( out_size == impl->report_descriptor_len, "got output size %lu\n", out_size );
1061 if (out_size == impl->report_descriptor_len)
1063 memcpy( irp->UserBuffer, impl->report_descriptor_buf, impl->report_descriptor_len );
1064 irp->IoStatus.Information = impl->report_descriptor_len;
1066 status = STATUS_SUCCESS;
1067 break;
1069 case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
1070 ok( !in_size, "got input size %lu\n", in_size );
1071 ok( out_size == sizeof(impl->attributes), "got output size %lu\n", out_size );
1073 if (out_size == sizeof(impl->attributes))
1075 memcpy( irp->UserBuffer, &impl->attributes, sizeof(impl->attributes) );
1076 irp->IoStatus.Information = sizeof(impl->attributes);
1078 status = STATUS_SUCCESS;
1079 break;
1081 case IOCTL_HID_READ_REPORT:
1083 ULONG expected_size = impl->caps.InputReportByteLength - (impl->use_report_id ? 0 : 1);
1084 ok( !in_size, "got input size %lu\n", in_size );
1085 ok( out_size == expected_size, "got output size %lu\n", out_size );
1086 status = input_queue_read( &impl->input_queue, irp );
1087 break;
1090 case IOCTL_HID_WRITE_REPORT:
1092 HID_XFER_PACKET *packet = irp->UserBuffer;
1094 ok( in_size == sizeof(*packet), "got input size %lu\n", in_size );
1095 ok( !out_size, "got output size %lu\n", out_size );
1096 ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer );
1098 expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) );
1099 winetest_push_context( "%s expect[%ld]", context, index );
1100 ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code );
1101 ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId );
1102 ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen );
1103 check_buffer( packet, &expect );
1104 winetest_pop_context();
1106 irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len;
1107 status = expect.ret_status;
1108 if (status == STATUS_PENDING) status = expect_queue_add_pending( &impl->expect_queue, irp );
1109 break;
1112 case IOCTL_HID_GET_INPUT_REPORT:
1114 HID_XFER_PACKET *packet = irp->UserBuffer;
1116 ok( !in_size, "got input size %lu\n", in_size );
1117 ok( out_size == sizeof(*packet), "got output size %lu\n", out_size );
1118 ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer );
1120 expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, FALSE, context, sizeof(context) );
1121 winetest_push_context( "%s expect[%ld]", context, index );
1122 ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code );
1123 ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId );
1124 ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen );
1125 winetest_pop_context();
1127 irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len;
1128 memcpy( packet->reportBuffer, expect.report_buf, irp->IoStatus.Information );
1129 status = expect.ret_status;
1130 if (status == STATUS_PENDING) status = expect_queue_add_pending( &impl->expect_queue, irp );
1131 break;
1134 case IOCTL_HID_SET_OUTPUT_REPORT:
1136 HID_XFER_PACKET *packet = irp->UserBuffer;
1138 ok( in_size == sizeof(*packet), "got input size %lu\n", in_size );
1139 ok( !out_size, "got output size %lu\n", out_size );
1140 ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer );
1142 expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) );
1143 winetest_push_context( "%s expect[%ld]", context, index );
1144 ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code );
1145 ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId );
1146 ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen );
1147 check_buffer( packet, &expect );
1148 winetest_pop_context();
1150 irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len;
1151 status = expect.ret_status;
1152 if (status == STATUS_PENDING) status = expect_queue_add_pending( &impl->expect_queue, irp );
1153 break;
1156 case IOCTL_HID_GET_FEATURE:
1158 HID_XFER_PACKET *packet = irp->UserBuffer;
1160 ok( !in_size, "got input size %lu\n", in_size );
1161 ok( out_size == sizeof(*packet), "got output size %lu\n", out_size );
1162 ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer );
1164 expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, FALSE, context, sizeof(context) );
1165 winetest_push_context( "%s expect[%ld]", context, index );
1166 ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code );
1167 ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId );
1168 ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen );
1169 winetest_pop_context();
1171 irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len;
1172 memcpy( packet->reportBuffer, expect.report_buf, irp->IoStatus.Information );
1173 status = expect.ret_status;
1174 if (status == STATUS_PENDING) status = expect_queue_add_pending( &impl->expect_queue, irp );
1175 break;
1178 case IOCTL_HID_SET_FEATURE:
1180 HID_XFER_PACKET *packet = irp->UserBuffer;
1182 ok( in_size == sizeof(*packet), "got input size %lu\n", in_size );
1183 ok( !out_size, "got output size %lu\n", out_size );
1184 ok( !!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer );
1186 expect_queue_next( &impl->expect_queue, code, packet, &index, &expect, TRUE, context, sizeof(context) );
1187 winetest_push_context( "%s expect[%ld]", context, index );
1188 ok( code == expect.code, "got %#lx, expected %#lx\n", code, expect.code );
1189 ok( packet->reportId == expect.report_id, "got id %u\n", packet->reportId );
1190 ok( packet->reportBufferLen == expect.report_len, "got len %lu\n", packet->reportBufferLen );
1191 check_buffer( packet, &expect );
1192 winetest_pop_context();
1194 irp->IoStatus.Information = expect.ret_length ? expect.ret_length : expect.report_len;
1195 status = expect.ret_status;
1196 if (status == STATUS_PENDING) status = expect_queue_add_pending( &impl->expect_queue, irp );
1197 break;
1200 case IOCTL_HID_GET_STRING:
1201 memcpy( irp->UserBuffer, L"Wine Test", sizeof(L"Wine Test") );
1202 irp->IoStatus.Information = sizeof(L"Wine Test");
1203 status = STATUS_SUCCESS;
1204 break;
1206 case IOCTL_GET_PHYSICAL_DESCRIPTOR:
1207 irp->IoStatus.Information = 0;
1208 status = STATUS_NOT_SUPPORTED;
1209 break;
1211 default:
1212 ok( 0, "unexpected call\n" );
1213 status = irp->IoStatus.Status;
1214 break;
1217 winetest_pop_context();
1219 if (status != STATUS_PENDING)
1221 irp->IoStatus.Status = status;
1222 IoCompleteRequest( irp, IO_NO_INCREMENT );
1224 return status;
1227 static NTSTATUS WINAPI fdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
1229 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
1230 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
1232 if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) );
1233 ok( 0, "unexpected call\n" );
1235 irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1236 IoCompleteRequest( irp, IO_NO_INCREMENT );
1237 return STATUS_NOT_SUPPORTED;
1240 static NTSTATUS WINAPI driver_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
1242 struct device *impl = impl_from_DEVICE_OBJECT( device );
1243 if (impl->is_phys) return pdo_internal_ioctl( device, irp );
1244 return fdo_internal_ioctl( device, irp );
1247 static NTSTATUS WINAPI pdo_ioctl( DEVICE_OBJECT *device, IRP *irp )
1249 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
1250 struct phys_device *impl = pdo_from_DEVICE_OBJECT( device );
1251 ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength;
1252 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
1253 NTSTATUS status;
1254 KIRQL irql;
1256 if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) );
1258 switch (code)
1260 case IOCTL_WINETEST_HID_SET_EXPECT:
1261 expect_queue_reset( &impl->expect_queue, irp->AssociatedIrp.SystemBuffer, in_size );
1262 status = STATUS_SUCCESS;
1263 break;
1264 case IOCTL_WINETEST_HID_WAIT_EXPECT:
1266 struct wait_expect_params wait_params = *(struct wait_expect_params *)irp->AssociatedIrp.SystemBuffer;
1267 if (!wait_params.wait_pending) status = expect_queue_wait( &impl->expect_queue, irp );
1268 else status = expect_queue_wait_pending( &impl->expect_queue, irp );
1269 break;
1271 case IOCTL_WINETEST_HID_SEND_INPUT:
1272 input_queue_reset( &impl->input_queue, irp->AssociatedIrp.SystemBuffer, in_size );
1273 status = STATUS_SUCCESS;
1274 break;
1275 case IOCTL_WINETEST_HID_SET_CONTEXT:
1276 KeAcquireSpinLock( &impl->expect_queue.lock, &irql );
1277 memcpy( impl->expect_queue.context, irp->AssociatedIrp.SystemBuffer, in_size );
1278 KeReleaseSpinLock( &impl->expect_queue.lock, irql );
1279 status = STATUS_SUCCESS;
1280 break;
1281 case IOCTL_WINETEST_REMOVE_DEVICE:
1282 KeAcquireSpinLock( &impl->base.lock, &irql );
1283 impl->base.state = PNP_DEVICE_REMOVED;
1284 irp_queue_clear( &impl->input_queue.pending );
1285 KeReleaseSpinLock( &impl->base.lock, irql );
1286 impl->pending_remove = irp;
1287 IoMarkIrpPending( irp );
1288 status = STATUS_PENDING;
1289 break;
1290 case IOCTL_WINETEST_CREATE_DEVICE:
1291 ok( 0, "unexpected call\n" );
1292 status = irp->IoStatus.Status;
1293 break;
1294 default:
1295 ok( 0, "unexpected call\n" );
1296 status = irp->IoStatus.Status;
1297 break;
1300 if (status != STATUS_PENDING)
1302 irp->IoStatus.Status = status;
1303 IoCompleteRequest( irp, IO_NO_INCREMENT );
1305 return status;
1308 static NTSTATUS WINAPI fdo_ioctl( DEVICE_OBJECT *device, IRP *irp )
1310 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
1311 ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength;
1312 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
1313 struct func_device *impl = fdo_from_DEVICE_OBJECT( device );
1314 NTSTATUS status;
1316 if (winetest_debug > 1) trace( "%s: device %p, code %#lx %s\n", __func__, device, code, debugstr_ioctl(code) );
1318 switch (code)
1320 case IOCTL_WINETEST_CREATE_DEVICE:
1321 if (in_size < sizeof(struct hid_device_desc)) status = STATUS_INVALID_PARAMETER;
1322 else status = create_child_pdo( device, irp->AssociatedIrp.SystemBuffer );
1323 break;
1324 case IOCTL_WINETEST_REMOVE_DEVICE:
1325 if ((device = find_child_device( impl, irp->AssociatedIrp.SystemBuffer )) &&
1326 !remove_child_device( impl, device ))
1328 status = pdo_ioctl( device, irp );
1329 IoInvalidateDeviceRelations( impl->pdo, BusRelations );
1330 return status;
1332 status = STATUS_NO_SUCH_DEVICE;
1333 break;
1334 default:
1335 ok( 0, "unexpected call\n" );
1336 status = irp->IoStatus.Status;
1337 break;
1340 irp->IoStatus.Status = status;
1341 IoCompleteRequest( irp, IO_NO_INCREMENT );
1342 return status;
1345 static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp )
1347 struct device *impl = impl_from_DEVICE_OBJECT( device );
1348 if (impl->is_phys) return pdo_ioctl( device, irp );
1349 return fdo_ioctl( device, irp );
1352 static NTSTATUS WINAPI driver_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *device )
1354 struct func_device *impl;
1355 DEVICE_OBJECT *child;
1356 NTSTATUS status;
1358 if (winetest_debug > 1) trace( "%s: driver %p, device %p\n", __func__, driver, device );
1360 if ((status = IoCreateDevice( driver, sizeof(struct func_device), NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &child )))
1362 ok( 0, "Failed to create FDO, status %#lx.\n", status );
1363 return status;
1366 impl = (struct func_device *)child->DeviceExtension;
1367 impl->devices = (void *)impl->devices_buffer;
1368 KeInitializeSpinLock( &impl->base.lock );
1369 impl->pdo = device;
1371 status = IoRegisterDeviceInterface( impl->pdo, &control_class, NULL, &impl->control_iface );
1372 ok( !status, "IoRegisterDeviceInterface returned %#lx\n", status );
1374 if (winetest_debug > 1) trace( "Created Bus FDO %p for PDO %p\n", child, device );
1376 IoAttachDeviceToDeviceStack( child, device );
1377 child->Flags &= ~DO_DEVICE_INITIALIZING;
1379 return STATUS_SUCCESS;
1382 static NTSTATUS WINAPI driver_create( DEVICE_OBJECT *device, IRP *irp )
1384 if (winetest_debug > 1) trace( "%s: device %p, irp %p\n", __func__, device, irp );
1386 irp->IoStatus.Status = STATUS_SUCCESS;
1387 IoCompleteRequest( irp, IO_NO_INCREMENT );
1388 return STATUS_SUCCESS;
1391 static NTSTATUS WINAPI driver_close( DEVICE_OBJECT *device, IRP *irp )
1393 if (winetest_debug > 1) trace( "%s: device %p, irp %p\n", __func__, device, irp );
1395 irp->IoStatus.Status = STATUS_SUCCESS;
1396 IoCompleteRequest( irp, IO_NO_INCREMENT );
1397 return STATUS_SUCCESS;
1400 static void WINAPI driver_unload( DRIVER_OBJECT *driver )
1402 if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver );
1403 winetest_cleanup();
1406 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *registry )
1408 NTSTATUS status;
1410 if ((status = winetest_init())) return status;
1411 if (winetest_debug > 1) trace( "%s: driver %p\n", __func__, driver );
1413 driver->DriverExtension->AddDevice = driver_add_device;
1414 driver->DriverUnload = driver_unload;
1415 driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
1416 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl;
1417 driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl;
1418 driver->MajorFunction[IRP_MJ_CREATE] = driver_create;
1419 driver->MajorFunction[IRP_MJ_CLOSE] = driver_close;
1421 return STATUS_SUCCESS;