1 /* 2 * PROJECT: ReactOS Kernel 3 * COPYRIGHT: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/pnpmgr/plugplay.c 5 * PURPOSE: Plug-and-play interface routines 6 * PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 typedef struct _PNP_EVENT_ENTRY 16 { 17 LIST_ENTRY ListEntry; 18 PLUGPLAY_EVENT_BLOCK Event; 19 } PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY; 20 21 typedef struct _IOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT 22 { 23 PCUNICODE_STRING InstancePath; 24 PDEVICE_OBJECT DeviceObject; 25 } IOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT, *PIOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT; 26 27 28 /* GLOBALS *******************************************************************/ 29 30 static LIST_ENTRY IopPnpEventQueueHead; 31 static KEVENT IopPnpNotifyEvent; 32 33 /* FUNCTIONS *****************************************************************/ 34 35 NTSTATUS 36 IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode); 37 38 CODE_SEG("INIT") 39 NTSTATUS 40 IopInitPlugPlayEvents(VOID) 41 { 42 InitializeListHead(&IopPnpEventQueueHead); 43 44 KeInitializeEvent(&IopPnpNotifyEvent, 45 SynchronizationEvent, 46 FALSE); 47 48 return STATUS_SUCCESS; 49 } 50 51 NTSTATUS 52 IopQueueDeviceChangeEvent( 53 _In_ const GUID *EventGuid, 54 _In_ const GUID *InterfaceClassGuid, 55 _In_ PUNICODE_STRING SymbolicLinkName) 56 { 57 PPNP_EVENT_ENTRY EventEntry; 58 UNICODE_STRING Copy; 59 ULONG TotalSize; 60 61 /* Allocate a big enough buffer */ 62 Copy.Length = 0; 63 Copy.MaximumLength = SymbolicLinkName->Length + sizeof(UNICODE_NULL); 64 TotalSize = 65 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, DeviceClass.SymbolicLinkName) + 66 Copy.MaximumLength; 67 68 EventEntry = ExAllocatePool(NonPagedPool, 69 TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); 70 if (!EventEntry) 71 return STATUS_INSUFFICIENT_RESOURCES; 72 RtlZeroMemory(EventEntry, TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); 73 74 /* Fill the buffer with the event GUID */ 75 RtlCopyMemory(&EventEntry->Event.EventGuid, EventGuid, sizeof(GUID)); 76 EventEntry->Event.EventCategory = DeviceClassChangeEvent; 77 EventEntry->Event.TotalSize = TotalSize; 78 79 /* Fill the interface class GUID */ 80 RtlCopyMemory(&EventEntry->Event.DeviceClass.ClassGuid, InterfaceClassGuid, sizeof(GUID)); 81 82 /* Fill the symbolic link name */ 83 RtlCopyMemory(&EventEntry->Event.DeviceClass.SymbolicLinkName, 84 SymbolicLinkName->Buffer, SymbolicLinkName->Length); 85 EventEntry->Event.DeviceClass.SymbolicLinkName[SymbolicLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL; 86 87 InsertHeadList(&IopPnpEventQueueHead, 88 &EventEntry->ListEntry); 89 KeSetEvent(&IopPnpNotifyEvent, 90 0, 91 FALSE); 92 93 return STATUS_SUCCESS; 94 } 95 96 NTSTATUS 97 IopQueueDeviceInstallEvent( 98 _In_ const GUID *EventGuid, 99 _In_ PUNICODE_STRING DeviceId) 100 { 101 PPNP_EVENT_ENTRY EventEntry; 102 UNICODE_STRING Copy; 103 ULONG TotalSize; 104 105 /* Allocate a big enough buffer */ 106 Copy.Length = 0; 107 Copy.MaximumLength = DeviceId->Length + sizeof(UNICODE_NULL); 108 TotalSize = 109 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, InstallDevice.DeviceId) + 110 Copy.MaximumLength; 111 112 EventEntry = ExAllocatePool(NonPagedPool, 113 TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); 114 if (!EventEntry) 115 return STATUS_INSUFFICIENT_RESOURCES; 116 RtlZeroMemory(EventEntry, TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); 117 118 /* Fill the buffer with the event GUID */ 119 RtlCopyMemory(&EventEntry->Event.EventGuid, EventGuid, sizeof(GUID)); 120 EventEntry->Event.EventCategory = DeviceInstallEvent; 121 EventEntry->Event.TotalSize = TotalSize; 122 123 /* Fill the symbolic link name */ 124 RtlCopyMemory(&EventEntry->Event.InstallDevice.DeviceId, 125 DeviceId->Buffer, DeviceId->Length); 126 EventEntry->Event.InstallDevice.DeviceId[DeviceId->Length / sizeof(WCHAR)] = UNICODE_NULL; 127 128 InsertHeadList(&IopPnpEventQueueHead, &EventEntry->ListEntry); 129 130 KeSetEvent(&IopPnpNotifyEvent, 0, FALSE); 131 132 return STATUS_SUCCESS; 133 } 134 135 136 NTSTATUS 137 IopQueueTargetDeviceEvent(const GUID *Guid, 138 PUNICODE_STRING DeviceIds) 139 { 140 PPNP_EVENT_ENTRY EventEntry; 141 UNICODE_STRING Copy; 142 ULONG TotalSize; 143 NTSTATUS Status; 144 145 ASSERT(DeviceIds); 146 147 /* Allocate a big enough buffer */ 148 Copy.Length = 0; 149 Copy.MaximumLength = DeviceIds->Length + sizeof(UNICODE_NULL); 150 TotalSize = 151 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) + 152 Copy.MaximumLength; 153 154 EventEntry = ExAllocatePool(NonPagedPool, 155 TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); 156 if (!EventEntry) 157 return STATUS_INSUFFICIENT_RESOURCES; 158 RtlZeroMemory(EventEntry, TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); 159 160 /* Fill the buffer with the event GUID */ 161 RtlCopyMemory(&EventEntry->Event.EventGuid, 162 Guid, 163 sizeof(GUID)); 164 EventEntry->Event.EventCategory = TargetDeviceChangeEvent; 165 EventEntry->Event.TotalSize = TotalSize; 166 167 /* Fill the device id */ 168 Copy.Buffer = EventEntry->Event.TargetDevice.DeviceIds; 169 Status = RtlAppendUnicodeStringToString(&Copy, DeviceIds); 170 if (!NT_SUCCESS(Status)) 171 { 172 ExFreePool(EventEntry); 173 return Status; 174 } 175 176 InsertHeadList(&IopPnpEventQueueHead, 177 &EventEntry->ListEntry); 178 KeSetEvent(&IopPnpNotifyEvent, 179 0, 180 FALSE); 181 182 return STATUS_SUCCESS; 183 } 184 185 NTSTATUS 186 IopFindDeviceInstanceTraverse( 187 _In_ PDEVICE_NODE DeviceNode, 188 _Inout_ PVOID Context) 189 { 190 PIOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT DeviceInstanceContext = Context; 191 192 if (RtlEqualUnicodeString(&DeviceNode->InstancePath, 193 DeviceInstanceContext->InstancePath, TRUE)) 194 { 195 ObReferenceObject(DeviceNode->PhysicalDeviceObject); 196 DeviceInstanceContext->DeviceObject = DeviceNode->PhysicalDeviceObject; 197 198 /* Stop enumeration */ 199 return STATUS_UNSUCCESSFUL; 200 } 201 202 return STATUS_SUCCESS; 203 } 204 205 PDEVICE_OBJECT 206 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance) 207 { 208 DEVICETREE_TRAVERSE_CONTEXT Context; 209 IOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT DeviceInstanceContext; 210 211 if (IopRootDeviceNode == NULL) 212 return NULL; 213 214 if (DeviceInstance == NULL || 215 DeviceInstance->Length == 0) 216 { 217 if (IopRootDeviceNode->PhysicalDeviceObject) 218 { 219 ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject); 220 return IopRootDeviceNode->PhysicalDeviceObject; 221 } 222 else 223 return NULL; 224 } 225 226 /* Traverse the device tree to find the matching device node */ 227 DeviceInstanceContext.InstancePath = DeviceInstance; 228 DeviceInstanceContext.DeviceObject = NULL; 229 IopInitDeviceTreeTraverseContext(&Context, 230 IopRootDeviceNode, 231 IopFindDeviceInstanceTraverse, 232 &DeviceInstanceContext); 233 (void)IopTraverseDeviceTree(&Context); 234 235 /* In case of error or instance not found, this will still be NULL from above. */ 236 return DeviceInstanceContext.DeviceObject; 237 } 238 239 static NTSTATUS 240 IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName) 241 { 242 NTSTATUS Status = STATUS_SUCCESS; 243 volatile UNICODE_STRING Name; 244 245 Name.Buffer = NULL; 246 _SEH2_TRY 247 { 248 Name.Length = SrcName->Length; 249 Name.MaximumLength = SrcName->MaximumLength; 250 if (Name.Length > Name.MaximumLength) 251 { 252 Status = STATUS_INVALID_PARAMETER; 253 _SEH2_LEAVE; 254 } 255 256 if (Name.MaximumLength) 257 { 258 ProbeForRead(SrcName->Buffer, 259 Name.MaximumLength, 260 sizeof(WCHAR)); 261 Name.Buffer = ExAllocatePool(NonPagedPool, Name.MaximumLength); 262 if (Name.Buffer == NULL) 263 { 264 Status = STATUS_INSUFFICIENT_RESOURCES; 265 _SEH2_LEAVE; 266 } 267 268 memcpy(Name.Buffer, SrcName->Buffer, Name.MaximumLength); 269 } 270 271 *DstName = Name; 272 } 273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 274 { 275 if (Name.Buffer) 276 { 277 ExFreePool(Name.Buffer); 278 } 279 Status = _SEH2_GetExceptionCode(); 280 } 281 _SEH2_END; 282 283 return Status; 284 } 285 286 287 static 288 NTSTATUS 289 PiControlInitializeDevice( 290 _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData) 291 { 292 UNICODE_STRING DeviceInstance; 293 PDEVICE_OBJECT DeviceObject; 294 PDEVICE_NODE DeviceNode; 295 NTSTATUS Status = STATUS_SUCCESS; 296 HANDLE InstanceKey; 297 298 DPRINT("PiControlInitializeDevice(%p)\n", ControlData); 299 300 Status = IopCaptureUnicodeString(&DeviceInstance, &ControlData->DeviceInstance); 301 if (!NT_SUCCESS(Status)) 302 { 303 return Status; 304 } 305 306 DPRINT("Device: %wZ\n", &DeviceInstance); 307 308 /* Leave, if the device already exists */ 309 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 310 if (DeviceObject != NULL) 311 { 312 DPRINT1("Device %wZ already exists!\n", &DeviceInstance); 313 ObDereferenceObject(DeviceObject); 314 Status = STATUS_SUCCESS; 315 goto done; 316 } 317 318 DPRINT("Device %wZ does not exist!\n", &DeviceInstance); 319 320 /* Create a device node for the device instance */ 321 Status = PnpRootCreateDeviceObject(&DeviceObject); 322 if (!NT_SUCCESS(Status)) 323 { 324 DPRINT1("IoCreateDevice() failed (Status 0x%08lx)\n", Status); 325 goto done; 326 } 327 328 /* Allocate a new device node */ 329 DeviceNode = PipAllocateDeviceNode(DeviceObject); 330 if (DeviceNode == NULL) 331 { 332 DPRINT1("Failed to allocate a device node!\n"); 333 IoDeleteDevice(DeviceObject); 334 Status = STATUS_INSUFFICIENT_RESOURCES; 335 goto done; 336 } 337 338 // Set the device instance of the device node 339 // NOTE: a NULL-terminated string is required for PnpRootRegisterDevice 340 Status = RtlDuplicateUnicodeString( 341 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 342 &DeviceInstance, 343 &DeviceNode->InstancePath); 344 if (!NT_SUCCESS(Status)) 345 { 346 DPRINT1("RtlDuplicateUnicodeString() failed (Status 0x%08lx)\n", Status); 347 IopFreeDeviceNode(DeviceNode); 348 IoDeleteDevice(DeviceObject); 349 goto done; 350 } 351 352 DeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; 353 DeviceNode->Flags |= DNF_MADEUP | DNF_IDS_QUERIED | DNF_ENUMERATED; 354 PiSetDevNodeState(DeviceNode, DeviceNodeInitialized); 355 356 Status = IopCreateDeviceKeyPath(&DeviceInstance, REG_OPTION_NON_VOLATILE, &InstanceKey); 357 if (!NT_SUCCESS(Status)) 358 { 359 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); 360 IopFreeDeviceNode(DeviceNode); 361 IoDeleteDevice(DeviceObject); 362 goto done; 363 } 364 365 /* Write the resource information to the registry */ 366 IopSetDeviceInstanceData(InstanceKey, DeviceNode); 367 368 // Finish the root device registration 369 PnpRootRegisterDevice(DeviceObject); 370 371 /* Insert as a root enumerated device node */ 372 PiInsertDevNode(DeviceNode, IopRootDeviceNode); 373 374 /* Report the device to the user-mode pnp manager */ 375 IopQueueDeviceInstallEvent(&GUID_DEVICE_ENUMERATED, &DeviceNode->InstancePath); 376 377 ZwClose(InstanceKey); 378 done: 379 ExFreePool(DeviceInstance.Buffer); 380 381 return Status; 382 } 383 384 385 /* 386 * Remove the current PnP event from the tail of the event queue 387 * and signal IopPnpNotifyEvent if there is yet another event in the queue. 388 */ 389 static 390 NTSTATUS 391 IopRemovePlugPlayEvent( 392 _In_ PPLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData) 393 { 394 /* Remove a pnp event entry from the tail of the queue */ 395 if (!IsListEmpty(&IopPnpEventQueueHead)) 396 { 397 ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead), PNP_EVENT_ENTRY, ListEntry)); 398 } 399 400 /* Signal the next pnp event in the queue */ 401 if (!IsListEmpty(&IopPnpEventQueueHead)) 402 { 403 KeSetEvent(&IopPnpNotifyEvent, 404 0, 405 FALSE); 406 } 407 408 return STATUS_SUCCESS; 409 } 410 411 412 static NTSTATUS 413 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList) 414 { 415 NTSTATUS Status; 416 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList; 417 UNICODE_STRING DeviceInstance; 418 PDEVICE_OBJECT DeviceObject = NULL; 419 GUID FilterGuid; 420 PZZWSTR SymbolicLinkList = NULL, LinkList; 421 SIZE_T TotalLength; 422 423 _SEH2_TRY 424 { 425 RtlCopyMemory(&StackList, DeviceList, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)); 426 427 ProbeForRead(StackList.FilterGuid, sizeof(GUID), sizeof(UCHAR)); 428 RtlCopyMemory(&FilterGuid, StackList.FilterGuid, sizeof(GUID)); 429 430 if (StackList.Buffer != NULL && StackList.BufferSize != 0) 431 { 432 ProbeForWrite(StackList.Buffer, StackList.BufferSize, sizeof(UCHAR)); 433 } 434 } 435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 436 { 437 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 438 } 439 _SEH2_END; 440 441 Status = IopCaptureUnicodeString(&DeviceInstance, &StackList.DeviceInstance); 442 if (NT_SUCCESS(Status)) 443 { 444 /* Get the device object */ 445 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 446 if (DeviceInstance.Buffer != NULL) 447 { 448 ExFreePool(DeviceInstance.Buffer); 449 } 450 } 451 452 Status = IoGetDeviceInterfaces(&FilterGuid, DeviceObject, StackList.Flags, &SymbolicLinkList); 453 ObDereferenceObject(DeviceObject); 454 455 if (!NT_SUCCESS(Status)) 456 { 457 /* failed */ 458 return Status; 459 } 460 461 LinkList = SymbolicLinkList; 462 while (*SymbolicLinkList != UNICODE_NULL) 463 { 464 SymbolicLinkList += wcslen(SymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); 465 } 466 TotalLength = ((SymbolicLinkList - LinkList + 1) * sizeof(WCHAR)); 467 468 _SEH2_TRY 469 { 470 if (StackList.Buffer != NULL && 471 StackList.BufferSize >= TotalLength) 472 { 473 // We've already probed the buffer for writing above. 474 RtlCopyMemory(StackList.Buffer, LinkList, TotalLength); 475 } 476 477 DeviceList->BufferSize = TotalLength; 478 } 479 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 480 { 481 ExFreePool(LinkList); 482 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 483 } 484 _SEH2_END; 485 486 ExFreePool(LinkList); 487 return STATUS_SUCCESS; 488 } 489 490 static NTSTATUS 491 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData) 492 { 493 PDEVICE_OBJECT DeviceObject = NULL; 494 PDEVICE_NODE DeviceNode; 495 UNICODE_STRING DeviceInstance; 496 ULONG BufferSize; 497 ULONG Property; 498 DEVICE_REGISTRY_PROPERTY DeviceProperty; 499 PVOID Buffer; 500 NTSTATUS Status; 501 502 DPRINT("IopGetDeviceProperty() called\n"); 503 DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance); 504 505 Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance); 506 if (!NT_SUCCESS(Status)) 507 { 508 return Status; 509 } 510 511 _SEH2_TRY 512 { 513 Property = PropertyData->Property; 514 BufferSize = PropertyData->BufferSize; 515 ProbeForWrite(PropertyData->Buffer, 516 BufferSize, 517 sizeof(UCHAR)); 518 } 519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 520 { 521 if (DeviceInstance.Buffer != NULL) 522 { 523 ExFreePool(DeviceInstance.Buffer); 524 } 525 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 526 } 527 _SEH2_END; 528 529 /* Get the device object */ 530 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 531 if (DeviceInstance.Buffer != NULL) 532 { 533 ExFreePool(DeviceInstance.Buffer); 534 } 535 if (DeviceObject == NULL) 536 { 537 return STATUS_NO_SUCH_DEVICE; 538 } 539 540 Buffer = ExAllocatePool(NonPagedPool, BufferSize); 541 if (Buffer == NULL) 542 { 543 ObDereferenceObject(DeviceObject); 544 return STATUS_INSUFFICIENT_RESOURCES; 545 } 546 547 548 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 549 550 if (Property == PNP_PROPERTY_POWER_DATA) 551 { 552 if (BufferSize < sizeof(CM_POWER_DATA)) 553 { 554 BufferSize = 0; 555 Status = STATUS_BUFFER_TOO_SMALL; 556 } 557 else 558 { 559 DEVICE_CAPABILITIES DeviceCapabilities; 560 PCM_POWER_DATA PowerData; 561 IO_STACK_LOCATION Stack; 562 IO_STATUS_BLOCK IoStatusBlock; 563 564 PowerData = (PCM_POWER_DATA)Buffer; 565 RtlZeroMemory(PowerData, sizeof(CM_POWER_DATA)); 566 PowerData->PD_Size = sizeof(CM_POWER_DATA); 567 568 RtlZeroMemory(&DeviceCapabilities, sizeof(DEVICE_CAPABILITIES)); 569 DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES); 570 DeviceCapabilities.Version = 1; 571 DeviceCapabilities.Address = -1; 572 DeviceCapabilities.UINumber = -1; 573 574 Stack.Parameters.DeviceCapabilities.Capabilities = &DeviceCapabilities; 575 576 Status = IopInitiatePnpIrp(DeviceObject, 577 &IoStatusBlock, 578 IRP_MN_QUERY_CAPABILITIES, 579 &Stack); 580 if (NT_SUCCESS(Status)) 581 { 582 DPRINT("Got device capabiliities\n"); 583 584 PowerData->PD_MostRecentPowerState = PowerDeviceD0; // FIXME 585 if (DeviceCapabilities.DeviceD1) 586 PowerData->PD_Capabilities |= PDCAP_D1_SUPPORTED; 587 if (DeviceCapabilities.DeviceD2) 588 PowerData->PD_Capabilities |= PDCAP_D2_SUPPORTED; 589 if (DeviceCapabilities.WakeFromD0) 590 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED; 591 if (DeviceCapabilities.WakeFromD1) 592 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D1_SUPPORTED; 593 if (DeviceCapabilities.WakeFromD2) 594 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D2_SUPPORTED; 595 if (DeviceCapabilities.WakeFromD3) 596 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED; 597 if (DeviceCapabilities.WarmEjectSupported) 598 PowerData->PD_Capabilities |= PDCAP_WARM_EJECT_SUPPORTED; 599 PowerData->PD_D1Latency = DeviceCapabilities.D1Latency; 600 PowerData->PD_D2Latency = DeviceCapabilities.D2Latency; 601 PowerData->PD_D3Latency = DeviceCapabilities.D3Latency; 602 RtlCopyMemory(&PowerData->PD_PowerStateMapping, 603 &DeviceCapabilities.DeviceState, 604 sizeof(DeviceCapabilities.DeviceState)); 605 PowerData->PD_DeepestSystemWake = DeviceCapabilities.SystemWake; 606 } 607 else 608 { 609 DPRINT("IRP_MN_QUERY_CAPABILITIES failed (Status 0x%08lx)\n", Status); 610 611 PowerData->PD_Capabilities = PDCAP_D0_SUPPORTED | PDCAP_D3_SUPPORTED; 612 PowerData->PD_MostRecentPowerState = PowerDeviceD0; 613 } 614 } 615 } 616 else if (Property == PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE) 617 { 618 UNIMPLEMENTED; 619 BufferSize = 0; 620 Status = STATUS_NOT_IMPLEMENTED; 621 } 622 else if (Property == PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT) 623 { 624 if (BufferSize < sizeof(DeviceNode->HardwareRemovalPolicy)) 625 { 626 BufferSize = 0; 627 Status = STATUS_BUFFER_TOO_SMALL; 628 } 629 else 630 { 631 BufferSize = sizeof(DeviceNode->HardwareRemovalPolicy); 632 RtlCopyMemory(Buffer, 633 &DeviceNode->HardwareRemovalPolicy, 634 BufferSize); 635 } 636 } 637 else 638 { 639 switch (Property) 640 { 641 case PNP_PROPERTY_UI_NUMBER: 642 DeviceProperty = DevicePropertyUINumber; 643 break; 644 645 case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME: 646 DeviceProperty = DevicePropertyPhysicalDeviceObjectName; 647 break; 648 649 case PNP_PROPERTY_BUSTYPEGUID: 650 DeviceProperty = DevicePropertyBusTypeGuid; 651 break; 652 653 case PNP_PROPERTY_LEGACYBUSTYPE: 654 DeviceProperty = DevicePropertyLegacyBusType; 655 break; 656 657 case PNP_PROPERTY_BUSNUMBER: 658 DeviceProperty = DevicePropertyBusNumber; 659 break; 660 661 case PNP_PROPERTY_REMOVAL_POLICY: 662 DeviceProperty = DevicePropertyRemovalPolicy; 663 break; 664 665 case PNP_PROPERTY_ADDRESS: 666 DeviceProperty = DevicePropertyAddress; 667 break; 668 669 case PNP_PROPERTY_ENUMERATOR_NAME: 670 DeviceProperty = DevicePropertyEnumeratorName; 671 break; 672 673 case PNP_PROPERTY_INSTALL_STATE: 674 DeviceProperty = DevicePropertyInstallState; 675 break; 676 677 #if (WINVER >= _WIN32_WINNT_WS03) 678 case PNP_PROPERTY_LOCATION_PATHS: 679 UNIMPLEMENTED; 680 BufferSize = 0; 681 Status = STATUS_NOT_IMPLEMENTED; 682 break; 683 #endif 684 685 #if (WINVER >= _WIN32_WINNT_WIN7) 686 case PNP_PROPERTY_CONTAINERID: 687 DeviceProperty = DevicePropertyContainerID; 688 break; 689 #endif 690 691 default: 692 BufferSize = 0; 693 Status = STATUS_INVALID_PARAMETER; 694 break; 695 } 696 697 if (Status == STATUS_SUCCESS) 698 { 699 Status = IoGetDeviceProperty(DeviceObject, 700 DeviceProperty, 701 BufferSize, 702 Buffer, 703 &BufferSize); 704 } 705 } 706 707 ObDereferenceObject(DeviceObject); 708 709 if (NT_SUCCESS(Status)) 710 { 711 _SEH2_TRY 712 { 713 RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize); 714 PropertyData->BufferSize = BufferSize; 715 } 716 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 717 { 718 Status = _SEH2_GetExceptionCode(); 719 } 720 _SEH2_END; 721 } 722 723 ExFreePool(Buffer); 724 return Status; 725 } 726 727 728 static NTSTATUS 729 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData) 730 { 731 UNICODE_STRING RootDeviceName; 732 PDEVICE_OBJECT DeviceObject = NULL; 733 PDEVICE_NODE DeviceNode = NULL; 734 PDEVICE_NODE RelatedDeviceNode; 735 UNICODE_STRING TargetDeviceInstance; 736 NTSTATUS Status = STATUS_SUCCESS; 737 ULONG Relation = 0; 738 ULONG MaximumLength = 0; 739 740 DPRINT("IopGetRelatedDevice() called\n"); 741 DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance); 742 743 Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance); 744 if (!NT_SUCCESS(Status)) 745 { 746 return Status; 747 } 748 749 _SEH2_TRY 750 { 751 Relation = RelatedDeviceData->Relation; 752 MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength; 753 ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance, 754 MaximumLength, 755 sizeof(WCHAR)); 756 } 757 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 758 { 759 if (TargetDeviceInstance.Buffer != NULL) 760 { 761 ExFreePool(TargetDeviceInstance.Buffer); 762 } 763 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 764 } 765 _SEH2_END; 766 767 RtlInitUnicodeString(&RootDeviceName, 768 L"HTREE\\ROOT\\0"); 769 if (RtlEqualUnicodeString(&TargetDeviceInstance, 770 &RootDeviceName, 771 TRUE)) 772 { 773 DeviceNode = IopRootDeviceNode; 774 if (TargetDeviceInstance.Buffer != NULL) 775 { 776 ExFreePool(TargetDeviceInstance.Buffer); 777 } 778 } 779 else 780 { 781 /* Get the device object */ 782 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance); 783 if (TargetDeviceInstance.Buffer != NULL) 784 { 785 ExFreePool(TargetDeviceInstance.Buffer); 786 } 787 if (DeviceObject == NULL) 788 return STATUS_NO_SUCH_DEVICE; 789 790 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 791 } 792 793 switch (Relation) 794 { 795 case PNP_GET_PARENT_DEVICE: 796 RelatedDeviceNode = DeviceNode->Parent; 797 break; 798 799 case PNP_GET_CHILD_DEVICE: 800 RelatedDeviceNode = DeviceNode->Child; 801 break; 802 803 case PNP_GET_SIBLING_DEVICE: 804 RelatedDeviceNode = DeviceNode->Sibling; 805 break; 806 807 default: 808 if (DeviceObject != NULL) 809 { 810 ObDereferenceObject(DeviceObject); 811 } 812 813 return STATUS_INVALID_PARAMETER; 814 } 815 816 if (RelatedDeviceNode == NULL) 817 { 818 if (DeviceObject) 819 { 820 ObDereferenceObject(DeviceObject); 821 } 822 823 return STATUS_NO_SUCH_DEVICE; 824 } 825 826 if (RelatedDeviceNode->InstancePath.Length > MaximumLength) 827 { 828 if (DeviceObject) 829 { 830 ObDereferenceObject(DeviceObject); 831 } 832 833 return STATUS_BUFFER_TOO_SMALL; 834 } 835 836 /* Copy related device instance name */ 837 _SEH2_TRY 838 { 839 RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance, 840 RelatedDeviceNode->InstancePath.Buffer, 841 RelatedDeviceNode->InstancePath.Length); 842 RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length; 843 } 844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 845 { 846 Status = _SEH2_GetExceptionCode(); 847 } 848 _SEH2_END; 849 850 if (DeviceObject != NULL) 851 { 852 ObDereferenceObject(DeviceObject); 853 } 854 855 DPRINT("IopGetRelatedDevice() done\n"); 856 857 return Status; 858 } 859 860 static 861 BOOLEAN 862 PiIsDevNodeStarted( 863 _In_ PDEVICE_NODE DeviceNode) 864 { 865 return (DeviceNode->State == DeviceNodeStartPending || 866 DeviceNode->State == DeviceNodeStartCompletion || 867 DeviceNode->State == DeviceNodeStartPostWork || 868 DeviceNode->State == DeviceNodeStarted || 869 DeviceNode->State == DeviceNodeQueryStopped || 870 DeviceNode->State == DeviceNodeEnumeratePending || 871 DeviceNode->State == DeviceNodeEnumerateCompletion || 872 DeviceNode->State == DeviceNodeStopped || 873 DeviceNode->State == DeviceNodeRestartCompletion); 874 } 875 876 static ULONG 877 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode) 878 { 879 ULONG Output = DN_NT_ENUMERATOR | DN_NT_DRIVER; 880 881 if (DeviceNode->Parent == IopRootDeviceNode) 882 Output |= DN_ROOT_ENUMERATED; 883 884 // FIXME: review for deleted and removed states 885 if (DeviceNode->State >= DeviceNodeDriversAdded) 886 Output |= DN_DRIVER_LOADED; 887 888 if (PiIsDevNodeStarted(DeviceNode)) 889 Output |= DN_STARTED; 890 891 if (DeviceNode->UserFlags & DNUF_WILL_BE_REMOVED) 892 Output |= DN_WILL_BE_REMOVED; 893 894 if (DeviceNode->Flags & DNF_HAS_PROBLEM) 895 Output |= DN_HAS_PROBLEM; 896 897 if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM) 898 Output |= DN_PRIVATE_PROBLEM; 899 900 if (DeviceNode->Flags & DNF_DRIVER_BLOCKED) 901 Output |= DN_DRIVER_BLOCKED; 902 903 if (DeviceNode->Flags & DNF_CHILD_WITH_INVALID_ID) 904 Output |= DN_CHILD_WITH_INVALID_ID; 905 906 if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM) 907 Output |= DN_PRIVATE_PROBLEM; 908 909 if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 910 Output |= DN_LEGACY_DRIVER; 911 912 if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI) 913 Output |= DN_NO_SHOW_IN_DM; 914 915 if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE)) 916 Output |= DN_DISABLEABLE; 917 918 return Output; 919 } 920 921 static NTSTATUS 922 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData) 923 { 924 PDEVICE_OBJECT DeviceObject; 925 PDEVICE_NODE DeviceNode; 926 ULONG Operation = 0; 927 ULONG DeviceStatus = 0; 928 ULONG DeviceProblem = 0; 929 UNICODE_STRING DeviceInstance; 930 NTSTATUS Status; 931 932 DPRINT("IopDeviceStatus() called\n"); 933 934 Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance); 935 if (!NT_SUCCESS(Status)) 936 { 937 return Status; 938 } 939 940 DPRINT("Device name: '%wZ'\n", &DeviceInstance); 941 942 _SEH2_TRY 943 { 944 Operation = StatusData->Operation; 945 if (Operation == PNP_SET_DEVICE_STATUS) 946 { 947 DeviceStatus = StatusData->DeviceStatus; 948 DeviceProblem = StatusData->DeviceProblem; 949 } 950 } 951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 952 { 953 if (DeviceInstance.Buffer != NULL) 954 { 955 ExFreePool(DeviceInstance.Buffer); 956 } 957 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 958 } 959 _SEH2_END; 960 961 /* Get the device object */ 962 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 963 if (DeviceInstance.Buffer != NULL) 964 { 965 ExFreePool(DeviceInstance.Buffer); 966 } 967 if (DeviceObject == NULL) 968 { 969 return STATUS_NO_SUCH_DEVICE; 970 } 971 972 DeviceNode = IopGetDeviceNode(DeviceObject); 973 974 switch (Operation) 975 { 976 case PNP_GET_DEVICE_STATUS: 977 DPRINT("Get status data\n"); 978 DeviceStatus = IopGetDeviceNodeStatus(DeviceNode); 979 DeviceProblem = DeviceNode->Problem; 980 break; 981 982 case PNP_SET_DEVICE_STATUS: 983 DPRINT1("Set status data is NOT SUPPORTED\n"); 984 break; 985 986 case PNP_CLEAR_DEVICE_STATUS: 987 DPRINT1("FIXME: Clear status data!\n"); 988 break; 989 } 990 991 ObDereferenceObject(DeviceObject); 992 993 if (Operation == PNP_GET_DEVICE_STATUS) 994 { 995 _SEH2_TRY 996 { 997 StatusData->DeviceStatus = DeviceStatus; 998 StatusData->DeviceProblem = DeviceProblem; 999 } 1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1001 { 1002 Status = _SEH2_GetExceptionCode(); 1003 } 1004 _SEH2_END; 1005 } 1006 1007 return Status; 1008 } 1009 1010 static 1011 NTSTATUS 1012 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData) 1013 { 1014 UNICODE_STRING DeviceInstance; 1015 PDEVICE_OBJECT DeviceObject = NULL; 1016 IO_STACK_LOCATION Stack; 1017 IO_STATUS_BLOCK IoStatusBlock; 1018 PDEVICE_RELATIONS DeviceRelations = NULL; 1019 PDEVICE_OBJECT ChildDeviceObject; 1020 PDEVICE_NODE ChildDeviceNode; 1021 ULONG i; 1022 ULONG Relations; 1023 ULONG BufferSize, RequiredSize; 1024 ULONG BufferLeft; 1025 PWCHAR Buffer, Ptr; 1026 NTSTATUS Status = STATUS_SUCCESS; 1027 1028 DPRINT("IopGetDeviceRelations() called\n"); 1029 DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance); 1030 DPRINT("Relations: %lu\n", RelationsData->Relations); 1031 DPRINT("BufferSize: %lu\n", RelationsData->BufferSize); 1032 DPRINT("Buffer: %p\n", RelationsData->Buffer); 1033 1034 _SEH2_TRY 1035 { 1036 Relations = RelationsData->Relations; 1037 BufferSize = RelationsData->BufferSize; 1038 Buffer = RelationsData->Buffer; 1039 1040 ProbeForWrite(Buffer, BufferSize, sizeof(CHAR)); 1041 } 1042 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1043 { 1044 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1045 } 1046 _SEH2_END; 1047 1048 Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance); 1049 if (!NT_SUCCESS(Status)) 1050 { 1051 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status); 1052 return Status; 1053 } 1054 1055 /* Get the device object */ 1056 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 1057 if (DeviceObject == NULL) 1058 { 1059 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n"); 1060 Status = STATUS_NO_SUCH_DEVICE; 1061 goto done; 1062 } 1063 1064 switch (Relations) 1065 { 1066 case PNP_EJECT_RELATIONS: 1067 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 1068 break; 1069 1070 case PNP_REMOVAL_RELATIONS: 1071 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 1072 break; 1073 1074 case PNP_POWER_RELATIONS: 1075 Stack.Parameters.QueryDeviceRelations.Type = PowerRelations; 1076 break; 1077 1078 case PNP_BUS_RELATIONS: 1079 Stack.Parameters.QueryDeviceRelations.Type = BusRelations; 1080 break; 1081 1082 default: 1083 Status = STATUS_INVALID_PARAMETER; 1084 goto done; 1085 } 1086 1087 Status = IopInitiatePnpIrp(DeviceObject, 1088 &IoStatusBlock, 1089 IRP_MN_QUERY_DEVICE_RELATIONS, 1090 &Stack); 1091 if (!NT_SUCCESS(Status)) 1092 { 1093 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 1094 goto done; 1095 } 1096 1097 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 1098 1099 DPRINT("Found %d device relations\n", DeviceRelations->Count); 1100 1101 _SEH2_TRY 1102 { 1103 RequiredSize = 0; 1104 BufferLeft = BufferSize; 1105 Ptr = Buffer; 1106 1107 for (i = 0; i < DeviceRelations->Count; i++) 1108 { 1109 ChildDeviceObject = DeviceRelations->Objects[i]; 1110 1111 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 1112 if (ChildDeviceNode) 1113 { 1114 DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath); 1115 DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 1116 1117 if (Ptr != NULL) 1118 { 1119 if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR)) 1120 { 1121 Status = STATUS_BUFFER_TOO_SMALL; 1122 break; 1123 } 1124 1125 RtlCopyMemory(Ptr, 1126 ChildDeviceNode->InstancePath.Buffer, 1127 ChildDeviceNode->InstancePath.Length); 1128 Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length); 1129 *Ptr = UNICODE_NULL; 1130 Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR)); 1131 1132 BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 1133 } 1134 1135 RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 1136 } 1137 } 1138 1139 if (Ptr != NULL && BufferLeft >= sizeof(WCHAR)) 1140 *Ptr = UNICODE_NULL; 1141 1142 if (RequiredSize > 0) 1143 RequiredSize += sizeof(WCHAR); 1144 1145 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize); 1146 1147 RelationsData->BufferSize = RequiredSize; 1148 } 1149 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1150 { 1151 Status = _SEH2_GetExceptionCode(); 1152 } 1153 _SEH2_END; 1154 1155 done: 1156 if (DeviceRelations != NULL) 1157 ExFreePool(DeviceRelations); 1158 1159 if (DeviceObject != NULL) 1160 ObDereferenceObject(DeviceObject); 1161 1162 if (DeviceInstance.Buffer != NULL) 1163 ExFreePool(DeviceInstance.Buffer); 1164 1165 return Status; 1166 } 1167 1168 static NTSTATUS 1169 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) 1170 { 1171 PDEVICE_OBJECT DeviceObject; 1172 PDEVICE_NODE DeviceNode; 1173 UNICODE_STRING DeviceInstance; 1174 NTSTATUS Status = STATUS_SUCCESS; 1175 1176 DPRINT("IopGetDeviceDepth() called\n"); 1177 DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance); 1178 1179 Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance); 1180 if (!NT_SUCCESS(Status)) 1181 { 1182 return Status; 1183 } 1184 1185 /* Get the device object */ 1186 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 1187 if (DeviceInstance.Buffer != NULL) 1188 { 1189 ExFreePool(DeviceInstance.Buffer); 1190 } 1191 if (DeviceObject == NULL) 1192 { 1193 return STATUS_NO_SUCH_DEVICE; 1194 } 1195 1196 DeviceNode = IopGetDeviceNode(DeviceObject); 1197 1198 _SEH2_TRY 1199 { 1200 DepthData->Depth = DeviceNode->Level; 1201 } 1202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1203 { 1204 Status = _SEH2_GetExceptionCode(); 1205 } 1206 _SEH2_END; 1207 1208 ObDereferenceObject(DeviceObject); 1209 1210 return Status; 1211 } 1212 1213 static 1214 NTSTATUS 1215 PiControlSyncDeviceAction( 1216 _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceData, 1217 _In_ PLUGPLAY_CONTROL_CLASS ControlClass) 1218 { 1219 PDEVICE_OBJECT DeviceObject; 1220 NTSTATUS Status; 1221 UNICODE_STRING DeviceInstance; 1222 1223 ASSERT(ControlClass == PlugPlayControlEnumerateDevice || 1224 ControlClass == PlugPlayControlStartDevice || 1225 ControlClass == PlugPlayControlResetDevice); 1226 1227 Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); 1228 if (!NT_SUCCESS(Status)) 1229 { 1230 return Status; 1231 } 1232 1233 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 1234 if (DeviceInstance.Buffer != NULL) 1235 { 1236 ExFreePool(DeviceInstance.Buffer); 1237 } 1238 if (DeviceObject == NULL) 1239 { 1240 return STATUS_NO_SUCH_DEVICE; 1241 } 1242 1243 DEVICE_ACTION Action; 1244 1245 switch (ControlClass) 1246 { 1247 case PlugPlayControlEnumerateDevice: 1248 Action = PiActionEnumDeviceTree; 1249 break; 1250 case PlugPlayControlStartDevice: 1251 Action = PiActionStartDevice; 1252 break; 1253 case PlugPlayControlResetDevice: 1254 Action = PiActionResetDevice; 1255 break; 1256 default: 1257 UNREACHABLE; 1258 break; 1259 } 1260 1261 Status = PiPerformSyncDeviceAction(DeviceObject, Action); 1262 1263 ObDereferenceObject(DeviceObject); 1264 1265 return Status; 1266 } 1267 1268 static 1269 NTSTATUS 1270 PiControlQueryRemoveDevice( 1271 _In_ PPLUGPLAY_CONTROL_QUERY_REMOVE_DATA ControlData) 1272 { 1273 PDEVICE_OBJECT DeviceObject; 1274 NTSTATUS Status; 1275 UNICODE_STRING DeviceInstance; 1276 1277 Status = IopCaptureUnicodeString(&DeviceInstance, &ControlData->DeviceInstance); 1278 if (!NT_SUCCESS(Status)) 1279 { 1280 return Status; 1281 } 1282 1283 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 1284 if (DeviceInstance.Buffer != NULL) 1285 { 1286 ExFreePool(DeviceInstance.Buffer); 1287 } 1288 if (DeviceObject == NULL) 1289 { 1290 return STATUS_NO_SUCH_DEVICE; 1291 } 1292 1293 UNIMPLEMENTED; 1294 Status = STATUS_NOT_IMPLEMENTED; 1295 1296 ObDereferenceObject(DeviceObject); 1297 1298 return Status; 1299 } 1300 1301 /* PUBLIC FUNCTIONS **********************************************************/ 1302 1303 /* 1304 * Plug and Play event structure used by NtGetPlugPlayEvent. 1305 * 1306 * EventGuid 1307 * Can be one of the following values: 1308 * GUID_HWPROFILE_QUERY_CHANGE 1309 * GUID_HWPROFILE_CHANGE_CANCELLED 1310 * GUID_HWPROFILE_CHANGE_COMPLETE 1311 * GUID_TARGET_DEVICE_QUERY_REMOVE 1312 * GUID_TARGET_DEVICE_REMOVE_CANCELLED 1313 * GUID_TARGET_DEVICE_REMOVE_COMPLETE 1314 * GUID_PNP_CUSTOM_NOTIFICATION 1315 * GUID_PNP_POWER_NOTIFICATION 1316 * GUID_DEVICE_* (see above) 1317 * 1318 * EventCategory 1319 * Type of the event that happened. 1320 * 1321 * Result 1322 * ? 1323 * 1324 * Flags 1325 * ? 1326 * 1327 * TotalSize 1328 * Size of the event block including the device IDs and other 1329 * per category specific fields. 1330 */ 1331 1332 /* 1333 * NtGetPlugPlayEvent 1334 * 1335 * Returns one Plug & Play event from a global queue. 1336 * 1337 * Parameters 1338 * Reserved1 1339 * Reserved2 1340 * Always set to zero. 1341 * 1342 * Buffer 1343 * The buffer that will be filled with the event information on 1344 * successful return from the function. 1345 * 1346 * BufferSize 1347 * Size of the buffer pointed by the Buffer parameter. If the 1348 * buffer size is not large enough to hold the whole event 1349 * information, error STATUS_BUFFER_TOO_SMALL is returned and 1350 * the buffer remains untouched. 1351 * 1352 * Return Values 1353 * STATUS_PRIVILEGE_NOT_HELD 1354 * STATUS_BUFFER_TOO_SMALL 1355 * STATUS_SUCCESS 1356 * 1357 * Remarks 1358 * This function isn't multi-thread safe! 1359 * 1360 * @implemented 1361 */ 1362 NTSTATUS 1363 NTAPI 1364 NtGetPlugPlayEvent(IN ULONG Reserved1, 1365 IN ULONG Reserved2, 1366 OUT PPLUGPLAY_EVENT_BLOCK Buffer, 1367 IN ULONG BufferSize) 1368 { 1369 PPNP_EVENT_ENTRY Entry; 1370 NTSTATUS Status; 1371 1372 DPRINT("NtGetPlugPlayEvent() called\n"); 1373 1374 /* Function can only be called from user-mode */ 1375 if (KeGetPreviousMode() == KernelMode) 1376 { 1377 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n"); 1378 return STATUS_ACCESS_DENIED; 1379 } 1380 1381 /* Check for Tcb privilege */ 1382 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, 1383 UserMode)) 1384 { 1385 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n"); 1386 return STATUS_PRIVILEGE_NOT_HELD; 1387 } 1388 1389 /* Wait for a PnP event */ 1390 DPRINT("Waiting for pnp notification event\n"); 1391 Status = KeWaitForSingleObject(&IopPnpNotifyEvent, 1392 UserRequest, 1393 UserMode, 1394 FALSE, 1395 NULL); 1396 if (!NT_SUCCESS(Status) || Status == STATUS_USER_APC) 1397 { 1398 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status); 1399 ASSERT(Status == STATUS_USER_APC); 1400 return Status; 1401 } 1402 1403 /* Get entry from the tail of the queue */ 1404 Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink, 1405 PNP_EVENT_ENTRY, 1406 ListEntry); 1407 1408 /* Check the buffer size */ 1409 if (BufferSize < Entry->Event.TotalSize) 1410 { 1411 DPRINT1("Buffer is too small for the pnp-event\n"); 1412 return STATUS_BUFFER_TOO_SMALL; 1413 } 1414 1415 /* Copy event data to the user buffer */ 1416 _SEH2_TRY 1417 { 1418 ProbeForWrite(Buffer, 1419 Entry->Event.TotalSize, 1420 sizeof(UCHAR)); 1421 RtlCopyMemory(Buffer, 1422 &Entry->Event, 1423 Entry->Event.TotalSize); 1424 } 1425 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1426 { 1427 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1428 } 1429 _SEH2_END; 1430 1431 DPRINT("NtGetPlugPlayEvent() done\n"); 1432 1433 return STATUS_SUCCESS; 1434 } 1435 1436 /* 1437 * NtPlugPlayControl 1438 * 1439 * A function for doing various Plug & Play operations from user mode. 1440 * 1441 * Parameters 1442 * PlugPlayControlClass 1443 * 0x00 Reenumerate device tree 1444 * 1445 * Buffer points to UNICODE_STRING decribing the instance 1446 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For 1447 * more information about instance paths see !devnode command 1448 * in kernel debugger or look at "Inside Windows 2000" book, 1449 * chapter "Driver Loading, Initialization, and Installation". 1450 * 1451 * 0x01 Register new device 1452 * 0x02 Deregister device 1453 * 0x03 Initialize device 1454 * 0x04 Start device 1455 * 0x06 Query and remove device 1456 * 0x07 User response 1457 * 1458 * Called after processing the message from NtGetPlugPlayEvent. 1459 * 1460 * 0x08 Generate legacy device 1461 * 0x09 Get interface device list 1462 * 0x0A Get property data 1463 * 0x0B Device class association (Registration) 1464 * 0x0C Get related device 1465 * 0x0D Get device interface alias 1466 * 0x0E Get/set/clear device status 1467 * 0x0F Get device depth 1468 * 0x10 Query device relations 1469 * 0x11 Query target device relation 1470 * 0x12 Query conflict list 1471 * 0x13 Retrieve dock data 1472 * 0x14 Reset device 1473 * 0x15 Halt device 1474 * 0x16 Get blocked driver data 1475 * 1476 * Buffer 1477 * The buffer contains information that is specific to each control 1478 * code. The buffer is read-only. 1479 * 1480 * BufferSize 1481 * Size of the buffer pointed by the Buffer parameter. If the 1482 * buffer size specifies incorrect value for specified control 1483 * code, error ??? is returned. 1484 * 1485 * Return Values 1486 * STATUS_PRIVILEGE_NOT_HELD 1487 * STATUS_SUCCESS 1488 * ... 1489 * 1490 * @unimplemented 1491 */ 1492 NTSTATUS 1493 NTAPI 1494 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, 1495 IN OUT PVOID Buffer, 1496 IN ULONG BufferLength) 1497 { 1498 DPRINT("NtPlugPlayControl(%d %p %lu) called\n", 1499 PlugPlayControlClass, Buffer, BufferLength); 1500 1501 /* Function can only be called from user-mode */ 1502 if (KeGetPreviousMode() == KernelMode) 1503 { 1504 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n"); 1505 return STATUS_ACCESS_DENIED; 1506 } 1507 1508 /* Check for Tcb privilege */ 1509 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, 1510 UserMode)) 1511 { 1512 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n"); 1513 return STATUS_PRIVILEGE_NOT_HELD; 1514 } 1515 1516 /* Probe the buffer */ 1517 _SEH2_TRY 1518 { 1519 ProbeForWrite(Buffer, 1520 BufferLength, 1521 sizeof(ULONG)); 1522 } 1523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1524 { 1525 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1526 } 1527 _SEH2_END; 1528 1529 switch (PlugPlayControlClass) 1530 { 1531 case PlugPlayControlEnumerateDevice: 1532 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)) 1533 return STATUS_INVALID_PARAMETER; 1534 // the Flags field is not used anyway 1535 return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, 1536 PlugPlayControlClass); 1537 1538 // case PlugPlayControlRegisterNewDevice: 1539 // case PlugPlayControlDeregisterDevice: 1540 1541 case PlugPlayControlInitializeDevice: 1542 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) 1543 return STATUS_INVALID_PARAMETER; 1544 return PiControlInitializeDevice((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer); 1545 1546 case PlugPlayControlStartDevice: 1547 case PlugPlayControlResetDevice: 1548 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) 1549 return STATUS_INVALID_PARAMETER; 1550 return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, 1551 PlugPlayControlClass); 1552 1553 // case PlugPlayControlUnlockDevice: 1554 case PlugPlayControlQueryAndRemoveDevice: 1555 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_QUERY_REMOVE_DATA)) 1556 return STATUS_INVALID_PARAMETER; 1557 return PiControlQueryRemoveDevice((PPLUGPLAY_CONTROL_QUERY_REMOVE_DATA)Buffer); 1558 1559 case PlugPlayControlUserResponse: 1560 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA)) 1561 return STATUS_INVALID_PARAMETER; 1562 return IopRemovePlugPlayEvent((PPLUGPLAY_CONTROL_USER_RESPONSE_DATA)Buffer); 1563 1564 // case PlugPlayControlGenerateLegacyDevice: 1565 1566 case PlugPlayControlGetInterfaceDeviceList: 1567 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)) 1568 return STATUS_INVALID_PARAMETER; 1569 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer); 1570 1571 case PlugPlayControlProperty: 1572 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA)) 1573 return STATUS_INVALID_PARAMETER; 1574 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer); 1575 1576 // case PlugPlayControlDeviceClassAssociation: 1577 1578 case PlugPlayControlGetRelatedDevice: 1579 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA)) 1580 return STATUS_INVALID_PARAMETER; 1581 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer); 1582 1583 // case PlugPlayControlGetInterfaceDeviceAlias: 1584 1585 case PlugPlayControlDeviceStatus: 1586 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA)) 1587 return STATUS_INVALID_PARAMETER; 1588 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer); 1589 1590 case PlugPlayControlGetDeviceDepth: 1591 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA)) 1592 return STATUS_INVALID_PARAMETER; 1593 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer); 1594 1595 case PlugPlayControlQueryDeviceRelations: 1596 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)) 1597 return STATUS_INVALID_PARAMETER; 1598 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer); 1599 1600 // case PlugPlayControlTargetDeviceRelation: 1601 // case PlugPlayControlQueryConflictList: 1602 // case PlugPlayControlRetrieveDock: 1603 // case PlugPlayControlHaltDevice: 1604 // case PlugPlayControlGetBlockedDriverList: 1605 1606 default: 1607 return STATUS_NOT_IMPLEMENTED; 1608 } 1609 1610 return STATUS_NOT_IMPLEMENTED; 1611 } 1612