* Sync up to trunk head (r64939).
[reactos.git] / drivers / input / kbdclass / kbdclass.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Keyboard class driver
4 * FILE: drivers/kbdclass/kbdclass.c
5 * PURPOSE: Keyboard class driver
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 #include "kbdclass.h"
11
12 #include <stdio.h>
13 #include <pseh/pseh2.h>
14 #include <kbdmou.h>
15 #include <debug.h>
16
17 static DRIVER_UNLOAD DriverUnload;
18 static DRIVER_DISPATCH ClassCreate;
19 static DRIVER_DISPATCH ClassClose;
20 static DRIVER_DISPATCH ClassCleanup;
21 static DRIVER_DISPATCH ClassRead;
22 static DRIVER_DISPATCH ClassDeviceControl;
23 static DRIVER_DISPATCH IrpStub;
24 static DRIVER_ADD_DEVICE ClassAddDevice;
25 static DRIVER_STARTIO ClassStartIo;
26 static DRIVER_CANCEL ClassCancelRoutine;
27 static NTSTATUS
28 HandleReadIrp(
29 IN PDEVICE_OBJECT DeviceObject,
30 IN PIRP Irp,
31 BOOLEAN IsInStartIo);
32
33 static VOID NTAPI
34 DriverUnload(IN PDRIVER_OBJECT DriverObject)
35 {
36 // nothing to do here yet
37 }
38
39 static NTSTATUS NTAPI
40 ClassCreate(
41 IN PDEVICE_OBJECT DeviceObject,
42 IN PIRP Irp)
43 {
44 TRACE_(CLASS_NAME, "IRP_MJ_CREATE\n");
45
46 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
47 return ForwardIrpAndForget(DeviceObject, Irp);
48
49 /* FIXME: open all associated Port devices */
50 Irp->IoStatus.Status = STATUS_SUCCESS;
51 Irp->IoStatus.Information = 0;
52 IoCompleteRequest(Irp, IO_NO_INCREMENT);
53 return STATUS_SUCCESS;
54 }
55
56 static NTSTATUS NTAPI
57 ClassClose(
58 IN PDEVICE_OBJECT DeviceObject,
59 IN PIRP Irp)
60 {
61 TRACE_(CLASS_NAME, "IRP_MJ_CLOSE\n");
62
63 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
64 return ForwardIrpAndForget(DeviceObject, Irp);
65
66 /* FIXME: close all associated Port devices */
67 Irp->IoStatus.Status = STATUS_SUCCESS;
68 Irp->IoStatus.Information = 0;
69 IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 return STATUS_SUCCESS;
71 }
72
73 static NTSTATUS NTAPI
74 ClassCleanup(
75 IN PDEVICE_OBJECT DeviceObject,
76 IN PIRP Irp)
77 {
78 TRACE_(CLASS_NAME, "IRP_MJ_CLEANUP\n");
79
80 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
81 return ForwardIrpAndForget(DeviceObject, Irp);
82
83 /* FIXME: cleanup all associated Port devices */
84 Irp->IoStatus.Status = STATUS_SUCCESS;
85 Irp->IoStatus.Information = 0;
86 IoCompleteRequest(Irp, IO_NO_INCREMENT);
87 return STATUS_SUCCESS;
88 }
89
90 static NTSTATUS NTAPI
91 ClassRead(
92 IN PDEVICE_OBJECT DeviceObject,
93 IN PIRP Irp)
94 {
95 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
96 KIRQL OldIrql;
97 NTSTATUS Status;
98
99 TRACE_(CLASS_NAME, "IRP_MJ_READ\n");
100
101 ASSERT(DeviceExtension->Common.IsClassDO);
102
103 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
104 return ForwardIrpAndForget(DeviceObject, Irp);
105
106 if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA))
107 {
108 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
109 Irp->IoStatus.Information = 0;
110 IoCompleteRequest(Irp, IO_NO_INCREMENT);
111
112 return STATUS_BUFFER_TOO_SMALL;
113 }
114
115 KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
116 Status = HandleReadIrp(DeviceObject, Irp, FALSE);
117 KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
118 return Status;
119 }
120
121 static NTSTATUS NTAPI
122 ClassDeviceControl(
123 IN PDEVICE_OBJECT DeviceObject,
124 IN PIRP Irp)
125 {
126 //PCLASS_DEVICE_EXTENSION DeviceExtension;
127 NTSTATUS Status = STATUS_NOT_SUPPORTED;
128
129 TRACE_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL\n");
130
131 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
132 return ForwardIrpAndForget(DeviceObject, Irp);
133
134 //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
135
136 switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
137 {
138 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
139 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
140 case IOCTL_KEYBOARD_QUERY_INDICATORS:
141 case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
142 {
143 /* FIXME: We hope that all devices will return the same result.
144 * Ask only the first one */
145 PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
146 if (Head->Flink != Head)
147 {
148 /* We have at least one device */
149 PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, PORT_DEVICE_EXTENSION, ListEntry);
150 IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
151 IoSkipCurrentIrpStackLocation(Irp);
152 return IoCallDriver(DevExt->DeviceObject, Irp);
153 }
154 break;
155 }
156 case IOCTL_KEYBOARD_SET_INDICATORS:
157 case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
158 {
159 /* Send it to all associated Port devices */
160 PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
161 PLIST_ENTRY Entry = Head->Flink;
162 Status = STATUS_SUCCESS;
163 while (Entry != Head)
164 {
165 PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Entry, PORT_DEVICE_EXTENSION, ListEntry);
166 NTSTATUS IntermediateStatus;
167
168 IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
169 IntermediateStatus = ForwardIrpAndWait(DevExt->DeviceObject, Irp);
170 if (!NT_SUCCESS(IntermediateStatus))
171 Status = IntermediateStatus;
172 Entry = Entry->Flink;
173 }
174 break;
175 }
176 default:
177 WARN_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
178 IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
179 ASSERT(FALSE);
180 break;
181 }
182
183 Irp->IoStatus.Status = Status;
184 Irp->IoStatus.Information = 0;
185 IoCompleteRequest(Irp, IO_NO_INCREMENT);
186
187 return Status;
188 }
189
190 static NTSTATUS NTAPI
191 IrpStub(
192 IN PDEVICE_OBJECT DeviceObject,
193 IN PIRP Irp)
194 {
195 NTSTATUS Status = STATUS_NOT_SUPPORTED;
196
197 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
198 {
199 /* Forward some IRPs to lower device */
200 switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
201 {
202 case IRP_MJ_PNP:
203 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
204 return ForwardIrpAndForget(DeviceObject, Irp);
205 default:
206 {
207 ERR_(CLASS_NAME, "Port DO stub for major function 0x%lx\n",
208 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
209 ASSERT(FALSE);
210 }
211 }
212 }
213 else
214 {
215 ERR_(CLASS_NAME, "Class DO stub for major function 0x%lx\n",
216 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
217 ASSERT(FALSE);
218 }
219
220 Irp->IoStatus.Status = Status;
221 IoCompleteRequest(Irp, IO_NO_INCREMENT);
222 return Status;
223 }
224
225 static NTSTATUS
226 ReadRegistryEntries(
227 IN PUNICODE_STRING RegistryPath,
228 IN PCLASS_DRIVER_EXTENSION DriverExtension)
229 {
230 UNICODE_STRING ParametersRegistryKey;
231 RTL_QUERY_REGISTRY_TABLE Parameters[4];
232 NTSTATUS Status;
233
234 /* HACK: We don't support multiple devices with this disabled */
235 ULONG DefaultConnectMultiplePorts = 1;
236 ULONG DefaultDataQueueSize = 0x64;
237 PCWSTR DefaultDeviceBaseName = L"KeyboardClass";
238
239 ParametersRegistryKey.Length = 0;
240 ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
241 ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, CLASS_TAG);
242 if (!ParametersRegistryKey.Buffer)
243 {
244 WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
245 return STATUS_NO_MEMORY;
246 }
247 RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
248 RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
249 ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
250
251 RtlZeroMemory(Parameters, sizeof(Parameters));
252
253 Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
254 Parameters[0].Name = L"ConnectMultiplePorts";
255 Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
256 Parameters[0].DefaultType = REG_DWORD;
257 Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
258 Parameters[0].DefaultLength = sizeof(ULONG);
259
260 Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
261 Parameters[1].Name = L"KeyboardDataQueueSize";
262 Parameters[1].EntryContext = &DriverExtension->DataQueueSize;
263 Parameters[1].DefaultType = REG_DWORD;
264 Parameters[1].DefaultData = &DefaultDataQueueSize;
265 Parameters[1].DefaultLength = sizeof(ULONG);
266
267 Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
268 Parameters[2].Name = L"KeyboardDeviceBaseName";
269 Parameters[2].EntryContext = &DriverExtension->DeviceBaseName;
270 Parameters[2].DefaultType = REG_SZ;
271 Parameters[2].DefaultData = (PVOID)DefaultDeviceBaseName;
272 Parameters[2].DefaultLength = 0;
273
274 Status = RtlQueryRegistryValues(
275 RTL_REGISTRY_ABSOLUTE,
276 ParametersRegistryKey.Buffer,
277 Parameters,
278 NULL,
279 NULL);
280
281 if (NT_SUCCESS(Status))
282 {
283 /* Check values */
284 if (DriverExtension->ConnectMultiplePorts != 0
285 && DriverExtension->ConnectMultiplePorts != 1)
286 {
287 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
288 }
289 if (DriverExtension->DataQueueSize == 0)
290 {
291 DriverExtension->DataQueueSize = DefaultDataQueueSize;
292 }
293 }
294 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
295 {
296 /* Registry path doesn't exist. Set defaults */
297 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
298 DriverExtension->DataQueueSize = DefaultDataQueueSize;
299 if (RtlCreateUnicodeString(&DriverExtension->DeviceBaseName, DefaultDeviceBaseName))
300 Status = STATUS_SUCCESS;
301 else
302 Status = STATUS_NO_MEMORY;
303 }
304
305 ExFreePoolWithTag(ParametersRegistryKey.Buffer, CLASS_TAG);
306 return Status;
307 }
308
309 static NTSTATUS
310 CreateClassDeviceObject(
311 IN PDRIVER_OBJECT DriverObject,
312 OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
313 {
314 PCLASS_DRIVER_EXTENSION DriverExtension;
315 ULONG DeviceId = 0;
316 ULONG PrefixLength;
317 UNICODE_STRING DeviceNameU;
318 PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
319 PDEVICE_OBJECT Fdo;
320 PCLASS_DEVICE_EXTENSION DeviceExtension;
321 NTSTATUS Status;
322
323 TRACE_(CLASS_NAME, "CreateClassDeviceObject(0x%p)\n", DriverObject);
324
325 /* Create new device object */
326 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
327 DeviceNameU.Length = 0;
328 DeviceNameU.MaximumLength =
329 wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */
330 + DriverExtension->DeviceBaseName.Length /* "KeyboardClass" */
331 + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */
332 + sizeof(UNICODE_NULL); /* Final NULL char */
333 DeviceNameU.Buffer = ExAllocatePoolWithTag(PagedPool, DeviceNameU.MaximumLength, CLASS_TAG);
334 if (!DeviceNameU.Buffer)
335 {
336 WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
337 return STATUS_NO_MEMORY;
338 }
339 Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
340 if (!NT_SUCCESS(Status))
341 {
342 WARN_(CLASS_NAME, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
343 goto cleanup;
344 }
345 Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName);
346 if (!NT_SUCCESS(Status))
347 {
348 WARN_(CLASS_NAME, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
349 goto cleanup;
350 }
351 PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
352 DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
353 while (DeviceId < 9999)
354 {
355 DeviceNameU.Length = (USHORT)(PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR));
356 Status = IoCreateDevice(
357 DriverObject,
358 sizeof(CLASS_DEVICE_EXTENSION),
359 &DeviceNameU,
360 FILE_DEVICE_KEYBOARD,
361 FILE_DEVICE_SECURE_OPEN,
362 FALSE,
363 &Fdo);
364 if (NT_SUCCESS(Status))
365 goto cleanup;
366 else if (Status != STATUS_OBJECT_NAME_COLLISION)
367 {
368 WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
369 goto cleanup;
370 }
371 DeviceId++;
372 }
373 WARN_(CLASS_NAME, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName);
374 Status = STATUS_TOO_MANY_NAMES;
375 cleanup:
376 if (!NT_SUCCESS(Status))
377 {
378 ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
379 return Status;
380 }
381
382 DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
383 RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
384 DeviceExtension->Common.IsClassDO = TRUE;
385 DeviceExtension->DriverExtension = DriverExtension;
386 InitializeListHead(&DeviceExtension->ListHead);
387 KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
388 KeInitializeSpinLock(&DeviceExtension->SpinLock);
389 DeviceExtension->InputCount = 0;
390 DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA), CLASS_TAG);
391 if (!DeviceExtension->PortData)
392 {
393 ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
394 return STATUS_NO_MEMORY;
395 }
396 DeviceExtension->DeviceName = DeviceNameU.Buffer;
397 Fdo->Flags |= DO_POWER_PAGABLE;
398 Fdo->Flags |= DO_BUFFERED_IO; /* FIXME: Why is it needed for 1st stage setup? */
399 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
400
401 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
402 RtlWriteRegistryValue(
403 RTL_REGISTRY_DEVICEMAP,
404 DriverExtension->DeviceBaseName.Buffer,
405 DeviceExtension->DeviceName,
406 REG_SZ,
407 DriverExtension->RegistryPath.Buffer,
408 DriverExtension->RegistryPath.MaximumLength);
409
410 if (ClassDO)
411 *ClassDO = Fdo;
412
413 return STATUS_SUCCESS;
414 }
415
416 static NTSTATUS
417 FillEntries(
418 IN PDEVICE_OBJECT ClassDeviceObject,
419 IN PIRP Irp,
420 IN PKEYBOARD_INPUT_DATA DataStart,
421 IN SIZE_T NumberOfEntries)
422 {
423 NTSTATUS Status = STATUS_SUCCESS;
424
425 if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
426 {
427 RtlCopyMemory(
428 Irp->AssociatedIrp.SystemBuffer,
429 DataStart,
430 NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
431 }
432 else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
433 {
434 PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
435 if (DestAddress)
436 {
437 RtlCopyMemory(
438 DestAddress,
439 DataStart,
440 NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
441 }
442 else
443 Status = STATUS_UNSUCCESSFUL;
444 }
445 else
446 {
447 _SEH2_TRY
448 {
449 RtlCopyMemory(
450 Irp->UserBuffer,
451 DataStart,
452 NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
453 }
454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
455 {
456 Status = _SEH2_GetExceptionCode();
457 }
458 _SEH2_END;
459 }
460
461 return Status;
462 }
463
464 static BOOLEAN NTAPI
465 ClassCallback(
466 IN PDEVICE_OBJECT ClassDeviceObject,
467 IN OUT PKEYBOARD_INPUT_DATA DataStart,
468 IN PKEYBOARD_INPUT_DATA DataEnd,
469 IN OUT PULONG ConsumedCount)
470 {
471 PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
472 KIRQL OldIrql;
473 SIZE_T InputCount = DataEnd - DataStart;
474 SIZE_T ReadSize;
475
476 TRACE_(CLASS_NAME, "ClassCallback()\n");
477
478 ASSERT(ClassDeviceExtension->Common.IsClassDO);
479
480 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
481 if (InputCount > 0)
482 {
483 if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
484 {
485 /*
486 * We're exceeding the buffer, and data will be thrown away...
487 * FIXME: What could we do, as we are at DISPATCH_LEVEL?
488 */
489 ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount;
490 }
491 else
492 ReadSize = InputCount;
493
494 /*
495 * Move the input data from the port data queue to our class data
496 * queue.
497 */
498 RtlCopyMemory(
499 &ClassDeviceExtension->PortData[ClassDeviceExtension->InputCount],
500 (PCHAR)DataStart,
501 sizeof(KEYBOARD_INPUT_DATA) * ReadSize);
502
503 /* Move the counter up */
504 ClassDeviceExtension->InputCount += ReadSize;
505
506 (*ConsumedCount) += (ULONG)ReadSize;
507
508 /* Complete pending IRP (if any) */
509 if (ClassDeviceExtension->PendingIrp)
510 HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
511 }
512 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
513
514 TRACE_(CLASS_NAME, "Leaving ClassCallback()\n");
515 return TRUE;
516 }
517
518 /* Send IOCTL_INTERNAL_*_CONNECT to port */
519 static NTSTATUS
520 ConnectPortDriver(
521 IN PDEVICE_OBJECT PortDO,
522 IN PDEVICE_OBJECT ClassDO)
523 {
524 KEVENT Event;
525 PIRP Irp;
526 IO_STATUS_BLOCK IoStatus;
527 CONNECT_DATA ConnectData;
528 NTSTATUS Status;
529
530 TRACE_(CLASS_NAME, "Connecting PortDO %p to ClassDO %p\n", PortDO, ClassDO);
531
532 KeInitializeEvent(&Event, NotificationEvent, FALSE);
533
534 ConnectData.ClassDeviceObject = ClassDO;
535 ConnectData.ClassService = ClassCallback;
536
537 Irp = IoBuildDeviceIoControlRequest(
538 IOCTL_INTERNAL_KEYBOARD_CONNECT,
539 PortDO,
540 &ConnectData, sizeof(CONNECT_DATA),
541 NULL, 0,
542 TRUE, &Event, &IoStatus);
543 if (!Irp)
544 return STATUS_INSUFFICIENT_RESOURCES;
545
546 Status = IoCallDriver(PortDO, Irp);
547
548 if (Status == STATUS_PENDING)
549 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
550 else
551 IoStatus.Status = Status;
552
553 if (NT_SUCCESS(IoStatus.Status))
554 {
555 ObReferenceObject(PortDO);
556 ExInterlockedInsertTailList(
557 &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListHead,
558 &((PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension)->ListEntry,
559 &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListSpinLock);
560 if (ClassDO->StackSize <= PortDO->StackSize)
561 {
562 /* Increase the stack size, in case we have to
563 * forward some IRPs to the port device object
564 */
565 ClassDO->StackSize = PortDO->StackSize + 1;
566 }
567 }
568
569 return IoStatus.Status;
570 }
571
572 /* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
573 static VOID
574 DestroyPortDriver(
575 IN PDEVICE_OBJECT PortDO)
576 {
577 PPORT_DEVICE_EXTENSION DeviceExtension;
578 PCLASS_DEVICE_EXTENSION ClassDeviceExtension;
579 PCLASS_DRIVER_EXTENSION DriverExtension;
580 KEVENT Event;
581 PIRP Irp;
582 IO_STATUS_BLOCK IoStatus;
583 KIRQL OldIrql;
584 NTSTATUS Status;
585
586 TRACE_(CLASS_NAME, "Destroying PortDO %p\n", PortDO);
587
588 DeviceExtension = (PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension;
589 ClassDeviceExtension = DeviceExtension->ClassDO->DeviceExtension;
590 DriverExtension = IoGetDriverObjectExtension(PortDO->DriverObject, PortDO->DriverObject);
591
592 /* Send IOCTL_INTERNAL_*_DISCONNECT */
593 KeInitializeEvent(&Event, NotificationEvent, FALSE);
594 Irp = IoBuildDeviceIoControlRequest(
595 IOCTL_INTERNAL_KEYBOARD_DISCONNECT,
596 PortDO,
597 NULL, 0,
598 NULL, 0,
599 TRUE, &Event, &IoStatus);
600 if (Irp)
601 {
602 Status = IoCallDriver(PortDO, Irp);
603 if (Status == STATUS_PENDING)
604 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
605 }
606
607 /* Remove from ClassDeviceExtension->ListHead list */
608 KeAcquireSpinLock(&ClassDeviceExtension->ListSpinLock, &OldIrql);
609 RemoveEntryList(&DeviceExtension->ListEntry);
610 KeReleaseSpinLock(&ClassDeviceExtension->ListSpinLock, OldIrql);
611
612 /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
613 RtlDeleteRegistryValue(
614 RTL_REGISTRY_DEVICEMAP,
615 DriverExtension->DeviceBaseName.Buffer,
616 ClassDeviceExtension->DeviceName);
617
618 if (DeviceExtension->LowerDevice)
619 IoDetachDevice(DeviceExtension->LowerDevice);
620 ObDereferenceObject(PortDO);
621
622 if (!DriverExtension->ConnectMultiplePorts && DeviceExtension->ClassDO)
623 {
624 ExFreePoolWithTag(ClassDeviceExtension->PortData, CLASS_TAG);
625 ExFreePoolWithTag((PVOID)ClassDeviceExtension->DeviceName, CLASS_TAG);
626 IoDeleteDevice(DeviceExtension->ClassDO);
627 }
628
629 IoDeleteDevice(PortDO);
630 }
631
632 static NTSTATUS NTAPI
633 ClassAddDevice(
634 IN PDRIVER_OBJECT DriverObject,
635 IN PDEVICE_OBJECT Pdo)
636 {
637 PCLASS_DRIVER_EXTENSION DriverExtension;
638 PDEVICE_OBJECT Fdo = NULL;
639 PPORT_DEVICE_EXTENSION DeviceExtension = NULL;
640 NTSTATUS Status;
641
642 TRACE_(CLASS_NAME, "ClassAddDevice called. Pdo = 0x%p\n", Pdo);
643
644 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
645
646 if (Pdo == NULL)
647 /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
648 return STATUS_SUCCESS;
649
650 /* Create new device object */
651 Status = IoCreateDevice(
652 DriverObject,
653 sizeof(PORT_DEVICE_EXTENSION),
654 NULL,
655 Pdo->DeviceType,
656 Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
657 FALSE,
658 &Fdo);
659 if (!NT_SUCCESS(Status))
660 {
661 WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
662 goto cleanup;
663 }
664 IoSetStartIoAttributes(Fdo, TRUE, TRUE);
665
666 DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
667 RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
668 DeviceExtension->Common.IsClassDO = FALSE;
669 DeviceExtension->DeviceObject = Fdo;
670 DeviceExtension->PnpState = dsStopped;
671 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
672 if (!NT_SUCCESS(Status))
673 {
674 WARN_(CLASS_NAME, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
675 goto cleanup;
676 }
677 if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
678 Fdo->Flags |= DO_POWER_PAGABLE;
679 if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
680 Fdo->Flags |= DO_BUFFERED_IO;
681 if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
682 Fdo->Flags |= DO_DIRECT_IO;
683
684 if (DriverExtension->ConnectMultiplePorts)
685 DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
686 else
687 {
688 /* We need a new class device object for this Fdo */
689 Status = CreateClassDeviceObject(
690 DriverObject,
691 &DeviceExtension->ClassDO);
692 if (!NT_SUCCESS(Status))
693 {
694 WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
695 goto cleanup;
696 }
697 }
698 Status = ConnectPortDriver(Fdo, DeviceExtension->ClassDO);
699 if (!NT_SUCCESS(Status))
700 {
701 WARN_(CLASS_NAME, "ConnectPortDriver() failed with status 0x%08lx\n", Status);
702 goto cleanup;
703 }
704 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
705
706 /* Register interface ; ignore the error (if any) as having
707 * a registred interface is not so important... */
708 Status = IoRegisterDeviceInterface(
709 Pdo,
710 &GUID_DEVINTERFACE_KEYBOARD,
711 NULL,
712 &DeviceExtension->InterfaceName);
713 if (!NT_SUCCESS(Status))
714 DeviceExtension->InterfaceName.Length = 0;
715
716 return STATUS_SUCCESS;
717
718 cleanup:
719 if (Fdo)
720 DestroyPortDriver(Fdo);
721 return Status;
722 }
723
724 static VOID NTAPI
725 ClassCancelRoutine(
726 IN PDEVICE_OBJECT DeviceObject,
727 IN PIRP Irp)
728 {
729 PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
730 KIRQL OldIrql;
731 BOOLEAN wasQueued = FALSE;
732
733 TRACE_(CLASS_NAME, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
734
735 ASSERT(ClassDeviceExtension->Common.IsClassDO);
736
737 IoReleaseCancelSpinLock(Irp->CancelIrql);
738
739 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
740
741 if (ClassDeviceExtension->PendingIrp == Irp)
742 {
743 ClassDeviceExtension->PendingIrp = NULL;
744 wasQueued = TRUE;
745 }
746 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
747
748 if (wasQueued)
749 {
750 Irp->IoStatus.Status = STATUS_CANCELLED;
751 Irp->IoStatus.Information = 0;
752 IoCompleteRequest(Irp, IO_NO_INCREMENT);
753 }
754 else
755 {
756 DPRINT1("Cancelled IRP is not pending. Race condition?\n");
757 }
758 }
759
760 static NTSTATUS
761 HandleReadIrp(
762 IN PDEVICE_OBJECT DeviceObject,
763 IN PIRP Irp,
764 BOOLEAN IsInStartIo)
765 {
766 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
767 NTSTATUS Status;
768 KIRQL OldIrql;
769
770 TRACE_(CLASS_NAME, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
771
772 ASSERT(DeviceExtension->Common.IsClassDO);
773
774 if (DeviceExtension->InputCount > 0)
775 {
776 SIZE_T NumberOfEntries;
777
778 NumberOfEntries = MIN(
779 DeviceExtension->InputCount,
780 IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));
781
782 Status = FillEntries(
783 DeviceObject,
784 Irp,
785 DeviceExtension->PortData,
786 NumberOfEntries);
787
788 if (NT_SUCCESS(Status))
789 {
790 if (DeviceExtension->InputCount > NumberOfEntries)
791 {
792 RtlMoveMemory(
793 &DeviceExtension->PortData[0],
794 &DeviceExtension->PortData[NumberOfEntries],
795 (DeviceExtension->InputCount - NumberOfEntries) * sizeof(KEYBOARD_INPUT_DATA));
796 }
797
798 DeviceExtension->InputCount -= NumberOfEntries;
799
800 Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
801 }
802
803 /* Go to next packet and complete this request */
804 Irp->IoStatus.Status = Status;
805
806 (VOID)IoSetCancelRoutine(Irp, NULL);
807 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
808 DeviceExtension->PendingIrp = NULL;
809 }
810 else
811 {
812 IoAcquireCancelSpinLock(&OldIrql);
813 if (Irp->Cancel)
814 {
815 DeviceExtension->PendingIrp = NULL;
816 Status = STATUS_CANCELLED;
817 }
818 else
819 {
820 IoMarkIrpPending(Irp);
821 DeviceExtension->PendingIrp = Irp;
822 (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
823 Status = STATUS_PENDING;
824 }
825 IoReleaseCancelSpinLock(OldIrql);
826 }
827 return Status;
828 }
829
830 static NTSTATUS NTAPI
831 ClassPnp(
832 IN PDEVICE_OBJECT DeviceObject,
833 IN PIRP Irp)
834 {
835 PPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
836 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
837 OBJECT_ATTRIBUTES ObjectAttributes;
838 IO_STATUS_BLOCK Iosb;
839 NTSTATUS Status;
840
841 switch (IrpSp->MinorFunction)
842 {
843 case IRP_MN_START_DEVICE:
844 Status = ForwardIrpAndWait(DeviceObject, Irp);
845 if (NT_SUCCESS(Status))
846 {
847 InitializeObjectAttributes(&ObjectAttributes,
848 &DeviceExtension->InterfaceName,
849 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
850 NULL,
851 NULL);
852
853 Status = ZwOpenFile(&DeviceExtension->FileHandle,
854 FILE_READ_DATA,
855 &ObjectAttributes,
856 &Iosb,
857 0,
858 0);
859 if (!NT_SUCCESS(Status))
860 DeviceExtension->FileHandle = NULL;
861 }
862 else
863 DeviceExtension->FileHandle = NULL;
864 Irp->IoStatus.Status = Status;
865 IoCompleteRequest(Irp, IO_NO_INCREMENT);
866 return Status;
867
868 case IRP_MN_STOP_DEVICE:
869 if (DeviceExtension->FileHandle)
870 {
871 ZwClose(DeviceExtension->FileHandle);
872 DeviceExtension->FileHandle = NULL;
873 }
874 Status = STATUS_SUCCESS;
875 break;
876
877 case IRP_MN_REMOVE_DEVICE:
878 if (DeviceExtension->FileHandle)
879 {
880 ZwClose(DeviceExtension->FileHandle);
881 DeviceExtension->FileHandle = NULL;
882 }
883 IoSkipCurrentIrpStackLocation(Irp);
884 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
885 DestroyPortDriver(DeviceObject);
886 return Status;
887
888 default:
889 Status = Irp->IoStatus.Status;
890 break;
891 }
892
893 Irp->IoStatus.Status = Status;
894 if (NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED)
895 {
896 IoSkipCurrentIrpStackLocation(Irp);
897 return IoCallDriver(DeviceExtension->LowerDevice, Irp);
898 }
899 else
900 {
901 IoCompleteRequest(Irp, IO_NO_INCREMENT);
902 return Status;
903 }
904 }
905
906 static VOID NTAPI
907 ClassStartIo(
908 IN PDEVICE_OBJECT DeviceObject,
909 IN PIRP Irp)
910 {
911 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
912 KIRQL OldIrql;
913
914 TRACE_(CLASS_NAME, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
915
916 ASSERT(DeviceExtension->Common.IsClassDO);
917
918 KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
919 HandleReadIrp(DeviceObject, Irp, TRUE);
920 KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
921 }
922
923 static VOID NTAPI
924 SearchForLegacyDrivers(
925 IN PDRIVER_OBJECT DriverObject,
926 IN PVOID Context, /* PCLASS_DRIVER_EXTENSION */
927 IN ULONG Count)
928 {
929 UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
930 PCLASS_DRIVER_EXTENSION DriverExtension;
931 UNICODE_STRING PortBaseName = { 0, 0, NULL };
932 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
933 OBJECT_ATTRIBUTES ObjectAttributes;
934 HANDLE hDeviceMapKey = (HANDLE)-1;
935 HANDLE hPortKey = (HANDLE)-1;
936 ULONG Index = 0;
937 ULONG Size, ResultLength;
938 NTSTATUS Status;
939
940 TRACE_(CLASS_NAME, "SearchForLegacyDrivers(%p %p %lu)\n",
941 DriverObject, Context, Count);
942
943 if (Count != 1)
944 return;
945 DriverExtension = (PCLASS_DRIVER_EXTENSION)Context;
946
947 /* Create port base name, by replacing Class by Port at the end of the class base name */
948 Status = DuplicateUnicodeString(
949 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
950 &DriverExtension->DeviceBaseName,
951 &PortBaseName);
952 if (!NT_SUCCESS(Status))
953 {
954 WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
955 goto cleanup;
956 }
957 PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
958 RtlAppendUnicodeToString(&PortBaseName, L"Port");
959
960 /* Allocate memory */
961 Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
962 KeyValueInformation = ExAllocatePoolWithTag(PagedPool, Size, CLASS_TAG);
963 if (!KeyValueInformation)
964 {
965 WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
966 Status = STATUS_NO_MEMORY;
967 goto cleanup;
968 }
969
970 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
971 InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
972 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
973 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
974 {
975 INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
976 Status = STATUS_SUCCESS;
977 goto cleanup;
978 }
979 else if (!NT_SUCCESS(Status))
980 {
981 WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
982 goto cleanup;
983 }
984
985 /* Open sub key */
986 InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
987 Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
988 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
989 {
990 INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
991 Status = STATUS_SUCCESS;
992 goto cleanup;
993 }
994 else if (!NT_SUCCESS(Status))
995 {
996 WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
997 goto cleanup;
998 }
999
1000 /* Read each value name */
1001 while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
1002 {
1003 UNICODE_STRING PortName;
1004 PDEVICE_OBJECT PortDeviceObject = NULL;
1005 PFILE_OBJECT FileObject = NULL;
1006
1007 PortName.Length = PortName.MaximumLength = (USHORT)KeyValueInformation->NameLength;
1008 PortName.Buffer = KeyValueInformation->Name;
1009
1010 /* Open the device object pointer */
1011 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 WARN_(CLASS_NAME, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName, Status);
1015 continue;
1016 }
1017 INFO_(CLASS_NAME, "Legacy driver found\n");
1018
1019 Status = ClassAddDevice(DriverObject, PortDeviceObject);
1020 if (!NT_SUCCESS(Status))
1021 {
1022 /* FIXME: Log the error */
1023 WARN_(CLASS_NAME, "ClassAddDevice() failed with status 0x%08lx\n", Status);
1024 }
1025
1026 ObDereferenceObject(FileObject);
1027 }
1028
1029 cleanup:
1030 if (KeyValueInformation != NULL)
1031 ExFreePoolWithTag(KeyValueInformation, CLASS_TAG);
1032 if (hDeviceMapKey != (HANDLE)-1)
1033 ZwClose(hDeviceMapKey);
1034 if (hPortKey != (HANDLE)-1)
1035 ZwClose(hPortKey);
1036 }
1037
1038 /*
1039 * Standard DriverEntry method.
1040 */
1041 NTSTATUS NTAPI
1042 DriverEntry(
1043 IN PDRIVER_OBJECT DriverObject,
1044 IN PUNICODE_STRING RegistryPath)
1045 {
1046 PCLASS_DRIVER_EXTENSION DriverExtension;
1047 ULONG i;
1048 NTSTATUS Status;
1049
1050 Status = IoAllocateDriverObjectExtension(
1051 DriverObject,
1052 DriverObject,
1053 sizeof(CLASS_DRIVER_EXTENSION),
1054 (PVOID*)&DriverExtension);
1055 if (!NT_SUCCESS(Status))
1056 {
1057 WARN_(CLASS_NAME, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
1058 return Status;
1059 }
1060 RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
1061
1062 Status = DuplicateUnicodeString(
1063 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1064 RegistryPath,
1065 &DriverExtension->RegistryPath);
1066 if (!NT_SUCCESS(Status))
1067 {
1068 WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
1069 return Status;
1070 }
1071
1072 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
1073 if (!NT_SUCCESS(Status))
1074 {
1075 WARN_(CLASS_NAME, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
1076 return Status;
1077 }
1078
1079 if (DriverExtension->ConnectMultiplePorts == 1)
1080 {
1081 Status = CreateClassDeviceObject(
1082 DriverObject,
1083 &DriverExtension->MainClassDeviceObject);
1084 if (!NT_SUCCESS(Status))
1085 {
1086 WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
1087 return Status;
1088 }
1089 }
1090
1091 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
1092 DriverObject->DriverUnload = DriverUnload;
1093
1094 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1095 DriverObject->MajorFunction[i] = IrpStub;
1096
1097 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate;
1098 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose;
1099 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup;
1100 DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead;
1101 DriverObject->MajorFunction[IRP_MJ_PNP] = ClassPnp;
1102 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
1103 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ForwardIrpAndForget;
1104 DriverObject->DriverStartIo = ClassStartIo;
1105
1106 /* We will detect the legacy devices later */
1107 IoRegisterDriverReinitialization(
1108 DriverObject,
1109 SearchForLegacyDrivers,
1110 DriverExtension);
1111
1112 return STATUS_SUCCESS;
1113 }