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
29 #include "ddk/hidtypes.h"
33 #include "wine/debug.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,
47 "xchgl (%esp),%ecx\n\t"
50 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
54 #define call_fastcall_func1(func,a) func(a)
58 static struct list minidriver_list
= LIST_INIT(minidriver_list
);
60 static minidriver
*find_minidriver(DRIVER_OBJECT
*driver
)
63 LIST_FOR_EACH_ENTRY(md
, &minidriver_list
, minidriver
, entry
)
65 if (md
->minidriver
.DriverObject
== driver
)
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
;
78 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
79 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_PNP
, device
, NULL
, 0, NULL
, &event
, &irp_status
);
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
;
120 if (!IsEqualGUID( ext
->class_guid
, &GUID_DEVINTERFACE_HID
)) return;
122 rawinput
.header
.dwType
= RIM_TYPEHID
;
123 rawinput
.header
.dwSize
= offsetof(RAWINPUT
, data
.hid
.bRawData
[2 * sizeof(USAGE
)]);
124 rawinput
.header
.hDevice
= ULongToHandle(ext
->u
.pdo
.rawinput_handle
);
125 rawinput
.header
.wParam
= param
;
126 rawinput
.data
.hid
.dwCount
= 0;
127 rawinput
.data
.hid
.dwSizeHid
= 0;
128 ((USAGE
*)rawinput
.data
.hid
.bRawData
)[0] = desc
->UsagePage
;
129 ((USAGE
*)rawinput
.data
.hid
.bRawData
)[1] = desc
->Usage
;
131 input
.type
= INPUT_HARDWARE
;
132 input
.hi
.uMsg
= WM_INPUT_DEVICE_CHANGE
;
133 input
.hi
.wParamH
= 0;
134 input
.hi
.wParamL
= 0;
135 __wine_send_input(0, &input
, &rawinput
);
138 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*bus_pdo
)
140 WCHAR device_id
[MAX_DEVICE_ID_LEN
], instance_id
[MAX_DEVICE_ID_LEN
];
141 BASE_DEVICE_EXTENSION
*ext
;
142 BOOL is_xinput_class
;
145 minidriver
*minidriver
;
147 if ((status
= get_device_id(bus_pdo
, BusQueryDeviceID
, device_id
)))
149 ERR( "Failed to get PDO device id, status %#lx.\n", status
);
153 if ((status
= get_device_id(bus_pdo
, BusQueryInstanceID
, instance_id
)))
155 ERR( "Failed to get PDO instance id, status %#lx.\n", status
);
159 TRACE("Adding device to PDO %p, id %s\\%s.\n", bus_pdo
, debugstr_w(device_id
), debugstr_w(instance_id
));
160 minidriver
= find_minidriver(driver
);
162 if ((status
= IoCreateDevice(driver
, sizeof(*ext
) + minidriver
->minidriver
.DeviceExtensionSize
,
163 NULL
, FILE_DEVICE_BUS_EXTENDER
, 0, FALSE
, &fdo
)))
165 ERR( "Failed to create bus FDO, status %#lx.\n", status
);
168 ext
= fdo
->DeviceExtension
;
170 ext
->u
.fdo
.hid_ext
.MiniDeviceExtension
= ext
+ 1;
171 ext
->u
.fdo
.hid_ext
.PhysicalDeviceObject
= bus_pdo
;
172 ext
->u
.fdo
.hid_ext
.NextDeviceObject
= bus_pdo
;
173 swprintf(ext
->device_id
, ARRAY_SIZE(ext
->device_id
), L
"HID\\%s", wcsrchr(device_id
, '\\') + 1);
174 wcscpy(ext
->instance_id
, instance_id
);
176 if (get_device_id(bus_pdo
, BusQueryContainerID
, ext
->container_id
))
177 ext
->container_id
[0] = 0;
179 is_xinput_class
= !wcsncmp(device_id
, L
"WINEXINPUT\\", 7) && wcsstr(device_id
, L
"&XI_") != NULL
;
180 if (is_xinput_class
) ext
->class_guid
= &GUID_DEVINTERFACE_WINEXINPUT
;
181 else ext
->class_guid
= &GUID_DEVINTERFACE_HID
;
183 status
= minidriver
->AddDevice(minidriver
->minidriver
.DriverObject
, fdo
);
184 if (status
!= STATUS_SUCCESS
)
186 ERR( "Minidriver AddDevice failed (%lx)\n", status
);
191 IoAttachDeviceToDeviceStack(fdo
, bus_pdo
);
192 fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
194 return STATUS_SUCCESS
;
197 static void create_child(minidriver
*minidriver
, DEVICE_OBJECT
*fdo
)
199 BASE_DEVICE_EXTENSION
*fdo_ext
= fdo
->DeviceExtension
, *pdo_ext
;
200 HID_DEVICE_ATTRIBUTES attr
= {0};
201 HID_DESCRIPTOR descriptor
= {0};
202 HIDP_COLLECTION_DESC
*desc
;
203 DEVICE_OBJECT
*child_pdo
;
204 BYTE
*reportDescriptor
;
205 UNICODE_STRING string
;
212 call_minidriver( IOCTL_HID_GET_DEVICE_ATTRIBUTES
, fdo
, NULL
, 0, &attr
, sizeof(attr
), &io
);
213 if (io
.Status
!= STATUS_SUCCESS
)
215 ERR( "Minidriver failed to get attributes, status %#lx.\n", io
.Status
);
219 swprintf(pdo_name
, ARRAY_SIZE(pdo_name
), L
"\\Device\\HID#%p&%p", fdo
->DriverObject
,
220 fdo_ext
->u
.fdo
.hid_ext
.PhysicalDeviceObject
);
221 RtlInitUnicodeString(&string
, pdo_name
);
222 if ((status
= IoCreateDevice(fdo
->DriverObject
, sizeof(*pdo_ext
), &string
, 0, 0, FALSE
, &child_pdo
)))
224 ERR( "Failed to create child PDO, status %#lx.\n", io
.Status
);
227 fdo_ext
->u
.fdo
.child_pdo
= child_pdo
;
229 pdo_ext
= child_pdo
->DeviceExtension
;
230 pdo_ext
->u
.pdo
.parent_fdo
= fdo
;
231 list_init( &pdo_ext
->u
.pdo
.queues
);
232 KeInitializeSpinLock( &pdo_ext
->u
.pdo
.queues_lock
);
233 wcscpy(pdo_ext
->device_id
, fdo_ext
->device_id
);
234 wcscpy(pdo_ext
->instance_id
, fdo_ext
->instance_id
);
235 wcscpy(pdo_ext
->container_id
, fdo_ext
->container_id
);
236 pdo_ext
->class_guid
= fdo_ext
->class_guid
;
238 pdo_ext
->u
.pdo
.information
.VendorID
= attr
.VendorID
;
239 pdo_ext
->u
.pdo
.information
.ProductID
= attr
.ProductID
;
240 pdo_ext
->u
.pdo
.information
.VersionNumber
= attr
.VersionNumber
;
241 pdo_ext
->u
.pdo
.information
.Polled
= minidriver
->minidriver
.DevicesArePolled
;
243 call_minidriver( IOCTL_HID_GET_DEVICE_DESCRIPTOR
, fdo
, NULL
, 0, &descriptor
, sizeof(descriptor
), &io
);
244 if (io
.Status
!= STATUS_SUCCESS
)
246 ERR( "Cannot get Device Descriptor, status %#lx\n", status
);
247 IoDeleteDevice(child_pdo
);
250 for (i
= 0; i
< descriptor
.bNumDescriptors
; i
++)
251 if (descriptor
.DescriptorList
[i
].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
)
254 if (i
>= descriptor
.bNumDescriptors
)
256 ERR("No Report Descriptor found in reply\n");
257 IoDeleteDevice(child_pdo
);
261 reportDescriptor
= malloc(descriptor
.DescriptorList
[i
].wReportLength
);
262 call_minidriver( IOCTL_HID_GET_REPORT_DESCRIPTOR
, fdo
, NULL
, 0, reportDescriptor
,
263 descriptor
.DescriptorList
[i
].wReportLength
, &io
);
264 if (io
.Status
!= STATUS_SUCCESS
)
266 ERR( "Cannot get Report Descriptor, status %#lx\n", status
);
267 free(reportDescriptor
);
268 IoDeleteDevice(child_pdo
);
272 io
.Status
= HidP_GetCollectionDescription( reportDescriptor
, descriptor
.DescriptorList
[i
].wReportLength
,
273 PagedPool
, &pdo_ext
->u
.pdo
.device_desc
);
274 free(reportDescriptor
);
275 if (io
.Status
!= HIDP_STATUS_SUCCESS
)
277 ERR("Cannot parse Report Descriptor\n");
278 IoDeleteDevice(child_pdo
);
282 desc
= pdo_ext
->u
.pdo
.device_desc
.CollectionDesc
;
283 pdo_ext
->u
.pdo
.information
.DescriptorSize
= desc
->PreparsedDataLength
;
285 page
= desc
->UsagePage
;
287 if (page
== HID_USAGE_PAGE_GENERIC
&& usage
== HID_USAGE_GENERIC_MOUSE
)
288 pdo_ext
->u
.pdo
.rawinput_handle
= WINE_MOUSE_HANDLE
;
289 else if (page
== HID_USAGE_PAGE_GENERIC
&& usage
== HID_USAGE_GENERIC_KEYBOARD
)
290 pdo_ext
->u
.pdo
.rawinput_handle
= WINE_KEYBOARD_HANDLE
;
292 pdo_ext
->u
.pdo
.rawinput_handle
= alloc_rawinput_handle();
294 IoInvalidateDeviceRelations(fdo_ext
->u
.fdo
.hid_ext
.PhysicalDeviceObject
, BusRelations
);
296 pdo_ext
->u
.pdo
.poll_interval
= DEFAULT_POLL_INTERVAL
;
298 HID_StartDeviceThread(child_pdo
);
300 send_wm_input_device_change(pdo_ext
, GIDC_ARRIVAL
);
303 static NTSTATUS
fdo_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
305 minidriver
*minidriver
= find_minidriver(device
->DriverObject
);
306 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
307 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
309 TRACE("irp %p, minor function %#x.\n", irp
, stack
->MinorFunction
);
311 switch (stack
->MinorFunction
)
313 case IRP_MN_QUERY_DEVICE_RELATIONS
:
315 DEVICE_RELATIONS
*devices
;
316 DEVICE_OBJECT
*child
;
318 if (stack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
319 return minidriver
->PNPDispatch(device
, irp
);
321 if (!(devices
= ExAllocatePool(PagedPool
, offsetof(DEVICE_RELATIONS
, Objects
[1]))))
323 irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
324 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
325 return STATUS_NO_MEMORY
;
328 if ((child
= ext
->u
.fdo
.child_pdo
))
330 devices
->Objects
[0] = ext
->u
.fdo
.child_pdo
;
331 call_fastcall_func1(ObfReferenceObject
, ext
->u
.fdo
.child_pdo
);
339 irp
->IoStatus
.Information
= (ULONG_PTR
)devices
;
340 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
341 IoSkipCurrentIrpStackLocation(irp
);
342 return IoCallDriver(ext
->u
.fdo
.hid_ext
.NextDeviceObject
, irp
);
345 case IRP_MN_START_DEVICE
:
349 if ((ret
= minidriver
->PNPDispatch(device
, irp
)))
351 create_child(minidriver
, device
);
352 return STATUS_SUCCESS
;
355 case IRP_MN_REMOVE_DEVICE
:
359 ret
= minidriver
->PNPDispatch(device
, irp
);
361 IoDetachDevice(ext
->u
.fdo
.hid_ext
.NextDeviceObject
);
362 IoDeleteDevice(device
);
367 return minidriver
->PNPDispatch(device
, irp
);
371 static NTSTATUS
pdo_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
373 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
374 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
375 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
376 NTSTATUS status
= irp
->IoStatus
.Status
;
377 struct hid_queue
*queue
, *next
;
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
:
395 /* Device instance ID */
396 lstrcpyW(ptr
, ext
->device_id
);
397 ptr
+= lstrlenW(ext
->device_id
);
398 lstrcpyW(ptr
, L
"\\");
400 lstrcpyW(ptr
, ext
->instance_id
);
401 ptr
+= lstrlenW(ext
->instance_id
) + 1;
403 lstrcpyW(ptr
, ext
->device_id
);
404 ptr
+= lstrlenW(ext
->device_id
) + 1;
406 lstrcpyW(ptr
, L
"HID");
407 ptr
+= lstrlenW(L
"HID") + 1;
409 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
410 status
= STATUS_SUCCESS
;
413 case BusQueryDeviceID
:
414 lstrcpyW(id
, ext
->device_id
);
415 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
416 status
= STATUS_SUCCESS
;
418 case BusQueryInstanceID
:
419 lstrcpyW(id
, ext
->instance_id
);
420 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
421 status
= STATUS_SUCCESS
;
423 case BusQueryContainerID
:
424 if (ext
->container_id
[0])
426 lstrcpyW(id
, ext
->container_id
);
427 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
428 status
= STATUS_SUCCESS
;
436 case BusQueryDeviceSerialNumber
:
437 FIXME("unimplemented id type %#x\n", irpsp
->Parameters
.QueryId
.IdType
);
444 case IRP_MN_QUERY_CAPABILITIES
:
446 DEVICE_CAPABILITIES
*caps
= irpsp
->Parameters
.DeviceCapabilities
.Capabilities
;
448 caps
->RawDeviceOK
= 1;
449 status
= STATUS_SUCCESS
;
453 case IRP_MN_START_DEVICE
:
454 if ((status
= IoRegisterDeviceInterface(device
, ext
->class_guid
, NULL
, &ext
->u
.pdo
.link_name
)))
456 ERR( "Failed to register interface, status %#lx.\n", status
);
460 /* FIXME: This should probably be done in mouhid.sys. */
461 if (desc
->UsagePage
== HID_USAGE_PAGE_GENERIC
&& desc
->Usage
== HID_USAGE_GENERIC_MOUSE
)
463 if (!IoRegisterDeviceInterface(device
, &GUID_DEVINTERFACE_MOUSE
, NULL
, &ext
->u
.pdo
.mouse_link_name
))
464 ext
->u
.pdo
.is_mouse
= TRUE
;
466 if (desc
->UsagePage
== HID_USAGE_PAGE_GENERIC
&& desc
->Usage
== HID_USAGE_GENERIC_KEYBOARD
)
468 if (!IoRegisterDeviceInterface(device
, &GUID_DEVINTERFACE_KEYBOARD
, NULL
, &ext
->u
.pdo
.keyboard_link_name
))
469 ext
->u
.pdo
.is_keyboard
= TRUE
;
472 IoSetDeviceInterfaceState(&ext
->u
.pdo
.link_name
, TRUE
);
473 if (ext
->u
.pdo
.is_mouse
)
474 IoSetDeviceInterfaceState(&ext
->u
.pdo
.mouse_link_name
, TRUE
);
475 if (ext
->u
.pdo
.is_keyboard
)
476 IoSetDeviceInterfaceState(&ext
->u
.pdo
.keyboard_link_name
, TRUE
);
478 ext
->u
.pdo
.removed
= FALSE
;
479 status
= STATUS_SUCCESS
;
482 case IRP_MN_REMOVE_DEVICE
:
483 send_wm_input_device_change(ext
, GIDC_REMOVAL
);
485 IoSetDeviceInterfaceState(&ext
->u
.pdo
.link_name
, FALSE
);
486 if (ext
->u
.pdo
.is_mouse
)
487 IoSetDeviceInterfaceState(&ext
->u
.pdo
.mouse_link_name
, FALSE
);
488 if (ext
->u
.pdo
.is_keyboard
)
489 IoSetDeviceInterfaceState(&ext
->u
.pdo
.keyboard_link_name
, FALSE
);
491 if (ext
->u
.pdo
.thread
)
493 SetEvent(ext
->u
.pdo
.halt_event
);
494 WaitForSingleObject(ext
->u
.pdo
.thread
, INFINITE
);
496 CloseHandle(ext
->u
.pdo
.halt_event
);
498 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
499 LIST_FOR_EACH_ENTRY_SAFE( queue
, next
, &ext
->u
.pdo
.queues
, struct hid_queue
, entry
)
500 hid_queue_destroy( queue
);
501 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
503 HidP_FreeCollectionDescription(&ext
->u
.pdo
.device_desc
);
505 RtlFreeUnicodeString(&ext
->u
.pdo
.link_name
);
507 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
508 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
509 IoDeleteDevice(device
);
510 return STATUS_SUCCESS
;
512 case IRP_MN_SURPRISE_REMOVAL
:
513 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
514 ext
->u
.pdo
.removed
= TRUE
;
515 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
517 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
518 LIST_FOR_EACH_ENTRY_SAFE( queue
, next
, &ext
->u
.pdo
.queues
, struct hid_queue
, entry
)
519 hid_queue_remove_pending_irps( queue
);
520 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
522 SetEvent(ext
->u
.pdo
.halt_event
);
523 status
= STATUS_SUCCESS
;
527 FIXME("Unhandled minor function %#x.\n", irpsp
->MinorFunction
);
530 irp
->IoStatus
.Status
= status
;
531 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
535 static NTSTATUS WINAPI
driver_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
537 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
540 return fdo_pnp(device
, irp
);
542 return pdo_pnp(device
, irp
);
545 static NTSTATUS WINAPI
driver_create(DEVICE_OBJECT
*device
, IRP
*irp
)
547 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
551 irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
552 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
553 return STATUS_UNSUCCESSFUL
;
556 return pdo_create(device
, irp
);
559 static NTSTATUS WINAPI
driver_close(DEVICE_OBJECT
*device
, IRP
*irp
)
561 return pdo_close(device
, irp
);
564 static NTSTATUS WINAPI
driver_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
566 return pdo_ioctl(device
, irp
);
569 static NTSTATUS WINAPI
driver_read(DEVICE_OBJECT
*device
, IRP
*irp
)
571 return pdo_read(device
, irp
);
574 static NTSTATUS WINAPI
driver_write(DEVICE_OBJECT
*device
, IRP
*irp
)
576 return pdo_write(device
, irp
);
579 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
585 if ((md
= find_minidriver(driver
)))
587 if (md
->DriverUnload
)
588 md
->DriverUnload(md
->minidriver
.DriverObject
);
589 list_remove(&md
->entry
);
594 NTSTATUS WINAPI
HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION
*registration
)
598 if (!(driver
= calloc(1, sizeof(*driver
))))
599 return STATUS_NO_MEMORY
;
601 driver
->DriverUnload
= registration
->DriverObject
->DriverUnload
;
602 registration
->DriverObject
->DriverUnload
= driver_unload
;
604 registration
->DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = driver_ioctl
;
605 registration
->DriverObject
->MajorFunction
[IRP_MJ_READ
] = driver_read
;
606 registration
->DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = driver_write
;
607 registration
->DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = driver_create
;
608 registration
->DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = driver_close
;
610 driver
->PNPDispatch
= registration
->DriverObject
->MajorFunction
[IRP_MJ_PNP
];
611 registration
->DriverObject
->MajorFunction
[IRP_MJ_PNP
] = driver_pnp
;
613 driver
->AddDevice
= registration
->DriverObject
->DriverExtension
->AddDevice
;
614 registration
->DriverObject
->DriverExtension
->AddDevice
= driver_add_device
;
616 driver
->minidriver
= *registration
;
617 list_add_tail(&minidriver_list
, &driver
->entry
);
619 return STATUS_SUCCESS
;
622 void call_minidriver( ULONG code
, DEVICE_OBJECT
*device
, void *in_buff
, ULONG in_size
,
623 void *out_buff
, ULONG out_size
, IO_STATUS_BLOCK
*io
)
628 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
630 irp
= IoBuildDeviceIoControlRequest( code
, device
, in_buff
, in_size
, out_buff
, out_size
, TRUE
, &event
, io
);
632 if (IoCallDriver(device
, irp
) == STATUS_PENDING
)
633 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);