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 static NTSTATUS 190 IopPnpEnumerateDevice(PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA DeviceData) 191 { 192 PDEVICE_OBJECT DeviceObject; 193 UNICODE_STRING DeviceInstance; 194 NTSTATUS Status = STATUS_SUCCESS; 195 196 Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); 197 if (!NT_SUCCESS(Status)) 198 { 199 return Status; 200 } 201 202 DPRINT("IopPnpEnumerateDevice(%wZ)\n", &DeviceInstance); 203 204 /* Get the device object */ 205 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 206 if (DeviceInstance.Buffer != NULL) 207 { 208 ExFreePool(DeviceInstance.Buffer); 209 } 210 if (DeviceObject == NULL) 211 { 212 return STATUS_NO_SUCH_DEVICE; 213 } 214 215 Status = PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree); 216 217 ObDereferenceObject(DeviceObject); 218 219 return Status; 220 } 221 222 223 /* 224 * Remove the current PnP event from the tail of the event queue 225 * and signal IopPnpNotifyEvent if there is yet another event in the queue. 226 */ 227 static 228 NTSTATUS 229 IopRemovePlugPlayEvent( 230 _In_ PPLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData) 231 { 232 /* Remove a pnp event entry from the tail of the queue */ 233 if (!IsListEmpty(&IopPnpEventQueueHead)) 234 { 235 ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead), PNP_EVENT_ENTRY, ListEntry)); 236 } 237 238 /* Signal the next pnp event in the queue */ 239 if (!IsListEmpty(&IopPnpEventQueueHead)) 240 { 241 KeSetEvent(&IopPnpNotifyEvent, 242 0, 243 FALSE); 244 } 245 246 return STATUS_SUCCESS; 247 } 248 249 250 static NTSTATUS 251 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList) 252 { 253 NTSTATUS Status; 254 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList; 255 UNICODE_STRING DeviceInstance; 256 PDEVICE_OBJECT DeviceObject = NULL; 257 GUID FilterGuid; 258 PZZWSTR SymbolicLinkList = NULL, LinkList; 259 SIZE_T TotalLength; 260 261 _SEH2_TRY 262 { 263 RtlCopyMemory(&StackList, DeviceList, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)); 264 265 ProbeForRead(StackList.FilterGuid, sizeof(GUID), sizeof(UCHAR)); 266 RtlCopyMemory(&FilterGuid, StackList.FilterGuid, sizeof(GUID)); 267 268 if (StackList.Buffer != NULL && StackList.BufferSize != 0) 269 { 270 ProbeForWrite(StackList.Buffer, StackList.BufferSize, sizeof(UCHAR)); 271 } 272 } 273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 274 { 275 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 276 } 277 _SEH2_END; 278 279 Status = IopCaptureUnicodeString(&DeviceInstance, &StackList.DeviceInstance); 280 if (NT_SUCCESS(Status)) 281 { 282 /* Get the device object */ 283 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 284 if (DeviceInstance.Buffer != NULL) 285 { 286 ExFreePool(DeviceInstance.Buffer); 287 } 288 } 289 290 Status = IoGetDeviceInterfaces(&FilterGuid, DeviceObject, StackList.Flags, &SymbolicLinkList); 291 ObDereferenceObject(DeviceObject); 292 293 if (!NT_SUCCESS(Status)) 294 { 295 /* failed */ 296 return Status; 297 } 298 299 LinkList = SymbolicLinkList; 300 while (*SymbolicLinkList != UNICODE_NULL) 301 { 302 SymbolicLinkList += wcslen(SymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR)); 303 } 304 TotalLength = ((SymbolicLinkList - LinkList + 1) * sizeof(WCHAR)); 305 306 _SEH2_TRY 307 { 308 if (StackList.Buffer != NULL && 309 StackList.BufferSize >= TotalLength) 310 { 311 // We've already probed the buffer for writing above. 312 RtlCopyMemory(StackList.Buffer, LinkList, TotalLength); 313 } 314 315 DeviceList->BufferSize = TotalLength; 316 } 317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 318 { 319 ExFreePool(LinkList); 320 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 321 } 322 _SEH2_END; 323 324 ExFreePool(LinkList); 325 return STATUS_SUCCESS; 326 } 327 328 static NTSTATUS 329 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData) 330 { 331 PDEVICE_OBJECT DeviceObject = NULL; 332 PDEVICE_NODE DeviceNode; 333 UNICODE_STRING DeviceInstance; 334 ULONG BufferSize; 335 ULONG Property; 336 DEVICE_REGISTRY_PROPERTY DeviceProperty; 337 PVOID Buffer; 338 NTSTATUS Status; 339 340 DPRINT("IopGetDeviceProperty() called\n"); 341 DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance); 342 343 Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance); 344 if (!NT_SUCCESS(Status)) 345 { 346 return Status; 347 } 348 349 _SEH2_TRY 350 { 351 Property = PropertyData->Property; 352 BufferSize = PropertyData->BufferSize; 353 ProbeForWrite(PropertyData->Buffer, 354 BufferSize, 355 sizeof(UCHAR)); 356 } 357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 358 { 359 if (DeviceInstance.Buffer != NULL) 360 { 361 ExFreePool(DeviceInstance.Buffer); 362 } 363 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 364 } 365 _SEH2_END; 366 367 /* Get the device object */ 368 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 369 if (DeviceInstance.Buffer != NULL) 370 { 371 ExFreePool(DeviceInstance.Buffer); 372 } 373 if (DeviceObject == NULL) 374 { 375 return STATUS_NO_SUCH_DEVICE; 376 } 377 378 Buffer = ExAllocatePool(NonPagedPool, BufferSize); 379 if (Buffer == NULL) 380 { 381 ObDereferenceObject(DeviceObject); 382 return STATUS_INSUFFICIENT_RESOURCES; 383 } 384 385 386 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 387 388 if (Property == PNP_PROPERTY_POWER_DATA) 389 { 390 if (BufferSize < sizeof(CM_POWER_DATA)) 391 { 392 BufferSize = 0; 393 Status = STATUS_BUFFER_TOO_SMALL; 394 } 395 else 396 { 397 DEVICE_CAPABILITIES DeviceCapabilities; 398 PCM_POWER_DATA PowerData; 399 IO_STACK_LOCATION Stack; 400 IO_STATUS_BLOCK IoStatusBlock; 401 402 PowerData = (PCM_POWER_DATA)Buffer; 403 RtlZeroMemory(PowerData, sizeof(CM_POWER_DATA)); 404 PowerData->PD_Size = sizeof(CM_POWER_DATA); 405 406 RtlZeroMemory(&DeviceCapabilities, sizeof(DEVICE_CAPABILITIES)); 407 DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES); 408 DeviceCapabilities.Version = 1; 409 DeviceCapabilities.Address = -1; 410 DeviceCapabilities.UINumber = -1; 411 412 Stack.Parameters.DeviceCapabilities.Capabilities = &DeviceCapabilities; 413 414 Status = IopInitiatePnpIrp(DeviceObject, 415 &IoStatusBlock, 416 IRP_MN_QUERY_CAPABILITIES, 417 &Stack); 418 if (NT_SUCCESS(Status)) 419 { 420 DPRINT("Got device capabiliities\n"); 421 422 PowerData->PD_MostRecentPowerState = PowerDeviceD0; // FIXME 423 if (DeviceCapabilities.DeviceD1) 424 PowerData->PD_Capabilities |= PDCAP_D1_SUPPORTED; 425 if (DeviceCapabilities.DeviceD2) 426 PowerData->PD_Capabilities |= PDCAP_D2_SUPPORTED; 427 if (DeviceCapabilities.WakeFromD0) 428 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED; 429 if (DeviceCapabilities.WakeFromD1) 430 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D1_SUPPORTED; 431 if (DeviceCapabilities.WakeFromD2) 432 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D2_SUPPORTED; 433 if (DeviceCapabilities.WakeFromD3) 434 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED; 435 if (DeviceCapabilities.WarmEjectSupported) 436 PowerData->PD_Capabilities |= PDCAP_WARM_EJECT_SUPPORTED; 437 PowerData->PD_D1Latency = DeviceCapabilities.D1Latency; 438 PowerData->PD_D2Latency = DeviceCapabilities.D2Latency; 439 PowerData->PD_D3Latency = DeviceCapabilities.D3Latency; 440 RtlCopyMemory(&PowerData->PD_PowerStateMapping, 441 &DeviceCapabilities.DeviceState, 442 sizeof(DeviceCapabilities.DeviceState)); 443 PowerData->PD_DeepestSystemWake = DeviceCapabilities.SystemWake; 444 } 445 else 446 { 447 DPRINT("IRP_MN_QUERY_CAPABILITIES failed (Status 0x%08lx)\n", Status); 448 449 PowerData->PD_Capabilities = PDCAP_D0_SUPPORTED | PDCAP_D3_SUPPORTED; 450 PowerData->PD_MostRecentPowerState = PowerDeviceD0; 451 } 452 } 453 } 454 else if (Property == PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE) 455 { 456 } 457 else if (Property == PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT) 458 { 459 if (BufferSize < sizeof(DeviceNode->HardwareRemovalPolicy)) 460 { 461 BufferSize = 0; 462 Status = STATUS_BUFFER_TOO_SMALL; 463 } 464 else 465 { 466 BufferSize = sizeof(DeviceNode->HardwareRemovalPolicy); 467 RtlCopyMemory(Buffer, 468 &DeviceNode->HardwareRemovalPolicy, 469 BufferSize); 470 } 471 } 472 else 473 { 474 switch (Property) 475 { 476 case PNP_PROPERTY_UI_NUMBER: 477 DeviceProperty = DevicePropertyUINumber; 478 break; 479 480 case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME: 481 DeviceProperty = DevicePropertyPhysicalDeviceObjectName; 482 break; 483 484 case PNP_PROPERTY_BUSTYPEGUID: 485 DeviceProperty = DevicePropertyBusTypeGuid; 486 break; 487 488 case PNP_PROPERTY_LEGACYBUSTYPE: 489 DeviceProperty = DevicePropertyLegacyBusType; 490 break; 491 492 case PNP_PROPERTY_BUSNUMBER: 493 DeviceProperty = DevicePropertyBusNumber; 494 break; 495 496 case PNP_PROPERTY_REMOVAL_POLICY: 497 DeviceProperty = DevicePropertyRemovalPolicy; 498 break; 499 500 case PNP_PROPERTY_ADDRESS: 501 DeviceProperty = DevicePropertyAddress; 502 break; 503 504 case PNP_PROPERTY_ENUMERATOR_NAME: 505 DeviceProperty = DevicePropertyEnumeratorName; 506 break; 507 508 case PNP_PROPERTY_INSTALL_STATE: 509 DeviceProperty = DevicePropertyInstallState; 510 break; 511 512 #if (WINVER >= _WIN32_WINNT_WS03) 513 case PNP_PROPERTY_LOCATION_PATHS: 514 break; 515 #endif 516 517 #if (WINVER >= _WIN32_WINNT_WIN7) 518 case PNP_PROPERTY_CONTAINERID: 519 DeviceProperty = DevicePropertyContainerID; 520 break; 521 #endif 522 523 default: 524 BufferSize = 0; 525 Status = STATUS_INVALID_PARAMETER; 526 break; 527 } 528 529 if (Status == STATUS_SUCCESS) 530 { 531 Status = IoGetDeviceProperty(DeviceObject, 532 DeviceProperty, 533 BufferSize, 534 Buffer, 535 &BufferSize); 536 } 537 } 538 539 ObDereferenceObject(DeviceObject); 540 541 if (NT_SUCCESS(Status)) 542 { 543 _SEH2_TRY 544 { 545 RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize); 546 PropertyData->BufferSize = BufferSize; 547 } 548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 549 { 550 Status = _SEH2_GetExceptionCode(); 551 } 552 _SEH2_END; 553 } 554 555 ExFreePool(Buffer); 556 return Status; 557 } 558 559 560 static NTSTATUS 561 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData) 562 { 563 UNICODE_STRING RootDeviceName; 564 PDEVICE_OBJECT DeviceObject = NULL; 565 PDEVICE_NODE DeviceNode = NULL; 566 PDEVICE_NODE RelatedDeviceNode; 567 UNICODE_STRING TargetDeviceInstance; 568 NTSTATUS Status = STATUS_SUCCESS; 569 ULONG Relation = 0; 570 ULONG MaximumLength = 0; 571 572 DPRINT("IopGetRelatedDevice() called\n"); 573 DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance); 574 575 Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance); 576 if (!NT_SUCCESS(Status)) 577 { 578 return Status; 579 } 580 581 _SEH2_TRY 582 { 583 Relation = RelatedDeviceData->Relation; 584 MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength; 585 ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance, 586 MaximumLength, 587 sizeof(WCHAR)); 588 } 589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 590 { 591 if (TargetDeviceInstance.Buffer != NULL) 592 { 593 ExFreePool(TargetDeviceInstance.Buffer); 594 } 595 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 596 } 597 _SEH2_END; 598 599 RtlInitUnicodeString(&RootDeviceName, 600 L"HTREE\\ROOT\\0"); 601 if (RtlEqualUnicodeString(&TargetDeviceInstance, 602 &RootDeviceName, 603 TRUE)) 604 { 605 DeviceNode = IopRootDeviceNode; 606 if (TargetDeviceInstance.Buffer != NULL) 607 { 608 ExFreePool(TargetDeviceInstance.Buffer); 609 } 610 } 611 else 612 { 613 /* Get the device object */ 614 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance); 615 if (TargetDeviceInstance.Buffer != NULL) 616 { 617 ExFreePool(TargetDeviceInstance.Buffer); 618 } 619 if (DeviceObject == NULL) 620 return STATUS_NO_SUCH_DEVICE; 621 622 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 623 } 624 625 switch (Relation) 626 { 627 case PNP_GET_PARENT_DEVICE: 628 RelatedDeviceNode = DeviceNode->Parent; 629 break; 630 631 case PNP_GET_CHILD_DEVICE: 632 RelatedDeviceNode = DeviceNode->Child; 633 break; 634 635 case PNP_GET_SIBLING_DEVICE: 636 RelatedDeviceNode = DeviceNode->Sibling; 637 break; 638 639 default: 640 if (DeviceObject != NULL) 641 { 642 ObDereferenceObject(DeviceObject); 643 } 644 645 return STATUS_INVALID_PARAMETER; 646 } 647 648 if (RelatedDeviceNode == NULL) 649 { 650 if (DeviceObject) 651 { 652 ObDereferenceObject(DeviceObject); 653 } 654 655 return STATUS_NO_SUCH_DEVICE; 656 } 657 658 if (RelatedDeviceNode->InstancePath.Length > MaximumLength) 659 { 660 if (DeviceObject) 661 { 662 ObDereferenceObject(DeviceObject); 663 } 664 665 return STATUS_BUFFER_TOO_SMALL; 666 } 667 668 /* Copy related device instance name */ 669 _SEH2_TRY 670 { 671 RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance, 672 RelatedDeviceNode->InstancePath.Buffer, 673 RelatedDeviceNode->InstancePath.Length); 674 RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length; 675 } 676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 677 { 678 Status = _SEH2_GetExceptionCode(); 679 } 680 _SEH2_END; 681 682 if (DeviceObject != NULL) 683 { 684 ObDereferenceObject(DeviceObject); 685 } 686 687 DPRINT("IopGetRelatedDevice() done\n"); 688 689 return Status; 690 } 691 692 static ULONG 693 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode) 694 { 695 ULONG Output = 0; 696 697 if (DeviceNode->Parent == IopRootDeviceNode) 698 Output |= DN_ROOT_ENUMERATED; 699 700 if (DeviceNode->Flags & DNF_ADDED) 701 Output |= DN_DRIVER_LOADED; 702 703 /* FIXME: DN_ENUM_LOADED */ 704 705 if (DeviceNode->Flags & DNF_STARTED) 706 Output |= DN_STARTED; 707 708 /* FIXME: Manual */ 709 710 if (!(DeviceNode->Flags & DNF_PROCESSED)) 711 Output |= DN_NEED_TO_ENUM; 712 713 /* DN_NOT_FIRST_TIME is 9x only */ 714 715 /* FIXME: DN_HARDWARE_ENUM */ 716 717 /* DN_LIAR and DN_HAS_MARK are 9x only */ 718 719 if (DeviceNode->Problem != 0) 720 Output |= DN_HAS_PROBLEM; 721 722 /* FIXME: DN_FILTERED */ 723 724 if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 725 Output |= DN_LEGACY_DRIVER; 726 727 if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI) 728 Output |= DN_NO_SHOW_IN_DM; 729 730 if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE)) 731 Output |= DN_DISABLEABLE; 732 733 /* FIXME: Implement the rest */ 734 735 Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER; 736 737 return Output; 738 } 739 740 static NTSTATUS 741 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData) 742 { 743 PDEVICE_OBJECT DeviceObject; 744 PDEVICE_NODE DeviceNode; 745 ULONG Operation = 0; 746 ULONG DeviceStatus = 0; 747 ULONG DeviceProblem = 0; 748 UNICODE_STRING DeviceInstance; 749 NTSTATUS Status; 750 751 DPRINT("IopDeviceStatus() called\n"); 752 753 Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance); 754 if (!NT_SUCCESS(Status)) 755 { 756 return Status; 757 } 758 759 DPRINT("Device name: '%wZ'\n", &DeviceInstance); 760 761 _SEH2_TRY 762 { 763 Operation = StatusData->Operation; 764 if (Operation == PNP_SET_DEVICE_STATUS) 765 { 766 DeviceStatus = StatusData->DeviceStatus; 767 DeviceProblem = StatusData->DeviceProblem; 768 } 769 } 770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 771 { 772 if (DeviceInstance.Buffer != NULL) 773 { 774 ExFreePool(DeviceInstance.Buffer); 775 } 776 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 777 } 778 _SEH2_END; 779 780 /* Get the device object */ 781 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 782 if (DeviceInstance.Buffer != NULL) 783 { 784 ExFreePool(DeviceInstance.Buffer); 785 } 786 if (DeviceObject == NULL) 787 { 788 return STATUS_NO_SUCH_DEVICE; 789 } 790 791 DeviceNode = IopGetDeviceNode(DeviceObject); 792 793 switch (Operation) 794 { 795 case PNP_GET_DEVICE_STATUS: 796 DPRINT("Get status data\n"); 797 DeviceStatus = IopGetDeviceNodeStatus(DeviceNode); 798 DeviceProblem = DeviceNode->Problem; 799 break; 800 801 case PNP_SET_DEVICE_STATUS: 802 DPRINT1("Set status data is NOT SUPPORTED\n"); 803 break; 804 805 case PNP_CLEAR_DEVICE_STATUS: 806 DPRINT1("FIXME: Clear status data!\n"); 807 break; 808 } 809 810 ObDereferenceObject(DeviceObject); 811 812 if (Operation == PNP_GET_DEVICE_STATUS) 813 { 814 _SEH2_TRY 815 { 816 StatusData->DeviceStatus = DeviceStatus; 817 StatusData->DeviceProblem = DeviceProblem; 818 } 819 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 820 { 821 Status = _SEH2_GetExceptionCode(); 822 } 823 _SEH2_END; 824 } 825 826 return Status; 827 } 828 829 static 830 NTSTATUS 831 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData) 832 { 833 UNICODE_STRING DeviceInstance; 834 PDEVICE_OBJECT DeviceObject = NULL; 835 IO_STACK_LOCATION Stack; 836 IO_STATUS_BLOCK IoStatusBlock; 837 PDEVICE_RELATIONS DeviceRelations = NULL; 838 PDEVICE_OBJECT ChildDeviceObject; 839 PDEVICE_NODE ChildDeviceNode; 840 ULONG i; 841 ULONG Relations; 842 ULONG BufferSize, RequiredSize; 843 ULONG BufferLeft; 844 PWCHAR Buffer, Ptr; 845 NTSTATUS Status = STATUS_SUCCESS; 846 847 DPRINT("IopGetDeviceRelations() called\n"); 848 DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance); 849 DPRINT("Relations: %lu\n", RelationsData->Relations); 850 DPRINT("BufferSize: %lu\n", RelationsData->BufferSize); 851 DPRINT("Buffer: %p\n", RelationsData->Buffer); 852 853 _SEH2_TRY 854 { 855 Relations = RelationsData->Relations; 856 BufferSize = RelationsData->BufferSize; 857 Buffer = RelationsData->Buffer; 858 859 ProbeForWrite(Buffer, BufferSize, sizeof(CHAR)); 860 } 861 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 862 { 863 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 864 } 865 _SEH2_END; 866 867 Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance); 868 if (!NT_SUCCESS(Status)) 869 { 870 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status); 871 return Status; 872 } 873 874 /* Get the device object */ 875 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 876 if (DeviceObject == NULL) 877 { 878 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n"); 879 Status = STATUS_NO_SUCH_DEVICE; 880 goto done; 881 } 882 883 switch (Relations) 884 { 885 case PNP_EJECT_RELATIONS: 886 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 887 break; 888 889 case PNP_REMOVAL_RELATIONS: 890 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 891 break; 892 893 case PNP_POWER_RELATIONS: 894 Stack.Parameters.QueryDeviceRelations.Type = PowerRelations; 895 break; 896 897 case PNP_BUS_RELATIONS: 898 Stack.Parameters.QueryDeviceRelations.Type = BusRelations; 899 break; 900 901 default: 902 Status = STATUS_INVALID_PARAMETER; 903 goto done; 904 } 905 906 Status = IopInitiatePnpIrp(DeviceObject, 907 &IoStatusBlock, 908 IRP_MN_QUERY_DEVICE_RELATIONS, 909 &Stack); 910 if (!NT_SUCCESS(Status)) 911 { 912 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 913 goto done; 914 } 915 916 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 917 918 DPRINT("Found %d device relations\n", DeviceRelations->Count); 919 920 _SEH2_TRY 921 { 922 RequiredSize = 0; 923 BufferLeft = BufferSize; 924 Ptr = Buffer; 925 926 for (i = 0; i < DeviceRelations->Count; i++) 927 { 928 ChildDeviceObject = DeviceRelations->Objects[i]; 929 930 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 931 if (ChildDeviceNode) 932 { 933 DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath); 934 DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 935 936 if (Ptr != NULL) 937 { 938 if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR)) 939 { 940 Status = STATUS_BUFFER_TOO_SMALL; 941 break; 942 } 943 944 RtlCopyMemory(Ptr, 945 ChildDeviceNode->InstancePath.Buffer, 946 ChildDeviceNode->InstancePath.Length); 947 Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length); 948 *Ptr = UNICODE_NULL; 949 Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR)); 950 951 BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 952 } 953 954 RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 955 } 956 } 957 958 if (Ptr != NULL && BufferLeft >= sizeof(WCHAR)) 959 *Ptr = UNICODE_NULL; 960 961 if (RequiredSize > 0) 962 RequiredSize += sizeof(WCHAR); 963 964 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize); 965 966 RelationsData->BufferSize = RequiredSize; 967 } 968 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 969 { 970 Status = _SEH2_GetExceptionCode(); 971 } 972 _SEH2_END; 973 974 done: 975 if (DeviceRelations != NULL) 976 ExFreePool(DeviceRelations); 977 978 if (DeviceObject != NULL) 979 ObDereferenceObject(DeviceObject); 980 981 if (DeviceInstance.Buffer != NULL) 982 ExFreePool(DeviceInstance.Buffer); 983 984 return Status; 985 } 986 987 static NTSTATUS 988 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) 989 { 990 PDEVICE_OBJECT DeviceObject; 991 PDEVICE_NODE DeviceNode; 992 UNICODE_STRING DeviceInstance; 993 NTSTATUS Status = STATUS_SUCCESS; 994 995 DPRINT("IopGetDeviceDepth() called\n"); 996 DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance); 997 998 Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance); 999 if (!NT_SUCCESS(Status)) 1000 { 1001 return Status; 1002 } 1003 1004 /* Get the device object */ 1005 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 1006 if (DeviceInstance.Buffer != NULL) 1007 { 1008 ExFreePool(DeviceInstance.Buffer); 1009 } 1010 if (DeviceObject == NULL) 1011 { 1012 return STATUS_NO_SUCH_DEVICE; 1013 } 1014 1015 DeviceNode = IopGetDeviceNode(DeviceObject); 1016 1017 _SEH2_TRY 1018 { 1019 DepthData->Depth = DeviceNode->Level; 1020 } 1021 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1022 { 1023 Status = _SEH2_GetExceptionCode(); 1024 } 1025 _SEH2_END; 1026 1027 ObDereferenceObject(DeviceObject); 1028 1029 return Status; 1030 } 1031 1032 1033 static NTSTATUS 1034 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData) 1035 { 1036 PDEVICE_OBJECT DeviceObject; 1037 NTSTATUS Status; 1038 UNICODE_STRING DeviceInstance; 1039 1040 Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance); 1041 if (!NT_SUCCESS(Status)) 1042 { 1043 return Status; 1044 } 1045 1046 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance); 1047 1048 /* Get the device object */ 1049 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 1050 if (DeviceInstance.Buffer != NULL) 1051 { 1052 ExFreePool(DeviceInstance.Buffer); 1053 } 1054 if (DeviceObject == NULL) 1055 { 1056 return STATUS_NO_SUCH_DEVICE; 1057 } 1058 1059 Status = PiPerformSyncDeviceAction(DeviceObject, PiActionResetDevice); 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 return IopPnpEnumerateDevice((PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)Buffer); 1300 1301 // case PlugPlayControlRegisterNewDevice: 1302 // case PlugPlayControlDeregisterDevice: 1303 // case PlugPlayControlInitializeDevice: 1304 // case PlugPlayControlStartDevice: 1305 // case PlugPlayControlUnlockDevice: 1306 // case PlugPlayControlQueryAndRemoveDevice: 1307 1308 case PlugPlayControlUserResponse: 1309 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA)) 1310 return STATUS_INVALID_PARAMETER; 1311 return IopRemovePlugPlayEvent((PPLUGPLAY_CONTROL_USER_RESPONSE_DATA)Buffer); 1312 1313 // case PlugPlayControlGenerateLegacyDevice: 1314 1315 case PlugPlayControlGetInterfaceDeviceList: 1316 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)) 1317 return STATUS_INVALID_PARAMETER; 1318 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer); 1319 1320 case PlugPlayControlProperty: 1321 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA)) 1322 return STATUS_INVALID_PARAMETER; 1323 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer); 1324 1325 // case PlugPlayControlDeviceClassAssociation: 1326 1327 case PlugPlayControlGetRelatedDevice: 1328 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA)) 1329 return STATUS_INVALID_PARAMETER; 1330 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer); 1331 1332 // case PlugPlayControlGetInterfaceDeviceAlias: 1333 1334 case PlugPlayControlDeviceStatus: 1335 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA)) 1336 return STATUS_INVALID_PARAMETER; 1337 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer); 1338 1339 case PlugPlayControlGetDeviceDepth: 1340 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA)) 1341 return STATUS_INVALID_PARAMETER; 1342 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer); 1343 1344 case PlugPlayControlQueryDeviceRelations: 1345 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)) 1346 return STATUS_INVALID_PARAMETER; 1347 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer); 1348 1349 // case PlugPlayControlTargetDeviceRelation: 1350 // case PlugPlayControlQueryConflictList: 1351 // case PlugPlayControlRetrieveDock: 1352 1353 case PlugPlayControlResetDevice: 1354 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)) 1355 return STATUS_INVALID_PARAMETER; 1356 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer); 1357 1358 // case PlugPlayControlHaltDevice: 1359 // case PlugPlayControlGetBlockedDriverList: 1360 1361 default: 1362 return STATUS_NOT_IMPLEMENTED; 1363 } 1364 1365 return STATUS_NOT_IMPLEMENTED; 1366 } 1367