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