hidclass.sys: Stop accepting IRPs after device removal.
[wine.git] / dlls / hidclass.sys / pnp.c
blob2f5fe5de4eb4345beb1823574cb44428787e86ef
1 /*
2 * Human Interface Device class driver
4 * Copyright 2015 Aric Stewart
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 <unistd.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include "initguid.h"
25 #include "hid.h"
26 #include "devguid.h"
27 #include "devpkey.h"
28 #include "ntddmou.h"
29 #include "ntddkbd.h"
30 #include "ddk/hidtypes.h"
31 #include "ddk/wdm.h"
32 #include "regstr.h"
33 #include "winuser.h"
34 #include "wine/debug.h"
35 #include "wine/asm.h"
36 #include "wine/list.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(hid);
40 DEFINE_DEVPROPKEY(DEVPROPKEY_HID_HANDLE, 0xbc62e415, 0xf4fe, 0x405c, 0x8e, 0xda, 0x63, 0x6f, 0xb5, 0x9f, 0x08, 0x98, 2);
42 #if defined(__i386__) && !defined(_WIN32)
44 extern void * WINAPI wrap_fastcall_func1( void *func, const void *a );
45 __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8,
46 "popl %ecx\n\t"
47 "popl %eax\n\t"
48 "xchgl (%esp),%ecx\n\t"
49 "jmp *%eax" );
51 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
53 #else
55 #define call_fastcall_func1(func,a) func(a)
57 #endif
59 static struct list minidriver_list = LIST_INIT(minidriver_list);
61 static minidriver *find_minidriver(DRIVER_OBJECT *driver)
63 minidriver *md;
64 LIST_FOR_EACH_ENTRY(md, &minidriver_list, minidriver, entry)
66 if (md->minidriver.DriverObject == driver)
67 return md;
69 return NULL;
72 static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR *id)
74 IO_STACK_LOCATION *irpsp;
75 IO_STATUS_BLOCK irp_status;
76 KEVENT event;
77 IRP *irp;
79 KeInitializeEvent(&event, NotificationEvent, FALSE);
80 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, &event, &irp_status);
81 if (irp == NULL)
82 return STATUS_NO_MEMORY;
84 irpsp = IoGetNextIrpStackLocation(irp);
85 irpsp->MinorFunction = IRP_MN_QUERY_ID;
86 irpsp->Parameters.QueryId.IdType = type;
88 if (IoCallDriver(device, irp) == STATUS_PENDING)
89 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
91 wcscpy(id, (WCHAR *)irp_status.Information);
92 ExFreePool((WCHAR *)irp_status.Information);
93 return irp_status.Status;
96 /* user32 reserves 1 & 2 for winemouse and winekeyboard,
97 * keep this in sync with user_private.h */
98 #define WINE_MOUSE_HANDLE 1
99 #define WINE_KEYBOARD_HANDLE 2
101 static UINT32 alloc_rawinput_handle(void)
103 static LONG counter = WINE_KEYBOARD_HANDLE + 1;
104 return InterlockedIncrement(&counter);
107 /* make sure bRawData can hold UsagePage and Usage without requiring additional allocation */
108 C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]) < sizeof(RAWINPUT));
110 static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param)
112 RAWINPUT rawinput;
113 INPUT input;
115 rawinput.header.dwType = RIM_TYPEHID;
116 rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]);
117 rawinput.header.hDevice = ULongToHandle(ext->u.pdo.rawinput_handle);
118 rawinput.header.wParam = param;
119 rawinput.data.hid.dwCount = 0;
120 rawinput.data.hid.dwSizeHid = 0;
121 ((USAGE *)rawinput.data.hid.bRawData)[0] = ext->u.pdo.preparsed_data->caps.UsagePage;
122 ((USAGE *)rawinput.data.hid.bRawData)[1] = ext->u.pdo.preparsed_data->caps.Usage;
124 input.type = INPUT_HARDWARE;
125 input.hi.uMsg = WM_INPUT_DEVICE_CHANGE;
126 input.hi.wParamH = 0;
127 input.hi.wParamL = 0;
128 __wine_send_input(0, &input, &rawinput);
131 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *bus_pdo)
133 WCHAR device_id[MAX_DEVICE_ID_LEN], instance_id[MAX_DEVICE_ID_LEN];
134 BASE_DEVICE_EXTENSION *ext;
135 DEVICE_OBJECT *fdo;
136 NTSTATUS status;
137 minidriver *minidriver;
139 if ((status = get_device_id(bus_pdo, BusQueryDeviceID, device_id)))
141 ERR("Failed to get PDO device id, status %#x.\n", status);
142 return status;
145 if ((status = get_device_id(bus_pdo, BusQueryInstanceID, instance_id)))
147 ERR("Failed to get PDO instance id, status %#x.\n", status);
148 return status;
151 TRACE("Adding device to PDO %p, id %s\\%s.\n", bus_pdo, debugstr_w(device_id), debugstr_w(instance_id));
152 minidriver = find_minidriver(driver);
154 if ((status = IoCreateDevice(driver, sizeof(*ext) + minidriver->minidriver.DeviceExtensionSize,
155 NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &fdo)))
157 ERR("Failed to create bus FDO, status %#x.\n", status);
158 return status;
160 ext = fdo->DeviceExtension;
161 ext->is_fdo = TRUE;
162 ext->u.fdo.hid_ext.MiniDeviceExtension = ext + 1;
163 ext->u.fdo.hid_ext.PhysicalDeviceObject = bus_pdo;
164 ext->u.fdo.hid_ext.NextDeviceObject = bus_pdo;
165 swprintf(ext->device_id, ARRAY_SIZE(ext->device_id), L"HID\\%s", wcsrchr(device_id, '\\') + 1);
166 wcscpy(ext->instance_id, instance_id);
168 status = minidriver->AddDevice(minidriver->minidriver.DriverObject, fdo);
169 if (status != STATUS_SUCCESS)
171 ERR("Minidriver AddDevice failed (%x)\n",status);
172 IoDeleteDevice(fdo);
173 return status;
176 IoAttachDeviceToDeviceStack(fdo, bus_pdo);
177 fdo->Flags &= ~DO_DEVICE_INITIALIZING;
179 return STATUS_SUCCESS;
182 static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo)
184 BASE_DEVICE_EXTENSION *fdo_ext = fdo->DeviceExtension, *pdo_ext;
185 HID_DEVICE_ATTRIBUTES attr = {0};
186 HID_DESCRIPTOR descriptor;
187 DEVICE_OBJECT *child_pdo;
188 BYTE *reportDescriptor;
189 UNICODE_STRING string;
190 WCHAR pdo_name[255];
191 USAGE page, usage;
192 NTSTATUS status;
193 INT i;
195 status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, fdo, NULL, 0, &attr, sizeof(attr));
196 if (status != STATUS_SUCCESS)
198 ERR("Minidriver failed to get Attributes(%x)\n",status);
199 return;
202 swprintf(pdo_name, ARRAY_SIZE(pdo_name), L"\\Device\\HID#%p&%p", fdo->DriverObject,
203 fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject);
204 RtlInitUnicodeString(&string, pdo_name);
205 if ((status = IoCreateDevice(fdo->DriverObject, sizeof(*pdo_ext), &string, 0, 0, FALSE, &child_pdo)))
207 ERR("Failed to create child PDO, status %#x.\n", status);
208 return;
210 fdo_ext->u.fdo.child_pdo = child_pdo;
212 pdo_ext = child_pdo->DeviceExtension;
213 pdo_ext->u.pdo.parent_fdo = fdo;
214 InitializeListHead(&pdo_ext->u.pdo.irp_queue);
215 KeInitializeSpinLock(&pdo_ext->u.pdo.irp_queue_lock);
216 wcscpy(pdo_ext->device_id, fdo_ext->device_id);
217 wcscpy(pdo_ext->instance_id, fdo_ext->instance_id);
219 pdo_ext->u.pdo.information.VendorID = attr.VendorID;
220 pdo_ext->u.pdo.information.ProductID = attr.ProductID;
221 pdo_ext->u.pdo.information.VersionNumber = attr.VersionNumber;
222 pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled;
224 status = call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR, fdo, NULL, 0, &descriptor, sizeof(descriptor));
225 if (status != STATUS_SUCCESS)
227 ERR("Cannot get Device Descriptor(%x)\n",status);
228 IoDeleteDevice(child_pdo);
229 return;
231 for (i = 0; i < descriptor.bNumDescriptors; i++)
232 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
233 break;
235 if (i >= descriptor.bNumDescriptors)
237 ERR("No Report Descriptor found in reply\n");
238 IoDeleteDevice(child_pdo);
239 return;
242 reportDescriptor = malloc(descriptor.DescriptorList[i].wReportLength);
243 status = call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR, fdo, NULL, 0,
244 reportDescriptor, descriptor.DescriptorList[i].wReportLength);
245 if (status != STATUS_SUCCESS)
247 ERR("Cannot get Report Descriptor(%x)\n",status);
248 free(reportDescriptor);
249 IoDeleteDevice(child_pdo);
250 return;
253 pdo_ext->u.pdo.preparsed_data = ParseDescriptor(reportDescriptor, descriptor.DescriptorList[i].wReportLength);
254 free(reportDescriptor);
255 if (!pdo_ext->u.pdo.preparsed_data)
257 ERR("Cannot parse Report Descriptor\n");
258 IoDeleteDevice(child_pdo);
259 return;
262 pdo_ext->u.pdo.information.DescriptorSize = pdo_ext->u.pdo.preparsed_data->dwSize;
264 page = pdo_ext->u.pdo.preparsed_data->caps.UsagePage;
265 usage = pdo_ext->u.pdo.preparsed_data->caps.Usage;
266 if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE)
267 pdo_ext->u.pdo.rawinput_handle = WINE_MOUSE_HANDLE;
268 else if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD)
269 pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE;
270 else
271 pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle();
273 IoInvalidateDeviceRelations(fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, BusRelations);
275 if ((status = IoSetDevicePropertyData(child_pdo, &DEVPROPKEY_HID_HANDLE, LOCALE_NEUTRAL,
276 PLUGPLAY_PROPERTY_PERSISTENT, DEVPROP_TYPE_UINT32,
277 sizeof(pdo_ext->u.pdo.rawinput_handle), &pdo_ext->u.pdo.rawinput_handle)))
279 ERR("Failed to set device handle property, status %x\n", status);
280 IoDeleteDevice(child_pdo);
281 return;
284 pdo_ext->u.pdo.poll_interval = DEFAULT_POLL_INTERVAL;
286 pdo_ext->u.pdo.ring_buffer = RingBuffer_Create(
287 sizeof(HID_XFER_PACKET) + pdo_ext->u.pdo.preparsed_data->caps.InputReportByteLength);
289 HID_StartDeviceThread(child_pdo);
291 send_wm_input_device_change(pdo_ext, GIDC_ARRIVAL);
294 static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp)
296 minidriver *minidriver = find_minidriver(device->DriverObject);
297 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
298 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
300 TRACE("irp %p, minor function %#x.\n", irp, stack->MinorFunction);
302 switch (stack->MinorFunction)
304 case IRP_MN_QUERY_DEVICE_RELATIONS:
306 DEVICE_RELATIONS *devices;
307 DEVICE_OBJECT *child;
309 if (stack->Parameters.QueryDeviceRelations.Type != BusRelations)
310 return minidriver->PNPDispatch(device, irp);
312 if (!(devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[1]))))
314 irp->IoStatus.Status = STATUS_NO_MEMORY;
315 IoCompleteRequest(irp, IO_NO_INCREMENT);
316 return STATUS_NO_MEMORY;
319 if ((child = ext->u.fdo.child_pdo))
321 devices->Objects[0] = ext->u.fdo.child_pdo;
322 call_fastcall_func1(ObfReferenceObject, ext->u.fdo.child_pdo);
323 devices->Count = 1;
325 else
327 devices->Count = 0;
330 irp->IoStatus.Information = (ULONG_PTR)devices;
331 irp->IoStatus.Status = STATUS_SUCCESS;
332 IoSkipCurrentIrpStackLocation(irp);
333 return IoCallDriver(ext->u.fdo.hid_ext.NextDeviceObject, irp);
336 case IRP_MN_START_DEVICE:
338 NTSTATUS ret;
340 if ((ret = minidriver->PNPDispatch(device, irp)))
341 return ret;
342 create_child(minidriver, device);
343 return STATUS_SUCCESS;
346 case IRP_MN_REMOVE_DEVICE:
348 NTSTATUS ret;
350 ret = minidriver->PNPDispatch(device, irp);
352 IoDetachDevice(ext->u.fdo.hid_ext.NextDeviceObject);
353 IoDeleteDevice(device);
354 return ret;
357 default:
358 return minidriver->PNPDispatch(device, irp);
362 static void remove_pending_irps(BASE_DEVICE_EXTENSION *ext)
364 IRP *irp;
366 while ((irp = pop_irp_from_queue(ext)))
368 irp->IoStatus.Status = STATUS_DELETE_PENDING;
369 IoCompleteRequest(irp, IO_NO_INCREMENT);
373 static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp)
375 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
376 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
377 NTSTATUS status = irp->IoStatus.Status;
378 KIRQL irql;
380 TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction);
382 switch(irpsp->MinorFunction)
384 case IRP_MN_QUERY_ID:
386 WCHAR *id = ExAllocatePool(PagedPool, sizeof(WCHAR) * REGSTR_VAL_MAX_HCID_LEN);
387 TRACE("IRP_MN_QUERY_ID[%i]\n", irpsp->Parameters.QueryId.IdType);
388 switch (irpsp->Parameters.QueryId.IdType)
390 case BusQueryHardwareIDs:
391 case BusQueryCompatibleIDs:
393 WCHAR *ptr;
394 ptr = id;
395 /* Device instance ID */
396 lstrcpyW(ptr, ext->device_id);
397 ptr += lstrlenW(ext->device_id);
398 lstrcpyW(ptr, L"\\");
399 ptr += 1;
400 lstrcpyW(ptr, ext->instance_id);
401 ptr += lstrlenW(ext->instance_id) + 1;
402 /* Device ID */
403 lstrcpyW(ptr, ext->device_id);
404 ptr += lstrlenW(ext->device_id) + 1;
405 /* Bus ID */
406 lstrcpyW(ptr, L"HID");
407 ptr += lstrlenW(L"HID") + 1;
408 *ptr = 0;
409 irp->IoStatus.Information = (ULONG_PTR)id;
410 status = STATUS_SUCCESS;
411 break;
413 case BusQueryDeviceID:
414 lstrcpyW(id, ext->device_id);
415 irp->IoStatus.Information = (ULONG_PTR)id;
416 status = STATUS_SUCCESS;
417 break;
418 case BusQueryInstanceID:
419 lstrcpyW(id, ext->instance_id);
420 irp->IoStatus.Information = (ULONG_PTR)id;
421 status = STATUS_SUCCESS;
422 break;
424 case BusQueryContainerID:
425 case BusQueryDeviceSerialNumber:
426 FIXME("unimplemented id type %#x\n", irpsp->Parameters.QueryId.IdType);
427 ExFreePool(id);
428 break;
430 break;
433 case IRP_MN_QUERY_CAPABILITIES:
435 DEVICE_CAPABILITIES *caps = irpsp->Parameters.DeviceCapabilities.Capabilities;
437 caps->RawDeviceOK = 1;
438 status = STATUS_SUCCESS;
439 break;
442 case IRP_MN_START_DEVICE:
443 if ((status = IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_HID, NULL, &ext->u.pdo.link_name)))
445 ERR("Failed to register interface, status %#x.\n", status);
446 break;
449 /* FIXME: This should probably be done in mouhid.sys. */
450 if (ext->u.pdo.preparsed_data->caps.UsagePage == HID_USAGE_PAGE_GENERIC
451 && ext->u.pdo.preparsed_data->caps.Usage == HID_USAGE_GENERIC_MOUSE)
453 if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_MOUSE, NULL, &ext->u.pdo.mouse_link_name))
454 ext->u.pdo.is_mouse = TRUE;
456 if (ext->u.pdo.preparsed_data->caps.UsagePage == HID_USAGE_PAGE_GENERIC
457 && ext->u.pdo.preparsed_data->caps.Usage == HID_USAGE_GENERIC_KEYBOARD)
459 if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_KEYBOARD, NULL, &ext->u.pdo.keyboard_link_name))
460 ext->u.pdo.is_keyboard = TRUE;
463 IoSetDeviceInterfaceState(&ext->u.pdo.link_name, TRUE);
464 if (ext->u.pdo.is_mouse)
465 IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, TRUE);
466 if (ext->u.pdo.is_keyboard)
467 IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, TRUE);
469 ext->u.pdo.removed = FALSE;
470 status = STATUS_SUCCESS;
471 break;
473 case IRP_MN_REMOVE_DEVICE:
474 remove_pending_irps(ext);
476 send_wm_input_device_change(ext, GIDC_REMOVAL);
478 IoSetDeviceInterfaceState(&ext->u.pdo.link_name, FALSE);
479 if (ext->u.pdo.is_mouse)
480 IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, FALSE);
481 if (ext->u.pdo.is_keyboard)
482 IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, FALSE);
484 if (ext->u.pdo.thread)
486 SetEvent(ext->u.pdo.halt_event);
487 WaitForSingleObject(ext->u.pdo.thread, INFINITE);
489 CloseHandle(ext->u.pdo.halt_event);
491 free(ext->u.pdo.preparsed_data);
492 if (ext->u.pdo.ring_buffer)
493 RingBuffer_Destroy(ext->u.pdo.ring_buffer);
495 RtlFreeUnicodeString(&ext->u.pdo.link_name);
497 irp->IoStatus.Status = STATUS_SUCCESS;
498 IoCompleteRequest(irp, IO_NO_INCREMENT);
499 IoDeleteDevice(device);
500 return STATUS_SUCCESS;
502 case IRP_MN_SURPRISE_REMOVAL:
503 KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
504 ext->u.pdo.removed = TRUE;
505 KeReleaseSpinLock(&ext->u.pdo.lock, irql);
507 remove_pending_irps(ext);
509 SetEvent(ext->u.pdo.halt_event);
510 status = STATUS_SUCCESS;
511 break;
513 default:
514 FIXME("Unhandled minor function %#x.\n", irpsp->MinorFunction);
517 irp->IoStatus.Status = status;
518 IoCompleteRequest( irp, IO_NO_INCREMENT );
519 return status;
522 static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
524 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
526 if (ext->is_fdo)
527 return fdo_pnp(device, irp);
528 else
529 return pdo_pnp(device, irp);
532 static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp)
534 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
536 if (ext->is_fdo)
538 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
539 IoCompleteRequest(irp, IO_NO_INCREMENT);
540 return STATUS_UNSUCCESSFUL;
543 return pdo_create(device, irp);
546 static NTSTATUS WINAPI driver_close(DEVICE_OBJECT *device, IRP *irp)
548 return pdo_close(device, irp);
551 static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp)
553 return pdo_ioctl(device, irp);
556 static NTSTATUS WINAPI driver_read(DEVICE_OBJECT *device, IRP *irp)
558 return pdo_read(device, irp);
561 static NTSTATUS WINAPI driver_write(DEVICE_OBJECT *device, IRP *irp)
563 return pdo_write(device, irp);
566 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
568 minidriver *md;
570 TRACE("\n");
572 if ((md = find_minidriver(driver)))
574 if (md->DriverUnload)
575 md->DriverUnload(md->minidriver.DriverObject);
576 list_remove(&md->entry);
577 free(md);
581 NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration)
583 minidriver *driver;
585 if (!(driver = calloc(1, sizeof(*driver))))
586 return STATUS_NO_MEMORY;
588 driver->DriverUnload = registration->DriverObject->DriverUnload;
589 registration->DriverObject->DriverUnload = driver_unload;
591 registration->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl;
592 registration->DriverObject->MajorFunction[IRP_MJ_READ] = driver_read;
593 registration->DriverObject->MajorFunction[IRP_MJ_WRITE] = driver_write;
594 registration->DriverObject->MajorFunction[IRP_MJ_CREATE] = driver_create;
595 registration->DriverObject->MajorFunction[IRP_MJ_CLOSE] = driver_close;
597 driver->PNPDispatch = registration->DriverObject->MajorFunction[IRP_MJ_PNP];
598 registration->DriverObject->MajorFunction[IRP_MJ_PNP] = driver_pnp;
600 driver->AddDevice = registration->DriverObject->DriverExtension->AddDevice;
601 registration->DriverObject->DriverExtension->AddDevice = driver_add_device;
603 driver->minidriver = *registration;
604 list_add_tail(&minidriver_list, &driver->entry);
606 return STATUS_SUCCESS;
609 NTSTATUS call_minidriver(ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size, void *out_buff, ULONG out_size)
611 IRP *irp;
612 IO_STATUS_BLOCK io;
613 KEVENT event;
615 KeInitializeEvent(&event, NotificationEvent, FALSE);
617 irp = IoBuildDeviceIoControlRequest(code, device, in_buff, in_size,
618 out_buff, out_size, TRUE, &event, &io);
620 if (IoCallDriver(device, irp) == STATUS_PENDING)
621 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
623 return io.Status;