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
30 #include "ddk/hidtypes.h"
34 #include "wine/debug.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,
48 "xchgl (%esp),%ecx\n\t"
51 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
55 #define call_fastcall_func1(func,a) func(a)
59 static struct list minidriver_list
= LIST_INIT(minidriver_list
);
61 static minidriver
*find_minidriver(DRIVER_OBJECT
*driver
)
64 LIST_FOR_EACH_ENTRY(md
, &minidriver_list
, minidriver
, entry
)
66 if (md
->minidriver
.DriverObject
== driver
)
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
;
79 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
80 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_PNP
, device
, NULL
, 0, NULL
, &event
, &irp_status
);
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
)
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
;
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
);
145 if ((status
= get_device_id(bus_pdo
, BusQueryInstanceID
, instance_id
)))
147 ERR("Failed to get PDO instance id, status %#x.\n", 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
);
160 ext
= fdo
->DeviceExtension
;
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
);
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
;
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
);
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
);
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
);
231 for (i
= 0; i
< descriptor
.bNumDescriptors
; i
++)
232 if (descriptor
.DescriptorList
[i
].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
)
235 if (i
>= descriptor
.bNumDescriptors
)
237 ERR("No Report Descriptor found in reply\n");
238 IoDeleteDevice(child_pdo
);
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
);
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
);
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
;
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
);
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
);
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
:
340 if ((ret
= minidriver
->PNPDispatch(device
, irp
)))
342 create_child(minidriver
, device
);
343 return STATUS_SUCCESS
;
346 case IRP_MN_REMOVE_DEVICE
:
350 ret
= minidriver
->PNPDispatch(device
, irp
);
352 IoDetachDevice(ext
->u
.fdo
.hid_ext
.NextDeviceObject
);
353 IoDeleteDevice(device
);
358 return minidriver
->PNPDispatch(device
, irp
);
362 static void remove_pending_irps(BASE_DEVICE_EXTENSION
*ext
)
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
;
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
;
424 case BusQueryContainerID
:
425 case BusQueryDeviceSerialNumber
:
426 FIXME("unimplemented id type %#x\n", irpsp
->Parameters
.QueryId
.IdType
);
433 case IRP_MN_QUERY_CAPABILITIES
:
435 DEVICE_CAPABILITIES
*caps
= irpsp
->Parameters
.DeviceCapabilities
.Capabilities
;
437 caps
->RawDeviceOK
= 1;
438 status
= STATUS_SUCCESS
;
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
);
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
;
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
;
514 FIXME("Unhandled minor function %#x.\n", irpsp
->MinorFunction
);
517 irp
->IoStatus
.Status
= status
;
518 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
522 static NTSTATUS WINAPI
driver_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
524 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
527 return fdo_pnp(device
, irp
);
529 return pdo_pnp(device
, irp
);
532 static NTSTATUS WINAPI
driver_create(DEVICE_OBJECT
*device
, IRP
*irp
)
534 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
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
)
572 if ((md
= find_minidriver(driver
)))
574 if (md
->DriverUnload
)
575 md
->DriverUnload(md
->minidriver
.DriverObject
);
576 list_remove(&md
->entry
);
581 NTSTATUS WINAPI
HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION
*registration
)
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
)
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
);