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 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
;
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
);
155 if ((status
= get_device_id(bus_pdo
, BusQueryInstanceID
, instance_id
)))
157 ERR( "Failed to get PDO instance id, status %#lx.\n", 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
);
170 ext
= fdo
->DeviceExtension
;
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
);
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
;
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
);
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
);
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
);
252 for (i
= 0; i
< descriptor
.bNumDescriptors
; i
++)
253 if (descriptor
.DescriptorList
[i
].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
)
256 if (i
>= descriptor
.bNumDescriptors
)
258 ERR("No Report Descriptor found in reply\n");
259 IoDeleteDevice(child_pdo
);
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
);
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
);
284 desc
= pdo_ext
->u
.pdo
.device_desc
.CollectionDesc
;
285 pdo_ext
->u
.pdo
.information
.DescriptorSize
= desc
->PreparsedDataLength
;
287 page
= desc
->UsagePage
;
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
;
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
);
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
:
353 if ((ret
= minidriver
->PNPDispatch(device
, irp
)))
355 create_child(minidriver
, device
);
356 return STATUS_SUCCESS
;
359 case IRP_MN_REMOVE_DEVICE
:
363 ret
= minidriver
->PNPDispatch(device
, irp
);
365 IoDetachDevice(ext
->u
.fdo
.hid_ext
.NextDeviceObject
);
366 IoDeleteDevice(device
);
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
;
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
:
399 /* Device instance ID */
400 lstrcpyW(ptr
, ext
->device_id
);
401 ptr
+= lstrlenW(ext
->device_id
);
402 lstrcpyW(ptr
, L
"\\");
404 lstrcpyW(ptr
, ext
->instance_id
);
405 ptr
+= lstrlenW(ext
->instance_id
) + 1;
407 lstrcpyW(ptr
, ext
->device_id
);
408 ptr
+= lstrlenW(ext
->device_id
) + 1;
410 lstrcpyW(ptr
, L
"HID");
411 ptr
+= lstrlenW(L
"HID") + 1;
413 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
414 status
= STATUS_SUCCESS
;
417 case BusQueryDeviceID
:
418 lstrcpyW(id
, ext
->device_id
);
419 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
420 status
= STATUS_SUCCESS
;
422 case BusQueryInstanceID
:
423 lstrcpyW(id
, ext
->instance_id
);
424 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
425 status
= STATUS_SUCCESS
;
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
;
440 case BusQueryDeviceSerialNumber
:
441 FIXME("unimplemented id type %#x\n", irpsp
->Parameters
.QueryId
.IdType
);
448 case IRP_MN_QUERY_CAPABILITIES
:
450 DEVICE_CAPABILITIES
*caps
= irpsp
->Parameters
.DeviceCapabilities
.Capabilities
;
452 caps
->RawDeviceOK
= 1;
453 status
= STATUS_SUCCESS
;
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
);
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
;
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
;
531 FIXME("Unhandled minor function %#x.\n", irpsp
->MinorFunction
);
534 irp
->IoStatus
.Status
= status
;
535 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
539 static NTSTATUS WINAPI
driver_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
541 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
544 return fdo_pnp(device
, irp
);
546 return pdo_pnp(device
, irp
);
549 static NTSTATUS WINAPI
driver_create(DEVICE_OBJECT
*device
, IRP
*irp
)
551 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
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
)
589 if ((md
= find_minidriver(driver
)))
591 if (md
->DriverUnload
)
592 md
->DriverUnload(md
->minidriver
.DriverObject
);
593 list_remove(&md
->entry
);
598 NTSTATUS WINAPI
HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION
*registration
)
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
)
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
);