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