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