urlmon/tests: Add basic tests for CoInternetParseUrl(PARSE_CANONICALIZE).
[wine.git] / dlls / hidclass.sys / pnp.c
blobab3cd5b2cb5903c1a690329c767225409ddfbaff
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 "ntddmou.h"
28 #include "ntddkbd.h"
29 #include "ddk/hidtypes.h"
30 #include "ddk/wdm.h"
31 #include "regstr.h"
32 #include "ntuser.h"
33 #include "wine/debug.h"
34 #include "wine/asm.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(hid);
39 DEFINE_GUID(GUID_DEVINTERFACE_WINEXINPUT, 0x6c53d5fd, 0x6480, 0x440f, 0xb6, 0x18, 0x47, 0x67, 0x50, 0xc5, 0xe1, 0xa6);
41 #ifdef __ASM_USE_FASTCALL_WRAPPER
43 extern void * WINAPI wrap_fastcall_func1( void *func, const void *a );
44 __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8,
45 "popl %ecx\n\t"
46 "popl %eax\n\t"
47 "xchgl (%esp),%ecx\n\t"
48 "jmp *%eax" );
50 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
52 #else
54 #define call_fastcall_func1(func,a) func(a)
56 #endif
58 static struct list minidriver_list = LIST_INIT(minidriver_list);
60 static minidriver *find_minidriver(DRIVER_OBJECT *driver)
62 minidriver *md;
63 LIST_FOR_EACH_ENTRY(md, &minidriver_list, minidriver, entry)
65 if (md->minidriver.DriverObject == driver)
66 return md;
68 return NULL;
71 static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR *id)
73 IO_STACK_LOCATION *irpsp;
74 IO_STATUS_BLOCK irp_status;
75 KEVENT event;
76 IRP *irp;
78 KeInitializeEvent(&event, NotificationEvent, FALSE);
79 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, &event, &irp_status);
80 if (irp == NULL)
81 return STATUS_NO_MEMORY;
83 irpsp = IoGetNextIrpStackLocation(irp);
84 irpsp->MinorFunction = IRP_MN_QUERY_ID;
85 irpsp->Parameters.QueryId.IdType = type;
87 irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
88 if (IoCallDriver(device, irp) == STATUS_PENDING)
89 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
91 if (!irp_status.Status)
93 wcscpy(id, (WCHAR *)irp_status.Information);
94 ExFreePool((WCHAR *)irp_status.Information);
97 return irp_status.Status;
100 /* user32 reserves 1 & 2 for winemouse and winekeyboard,
101 * keep this in sync with user_private.h */
102 #define WINE_MOUSE_HANDLE 1
103 #define WINE_KEYBOARD_HANDLE 2
105 static UINT32 alloc_rawinput_handle(void)
107 static LONG counter = WINE_KEYBOARD_HANDLE + 1;
108 return InterlockedIncrement(&counter);
111 /* make sure bRawData can hold UsagePage and Usage without requiring additional allocation */
112 C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]) < sizeof(RAWINPUT));
114 static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param)
116 HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc;
117 RAWINPUT rawinput;
118 INPUT input;
120 TRACE("ext %p, lparam %p\n", ext, (void *)param);
122 if (!IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID )) return;
124 rawinput.header.dwType = RIM_TYPEHID;
125 rawinput.header.dwSize = offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]);
126 rawinput.header.hDevice = ULongToHandle(ext->u.pdo.rawinput_handle);
127 rawinput.header.wParam = param;
128 rawinput.data.hid.dwCount = 0;
129 rawinput.data.hid.dwSizeHid = 0;
130 ((USAGE *)rawinput.data.hid.bRawData)[0] = desc->UsagePage;
131 ((USAGE *)rawinput.data.hid.bRawData)[1] = desc->Usage;
133 input.type = INPUT_HARDWARE;
134 input.hi.uMsg = WM_INPUT_DEVICE_CHANGE;
135 input.hi.wParamH = 0;
136 input.hi.wParamL = 0;
137 __wine_send_input(0, &input, &rawinput);
140 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *bus_pdo)
142 WCHAR device_id[MAX_DEVICE_ID_LEN], instance_id[MAX_DEVICE_ID_LEN];
143 BASE_DEVICE_EXTENSION *ext;
144 BOOL is_xinput_class;
145 DEVICE_OBJECT *fdo;
146 NTSTATUS status;
147 minidriver *minidriver;
149 if ((status = get_device_id(bus_pdo, BusQueryDeviceID, device_id)))
151 ERR( "Failed to get PDO device id, status %#lx.\n", status );
152 return status;
155 if ((status = get_device_id(bus_pdo, BusQueryInstanceID, instance_id)))
157 ERR( "Failed to get PDO instance id, status %#lx.\n", status );
158 return status;
161 TRACE("Adding device to PDO %p, id %s\\%s.\n", bus_pdo, debugstr_w(device_id), debugstr_w(instance_id));
162 minidriver = find_minidriver(driver);
164 if ((status = IoCreateDevice(driver, sizeof(*ext) + minidriver->minidriver.DeviceExtensionSize,
165 NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &fdo)))
167 ERR( "Failed to create bus FDO, status %#lx.\n", status );
168 return status;
170 ext = fdo->DeviceExtension;
171 ext->is_fdo = TRUE;
172 ext->u.fdo.hid_ext.MiniDeviceExtension = ext + 1;
173 ext->u.fdo.hid_ext.PhysicalDeviceObject = bus_pdo;
174 ext->u.fdo.hid_ext.NextDeviceObject = bus_pdo;
175 swprintf(ext->device_id, ARRAY_SIZE(ext->device_id), L"HID\\%s", wcsrchr(device_id, '\\') + 1);
176 wcscpy(ext->instance_id, instance_id);
178 if (get_device_id(bus_pdo, BusQueryContainerID, ext->container_id))
179 ext->container_id[0] = 0;
181 is_xinput_class = !wcsncmp(device_id, L"WINEXINPUT\\", 7) && wcsstr(device_id, L"&XI_") != NULL;
182 if (is_xinput_class) ext->class_guid = &GUID_DEVINTERFACE_WINEXINPUT;
183 else ext->class_guid = &GUID_DEVINTERFACE_HID;
185 status = minidriver->AddDevice(minidriver->minidriver.DriverObject, fdo);
186 if (status != STATUS_SUCCESS)
188 ERR( "Minidriver AddDevice failed (%lx)\n", status );
189 IoDeleteDevice(fdo);
190 return status;
193 IoAttachDeviceToDeviceStack(fdo, bus_pdo);
194 fdo->Flags &= ~DO_DEVICE_INITIALIZING;
196 return STATUS_SUCCESS;
199 static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo)
201 BASE_DEVICE_EXTENSION *fdo_ext = fdo->DeviceExtension, *pdo_ext;
202 HID_DEVICE_ATTRIBUTES attr = {0};
203 HID_DESCRIPTOR descriptor = {0};
204 HIDP_COLLECTION_DESC *desc;
205 DEVICE_OBJECT *child_pdo;
206 BYTE *reportDescriptor;
207 UNICODE_STRING string;
208 WCHAR pdo_name[255];
209 IO_STATUS_BLOCK io;
210 USAGE page, usage;
211 NTSTATUS status;
212 INT i;
214 call_minidriver( IOCTL_HID_GET_DEVICE_ATTRIBUTES, fdo, NULL, 0, &attr, sizeof(attr), &io );
215 if (io.Status != STATUS_SUCCESS)
217 ERR( "Minidriver failed to get attributes, status %#lx.\n", io.Status );
218 return;
221 swprintf(pdo_name, ARRAY_SIZE(pdo_name), L"\\Device\\HID#%p&%p", fdo->DriverObject,
222 fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject);
223 RtlInitUnicodeString(&string, pdo_name);
224 if ((status = IoCreateDevice(fdo->DriverObject, sizeof(*pdo_ext), &string, 0, 0, FALSE, &child_pdo)))
226 ERR( "Failed to create child PDO, status %#lx.\n", io.Status );
227 return;
229 fdo_ext->u.fdo.child_pdo = child_pdo;
231 pdo_ext = child_pdo->DeviceExtension;
232 pdo_ext->u.pdo.parent_fdo = fdo;
233 list_init( &pdo_ext->u.pdo.queues );
234 KeInitializeSpinLock( &pdo_ext->u.pdo.queues_lock );
235 wcscpy(pdo_ext->device_id, fdo_ext->device_id);
236 wcscpy(pdo_ext->instance_id, fdo_ext->instance_id);
237 wcscpy(pdo_ext->container_id, fdo_ext->container_id);
238 pdo_ext->class_guid = fdo_ext->class_guid;
240 pdo_ext->u.pdo.information.VendorID = attr.VendorID;
241 pdo_ext->u.pdo.information.ProductID = attr.ProductID;
242 pdo_ext->u.pdo.information.VersionNumber = attr.VersionNumber;
243 pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled;
245 call_minidriver( IOCTL_HID_GET_DEVICE_DESCRIPTOR, fdo, NULL, 0, &descriptor, sizeof(descriptor), &io );
246 if (io.Status != STATUS_SUCCESS)
248 ERR( "Cannot get Device Descriptor, status %#lx\n", status );
249 IoDeleteDevice(child_pdo);
250 return;
252 for (i = 0; i < descriptor.bNumDescriptors; i++)
253 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
254 break;
256 if (i >= descriptor.bNumDescriptors)
258 ERR("No Report Descriptor found in reply\n");
259 IoDeleteDevice(child_pdo);
260 return;
263 reportDescriptor = malloc(descriptor.DescriptorList[i].wReportLength);
264 call_minidriver( IOCTL_HID_GET_REPORT_DESCRIPTOR, fdo, NULL, 0, reportDescriptor,
265 descriptor.DescriptorList[i].wReportLength, &io );
266 if (io.Status != STATUS_SUCCESS)
268 ERR( "Cannot get Report Descriptor, status %#lx\n", status );
269 free(reportDescriptor);
270 IoDeleteDevice(child_pdo);
271 return;
274 io.Status = HidP_GetCollectionDescription( reportDescriptor, descriptor.DescriptorList[i].wReportLength,
275 PagedPool, &pdo_ext->u.pdo.device_desc );
276 free(reportDescriptor);
277 if (io.Status != HIDP_STATUS_SUCCESS)
279 ERR("Cannot parse Report Descriptor\n");
280 IoDeleteDevice(child_pdo);
281 return;
284 desc = pdo_ext->u.pdo.device_desc.CollectionDesc;
285 pdo_ext->u.pdo.information.DescriptorSize = desc->PreparsedDataLength;
287 page = desc->UsagePage;
288 usage = desc->Usage;
289 if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE)
290 pdo_ext->u.pdo.rawinput_handle = WINE_MOUSE_HANDLE;
291 else if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD)
292 pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE;
293 else
294 pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle();
296 IoInvalidateDeviceRelations(fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, BusRelations);
298 pdo_ext->u.pdo.poll_interval = DEFAULT_POLL_INTERVAL;
300 HID_StartDeviceThread(child_pdo);
302 send_wm_input_device_change(pdo_ext, GIDC_ARRIVAL);
304 TRACE( "created device %p, rawinput handle %#x\n", pdo_ext, pdo_ext->u.pdo.rawinput_handle );
307 static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp)
309 minidriver *minidriver = find_minidriver(device->DriverObject);
310 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
311 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
313 TRACE("irp %p, minor function %#x.\n", irp, stack->MinorFunction);
315 switch (stack->MinorFunction)
317 case IRP_MN_QUERY_DEVICE_RELATIONS:
319 DEVICE_RELATIONS *devices;
320 DEVICE_OBJECT *child;
322 if (stack->Parameters.QueryDeviceRelations.Type != BusRelations)
323 return minidriver->PNPDispatch(device, irp);
325 if (!(devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[1]))))
327 irp->IoStatus.Status = STATUS_NO_MEMORY;
328 IoCompleteRequest(irp, IO_NO_INCREMENT);
329 return STATUS_NO_MEMORY;
332 if ((child = ext->u.fdo.child_pdo))
334 devices->Objects[0] = ext->u.fdo.child_pdo;
335 call_fastcall_func1(ObfReferenceObject, ext->u.fdo.child_pdo);
336 devices->Count = 1;
338 else
340 devices->Count = 0;
343 irp->IoStatus.Information = (ULONG_PTR)devices;
344 irp->IoStatus.Status = STATUS_SUCCESS;
345 IoSkipCurrentIrpStackLocation(irp);
346 return IoCallDriver(ext->u.fdo.hid_ext.NextDeviceObject, irp);
349 case IRP_MN_START_DEVICE:
351 NTSTATUS ret;
353 if ((ret = minidriver->PNPDispatch(device, irp)))
354 return ret;
355 create_child(minidriver, device);
356 return STATUS_SUCCESS;
359 case IRP_MN_REMOVE_DEVICE:
361 NTSTATUS ret;
363 ret = minidriver->PNPDispatch(device, irp);
365 IoDetachDevice(ext->u.fdo.hid_ext.NextDeviceObject);
366 IoDeleteDevice(device);
367 return ret;
370 default:
371 return minidriver->PNPDispatch(device, irp);
375 static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp)
377 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
378 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
379 HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc;
380 NTSTATUS status = irp->IoStatus.Status;
381 struct hid_queue *queue, *next;
382 KIRQL irql;
384 TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction);
386 switch(irpsp->MinorFunction)
388 case IRP_MN_QUERY_ID:
390 WCHAR *id = ExAllocatePool(PagedPool, sizeof(WCHAR) * REGSTR_VAL_MAX_HCID_LEN);
391 TRACE("IRP_MN_QUERY_ID[%i]\n", irpsp->Parameters.QueryId.IdType);
392 switch (irpsp->Parameters.QueryId.IdType)
394 case BusQueryHardwareIDs:
395 case BusQueryCompatibleIDs:
397 WCHAR *ptr;
398 ptr = id;
399 /* Device instance ID */
400 lstrcpyW(ptr, ext->device_id);
401 ptr += lstrlenW(ext->device_id);
402 lstrcpyW(ptr, L"\\");
403 ptr += 1;
404 lstrcpyW(ptr, ext->instance_id);
405 ptr += lstrlenW(ext->instance_id) + 1;
406 /* Device ID */
407 lstrcpyW(ptr, ext->device_id);
408 ptr += lstrlenW(ext->device_id) + 1;
409 /* Bus ID */
410 lstrcpyW(ptr, L"HID");
411 ptr += lstrlenW(L"HID") + 1;
412 *ptr = 0;
413 irp->IoStatus.Information = (ULONG_PTR)id;
414 status = STATUS_SUCCESS;
415 break;
417 case BusQueryDeviceID:
418 lstrcpyW(id, ext->device_id);
419 irp->IoStatus.Information = (ULONG_PTR)id;
420 status = STATUS_SUCCESS;
421 break;
422 case BusQueryInstanceID:
423 lstrcpyW(id, ext->instance_id);
424 irp->IoStatus.Information = (ULONG_PTR)id;
425 status = STATUS_SUCCESS;
426 break;
427 case BusQueryContainerID:
428 if (ext->container_id[0])
430 lstrcpyW(id, ext->container_id);
431 irp->IoStatus.Information = (ULONG_PTR)id;
432 status = STATUS_SUCCESS;
434 else
436 ExFreePool(id);
438 break;
440 case BusQueryDeviceSerialNumber:
441 FIXME("unimplemented id type %#x\n", irpsp->Parameters.QueryId.IdType);
442 ExFreePool(id);
443 break;
445 break;
448 case IRP_MN_QUERY_CAPABILITIES:
450 DEVICE_CAPABILITIES *caps = irpsp->Parameters.DeviceCapabilities.Capabilities;
452 caps->RawDeviceOK = 1;
453 status = STATUS_SUCCESS;
454 break;
457 case IRP_MN_START_DEVICE:
458 if ((status = IoRegisterDeviceInterface(device, ext->class_guid, NULL, &ext->u.pdo.link_name)))
460 ERR( "Failed to register interface, status %#lx.\n", status );
461 break;
464 /* FIXME: This should probably be done in mouhid.sys. */
465 if (desc->UsagePage == HID_USAGE_PAGE_GENERIC && desc->Usage == HID_USAGE_GENERIC_MOUSE)
467 if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_MOUSE, NULL, &ext->u.pdo.mouse_link_name))
468 ext->u.pdo.is_mouse = TRUE;
470 if (desc->UsagePage == HID_USAGE_PAGE_GENERIC && desc->Usage == HID_USAGE_GENERIC_KEYBOARD)
472 if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_KEYBOARD, NULL, &ext->u.pdo.keyboard_link_name))
473 ext->u.pdo.is_keyboard = TRUE;
476 IoSetDeviceInterfaceState(&ext->u.pdo.link_name, TRUE);
477 if (ext->u.pdo.is_mouse)
478 IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, TRUE);
479 if (ext->u.pdo.is_keyboard)
480 IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, TRUE);
482 ext->u.pdo.removed = FALSE;
483 status = STATUS_SUCCESS;
484 break;
486 case IRP_MN_REMOVE_DEVICE:
487 send_wm_input_device_change(ext, GIDC_REMOVAL);
489 IoSetDeviceInterfaceState(&ext->u.pdo.link_name, FALSE);
490 if (ext->u.pdo.is_mouse)
491 IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, FALSE);
492 if (ext->u.pdo.is_keyboard)
493 IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, FALSE);
495 if (ext->u.pdo.thread)
497 SetEvent(ext->u.pdo.halt_event);
498 WaitForSingleObject(ext->u.pdo.thread, INFINITE);
500 CloseHandle(ext->u.pdo.halt_event);
502 KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql );
503 LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry )
504 hid_queue_destroy( queue );
505 KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
507 HidP_FreeCollectionDescription(&ext->u.pdo.device_desc);
509 RtlFreeUnicodeString(&ext->u.pdo.link_name);
511 irp->IoStatus.Status = STATUS_SUCCESS;
512 IoCompleteRequest(irp, IO_NO_INCREMENT);
513 IoDeleteDevice(device);
514 return STATUS_SUCCESS;
516 case IRP_MN_SURPRISE_REMOVAL:
517 KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
518 ext->u.pdo.removed = TRUE;
519 KeReleaseSpinLock(&ext->u.pdo.lock, irql);
521 KeAcquireSpinLock( &ext->u.pdo.queues_lock, &irql );
522 LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry )
523 hid_queue_remove_pending_irps( queue );
524 KeReleaseSpinLock( &ext->u.pdo.queues_lock, irql );
526 SetEvent(ext->u.pdo.halt_event);
527 status = STATUS_SUCCESS;
528 break;
530 default:
531 FIXME("Unhandled minor function %#x.\n", irpsp->MinorFunction);
534 irp->IoStatus.Status = status;
535 IoCompleteRequest( irp, IO_NO_INCREMENT );
536 return status;
539 static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
541 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
543 if (ext->is_fdo)
544 return fdo_pnp(device, irp);
545 else
546 return pdo_pnp(device, irp);
549 static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp)
551 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
553 if (ext->is_fdo)
555 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
556 IoCompleteRequest(irp, IO_NO_INCREMENT);
557 return STATUS_UNSUCCESSFUL;
560 return pdo_create(device, irp);
563 static NTSTATUS WINAPI driver_close(DEVICE_OBJECT *device, IRP *irp)
565 return pdo_close(device, irp);
568 static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp)
570 return pdo_ioctl(device, irp);
573 static NTSTATUS WINAPI driver_read(DEVICE_OBJECT *device, IRP *irp)
575 return pdo_read(device, irp);
578 static NTSTATUS WINAPI driver_write(DEVICE_OBJECT *device, IRP *irp)
580 return pdo_write(device, irp);
583 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
585 minidriver *md;
587 TRACE("\n");
589 if ((md = find_minidriver(driver)))
591 if (md->DriverUnload)
592 md->DriverUnload(md->minidriver.DriverObject);
593 list_remove(&md->entry);
594 free(md);
598 NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration)
600 minidriver *driver;
602 /* make sure we have a window station and a desktop, we need one to send input */
603 if (!GetProcessWindowStation())
604 return STATUS_INVALID_PARAMETER;
606 if (!(driver = calloc(1, sizeof(*driver))))
607 return STATUS_NO_MEMORY;
609 driver->DriverUnload = registration->DriverObject->DriverUnload;
610 registration->DriverObject->DriverUnload = driver_unload;
612 registration->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl;
613 registration->DriverObject->MajorFunction[IRP_MJ_READ] = driver_read;
614 registration->DriverObject->MajorFunction[IRP_MJ_WRITE] = driver_write;
615 registration->DriverObject->MajorFunction[IRP_MJ_CREATE] = driver_create;
616 registration->DriverObject->MajorFunction[IRP_MJ_CLOSE] = driver_close;
618 driver->PNPDispatch = registration->DriverObject->MajorFunction[IRP_MJ_PNP];
619 registration->DriverObject->MajorFunction[IRP_MJ_PNP] = driver_pnp;
621 driver->AddDevice = registration->DriverObject->DriverExtension->AddDevice;
622 registration->DriverObject->DriverExtension->AddDevice = driver_add_device;
624 driver->minidriver = *registration;
625 list_add_tail(&minidriver_list, &driver->entry);
627 return STATUS_SUCCESS;
630 void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size,
631 void *out_buff, ULONG out_size, IO_STATUS_BLOCK *io )
633 IRP *irp;
634 KEVENT event;
636 KeInitializeEvent(&event, NotificationEvent, FALSE);
638 irp = IoBuildDeviceIoControlRequest( code, device, in_buff, in_size, out_buff, out_size, TRUE, &event, io );
640 if (IoCallDriver(device, irp) == STATUS_PENDING)
641 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);