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