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