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 365 // Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 366 367 PowerData = (PCM_POWER_DATA)Buffer; 368 369 RtlZeroMemory(PowerData, sizeof(CM_POWER_DATA)); 370 PowerData->PD_Size = sizeof(CM_POWER_DATA); 371 // PowerData->PD_MostRecentPowerState; 372 PowerData->PD_Capabilities = PDCAP_D0_SUPPORTED | PDCAP_D3_SUPPORTED; 373 /* 374 if (DeviceCapabilities.DeviceD1) 375 PowerData->PD_Capabilities |= PDCAP_D1_SUPPORTED; 376 if (DeviceCapabilities.DeviceD2) 377 PowerData->PD_Capabilities |= PDCAP_D2_SUPPORTED; 378 if (DeviceCapabilities.WakeFromD0) 379 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED; 380 if (DeviceCapabilities.WakeFromD1) 381 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D1_SUPPORTED; 382 if (DeviceCapabilities.WakeFromD2) 383 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D2_SUPPORTED; 384 if (DeviceCapabilities.WakeFromD3) 385 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED; 386 if (DeviceCapabilities.WarmEjectSupported) 387 PowerData->PD_Capabilities |= PDCAP_WARM_EJECT_SUPPORTED; 388 PowerData->PD_D1Latency = DeviceCapabilities.D1Latency; 389 PowerData->PD_D2Latency = DeviceCapabilities.D2Latency; 390 PowerData->PD_D3Latency = DeviceCapabilities.D3Latency; 391 RtlCopyMemory(&PowerData->PD_PowerStateMapping, 392 &DeviceCapabilities.DeviceState, 393 sizeof(DeviceCapabilities.DeviceState)); 394 PowerData->PD_DeepestSystemWake = DeviceCapabilities.SystemWake; 395 */ 396 } 397 } 398 else if (Property == PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE) 399 { 400 } 401 else if (Property == PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT) 402 { 403 if (BufferSize < sizeof(DeviceNode->HardwareRemovalPolicy)) 404 { 405 BufferSize = 0; 406 Status = STATUS_BUFFER_TOO_SMALL; 407 } 408 else 409 { 410 BufferSize = sizeof(DeviceNode->HardwareRemovalPolicy); 411 RtlCopyMemory(Buffer, 412 &DeviceNode->HardwareRemovalPolicy, 413 BufferSize); 414 } 415 } 416 else 417 { 418 switch (Property) 419 { 420 case PNP_PROPERTY_UI_NUMBER: 421 DeviceProperty = DevicePropertyUINumber; 422 break; 423 424 case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME: 425 DeviceProperty = DevicePropertyPhysicalDeviceObjectName; 426 break; 427 428 case PNP_PROPERTY_BUSTYPEGUID: 429 DeviceProperty = DevicePropertyBusTypeGuid; 430 break; 431 432 case PNP_PROPERTY_LEGACYBUSTYPE: 433 DeviceProperty = DevicePropertyLegacyBusType; 434 break; 435 436 case PNP_PROPERTY_BUSNUMBER: 437 DeviceProperty = DevicePropertyBusNumber; 438 break; 439 440 case PNP_PROPERTY_REMOVAL_POLICY: 441 DeviceProperty = DevicePropertyRemovalPolicy; 442 break; 443 444 case PNP_PROPERTY_ADDRESS: 445 DeviceProperty = DevicePropertyAddress; 446 break; 447 448 case PNP_PROPERTY_ENUMERATOR_NAME: 449 DeviceProperty = DevicePropertyEnumeratorName; 450 break; 451 452 case PNP_PROPERTY_INSTALL_STATE: 453 DeviceProperty = DevicePropertyInstallState; 454 break; 455 456 #if (WINVER >= _WIN32_WINNT_WS03) 457 case PNP_PROPERTY_LOCATION_PATHS: 458 break; 459 #endif 460 461 #if (WINVER >= _WIN32_WINNT_WIN7) 462 case PNP_PROPERTY_CONTAINERID: 463 DeviceProperty = DevicePropertyContainerID; 464 break; 465 #endif 466 467 default: 468 BufferSize = 0; 469 Status = STATUS_INVALID_PARAMETER; 470 break; 471 } 472 473 if (Status == STATUS_SUCCESS) 474 { 475 Status = IoGetDeviceProperty(DeviceObject, 476 DeviceProperty, 477 BufferSize, 478 Buffer, 479 &BufferSize); 480 } 481 } 482 483 ObDereferenceObject(DeviceObject); 484 485 if (NT_SUCCESS(Status)) 486 { 487 _SEH2_TRY 488 { 489 RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize); 490 PropertyData->BufferSize = BufferSize; 491 } 492 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 493 { 494 Status = _SEH2_GetExceptionCode(); 495 } 496 _SEH2_END; 497 } 498 499 ExFreePool(Buffer); 500 return Status; 501 } 502 503 504 static NTSTATUS 505 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData) 506 { 507 UNICODE_STRING RootDeviceName; 508 PDEVICE_OBJECT DeviceObject = NULL; 509 PDEVICE_NODE DeviceNode = NULL; 510 PDEVICE_NODE RelatedDeviceNode; 511 UNICODE_STRING TargetDeviceInstance; 512 NTSTATUS Status = STATUS_SUCCESS; 513 ULONG Relation = 0; 514 ULONG MaximumLength = 0; 515 516 DPRINT("IopGetRelatedDevice() called\n"); 517 DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance); 518 519 Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance); 520 if (!NT_SUCCESS(Status)) 521 { 522 return Status; 523 } 524 525 _SEH2_TRY 526 { 527 Relation = RelatedDeviceData->Relation; 528 MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength; 529 ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance, 530 MaximumLength, 531 sizeof(WCHAR)); 532 } 533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 534 { 535 if (TargetDeviceInstance.Buffer != NULL) 536 { 537 ExFreePool(TargetDeviceInstance.Buffer); 538 } 539 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 540 } 541 _SEH2_END; 542 543 RtlInitUnicodeString(&RootDeviceName, 544 L"HTREE\\ROOT\\0"); 545 if (RtlEqualUnicodeString(&TargetDeviceInstance, 546 &RootDeviceName, 547 TRUE)) 548 { 549 DeviceNode = IopRootDeviceNode; 550 if (TargetDeviceInstance.Buffer != NULL) 551 { 552 ExFreePool(TargetDeviceInstance.Buffer); 553 } 554 } 555 else 556 { 557 /* Get the device object */ 558 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance); 559 if (TargetDeviceInstance.Buffer != NULL) 560 { 561 ExFreePool(TargetDeviceInstance.Buffer); 562 } 563 if (DeviceObject == NULL) 564 return STATUS_NO_SUCH_DEVICE; 565 566 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 567 } 568 569 switch (Relation) 570 { 571 case PNP_GET_PARENT_DEVICE: 572 RelatedDeviceNode = DeviceNode->Parent; 573 break; 574 575 case PNP_GET_CHILD_DEVICE: 576 RelatedDeviceNode = DeviceNode->Child; 577 break; 578 579 case PNP_GET_SIBLING_DEVICE: 580 RelatedDeviceNode = DeviceNode->Sibling; 581 break; 582 583 default: 584 if (DeviceObject != NULL) 585 { 586 ObDereferenceObject(DeviceObject); 587 } 588 589 return STATUS_INVALID_PARAMETER; 590 } 591 592 if (RelatedDeviceNode == NULL) 593 { 594 if (DeviceObject) 595 { 596 ObDereferenceObject(DeviceObject); 597 } 598 599 return STATUS_NO_SUCH_DEVICE; 600 } 601 602 if (RelatedDeviceNode->InstancePath.Length > MaximumLength) 603 { 604 if (DeviceObject) 605 { 606 ObDereferenceObject(DeviceObject); 607 } 608 609 return STATUS_BUFFER_TOO_SMALL; 610 } 611 612 /* Copy related device instance name */ 613 _SEH2_TRY 614 { 615 RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance, 616 RelatedDeviceNode->InstancePath.Buffer, 617 RelatedDeviceNode->InstancePath.Length); 618 RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length; 619 } 620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 621 { 622 Status = _SEH2_GetExceptionCode(); 623 } 624 _SEH2_END; 625 626 if (DeviceObject != NULL) 627 { 628 ObDereferenceObject(DeviceObject); 629 } 630 631 DPRINT("IopGetRelatedDevice() done\n"); 632 633 return Status; 634 } 635 636 static ULONG 637 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode) 638 { 639 ULONG Output = 0; 640 641 if (DeviceNode->Parent == IopRootDeviceNode) 642 Output |= DN_ROOT_ENUMERATED; 643 644 if (DeviceNode->Flags & DNF_ADDED) 645 Output |= DN_DRIVER_LOADED; 646 647 /* FIXME: DN_ENUM_LOADED */ 648 649 if (DeviceNode->Flags & DNF_STARTED) 650 Output |= DN_STARTED; 651 652 /* FIXME: Manual */ 653 654 if (!(DeviceNode->Flags & DNF_PROCESSED)) 655 Output |= DN_NEED_TO_ENUM; 656 657 /* DN_NOT_FIRST_TIME is 9x only */ 658 659 /* FIXME: DN_HARDWARE_ENUM */ 660 661 /* DN_LIAR and DN_HAS_MARK are 9x only */ 662 663 if (DeviceNode->Problem != 0) 664 Output |= DN_HAS_PROBLEM; 665 666 /* FIXME: DN_FILTERED */ 667 668 if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 669 Output |= DN_LEGACY_DRIVER; 670 671 if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI) 672 Output |= DN_NO_SHOW_IN_DM; 673 674 if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE)) 675 Output |= DN_DISABLEABLE; 676 677 /* FIXME: Implement the rest */ 678 679 Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER; 680 681 return Output; 682 } 683 684 static NTSTATUS 685 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData) 686 { 687 PDEVICE_OBJECT DeviceObject; 688 PDEVICE_NODE DeviceNode; 689 ULONG Operation = 0; 690 ULONG DeviceStatus = 0; 691 ULONG DeviceProblem = 0; 692 UNICODE_STRING DeviceInstance; 693 NTSTATUS Status; 694 695 DPRINT("IopDeviceStatus() called\n"); 696 697 Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance); 698 if (!NT_SUCCESS(Status)) 699 { 700 return Status; 701 } 702 703 DPRINT("Device name: '%wZ'\n", &DeviceInstance); 704 705 _SEH2_TRY 706 { 707 Operation = StatusData->Operation; 708 if (Operation == PNP_SET_DEVICE_STATUS) 709 { 710 DeviceStatus = StatusData->DeviceStatus; 711 DeviceProblem = StatusData->DeviceProblem; 712 } 713 } 714 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 715 { 716 if (DeviceInstance.Buffer != NULL) 717 { 718 ExFreePool(DeviceInstance.Buffer); 719 } 720 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 721 } 722 _SEH2_END; 723 724 /* Get the device object */ 725 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 726 if (DeviceInstance.Buffer != NULL) 727 { 728 ExFreePool(DeviceInstance.Buffer); 729 } 730 if (DeviceObject == NULL) 731 { 732 return STATUS_NO_SUCH_DEVICE; 733 } 734 735 DeviceNode = IopGetDeviceNode(DeviceObject); 736 737 switch (Operation) 738 { 739 case PNP_GET_DEVICE_STATUS: 740 DPRINT("Get status data\n"); 741 DeviceStatus = IopGetDeviceNodeStatus(DeviceNode); 742 DeviceProblem = DeviceNode->Problem; 743 break; 744 745 case PNP_SET_DEVICE_STATUS: 746 DPRINT1("Set status data is NOT SUPPORTED\n"); 747 break; 748 749 case PNP_CLEAR_DEVICE_STATUS: 750 DPRINT1("FIXME: Clear status data!\n"); 751 break; 752 } 753 754 ObDereferenceObject(DeviceObject); 755 756 if (Operation == PNP_GET_DEVICE_STATUS) 757 { 758 _SEH2_TRY 759 { 760 StatusData->DeviceStatus = DeviceStatus; 761 StatusData->DeviceProblem = DeviceProblem; 762 } 763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 764 { 765 Status = _SEH2_GetExceptionCode(); 766 } 767 _SEH2_END; 768 } 769 770 return Status; 771 } 772 773 static 774 NTSTATUS 775 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData) 776 { 777 UNICODE_STRING DeviceInstance; 778 PDEVICE_OBJECT DeviceObject = NULL; 779 IO_STACK_LOCATION Stack; 780 IO_STATUS_BLOCK IoStatusBlock; 781 PDEVICE_RELATIONS DeviceRelations = NULL; 782 PDEVICE_OBJECT ChildDeviceObject; 783 PDEVICE_NODE ChildDeviceNode; 784 ULONG i; 785 ULONG Relations; 786 ULONG BufferSize, RequiredSize; 787 ULONG BufferLeft; 788 PWCHAR Buffer, Ptr; 789 NTSTATUS Status = STATUS_SUCCESS; 790 791 DPRINT("IopGetDeviceRelations() called\n"); 792 DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance); 793 DPRINT("Relations: %lu\n", RelationsData->Relations); 794 DPRINT("BufferSize: %lu\n", RelationsData->BufferSize); 795 DPRINT("Buffer: %p\n", RelationsData->Buffer); 796 797 _SEH2_TRY 798 { 799 Relations = RelationsData->Relations; 800 BufferSize = RelationsData->BufferSize; 801 Buffer = RelationsData->Buffer; 802 803 ProbeForWrite(Buffer, BufferSize, sizeof(CHAR)); 804 } 805 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 806 { 807 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 808 } 809 _SEH2_END; 810 811 Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance); 812 if (!NT_SUCCESS(Status)) 813 { 814 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status); 815 return Status; 816 } 817 818 /* Get the device object */ 819 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 820 if (DeviceObject == NULL) 821 { 822 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n"); 823 Status = STATUS_NO_SUCH_DEVICE; 824 goto done; 825 } 826 827 switch (Relations) 828 { 829 case PNP_EJECT_RELATIONS: 830 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 831 break; 832 833 case PNP_REMOVAL_RELATIONS: 834 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 835 break; 836 837 case PNP_POWER_RELATIONS: 838 Stack.Parameters.QueryDeviceRelations.Type = PowerRelations; 839 break; 840 841 case PNP_BUS_RELATIONS: 842 Stack.Parameters.QueryDeviceRelations.Type = BusRelations; 843 break; 844 845 default: 846 Status = STATUS_INVALID_PARAMETER; 847 goto done; 848 } 849 850 Status = IopInitiatePnpIrp(DeviceObject, 851 &IoStatusBlock, 852 IRP_MN_QUERY_DEVICE_RELATIONS, 853 &Stack); 854 if (!NT_SUCCESS(Status)) 855 { 856 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 857 goto done; 858 } 859 860 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 861 862 DPRINT("Found %d device relations\n", DeviceRelations->Count); 863 864 _SEH2_TRY 865 { 866 RequiredSize = 0; 867 BufferLeft = BufferSize; 868 Ptr = Buffer; 869 870 for (i = 0; i < DeviceRelations->Count; i++) 871 { 872 ChildDeviceObject = DeviceRelations->Objects[i]; 873 874 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 875 if (ChildDeviceNode) 876 { 877 DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath); 878 DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 879 880 if (Ptr != NULL) 881 { 882 if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR)) 883 { 884 Status = STATUS_BUFFER_TOO_SMALL; 885 break; 886 } 887 888 RtlCopyMemory(Ptr, 889 ChildDeviceNode->InstancePath.Buffer, 890 ChildDeviceNode->InstancePath.Length); 891 Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length); 892 *Ptr = UNICODE_NULL; 893 Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR)); 894 895 BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 896 } 897 898 RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR)); 899 } 900 } 901 902 if (Ptr != NULL && BufferLeft >= sizeof(WCHAR)) 903 *Ptr = UNICODE_NULL; 904 905 if (RequiredSize > 0) 906 RequiredSize += sizeof(WCHAR); 907 908 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize); 909 910 RelationsData->BufferSize = RequiredSize; 911 } 912 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 913 { 914 Status = _SEH2_GetExceptionCode(); 915 } 916 _SEH2_END; 917 918 done: 919 if (DeviceRelations != NULL) 920 ExFreePool(DeviceRelations); 921 922 if (DeviceObject != NULL) 923 ObDereferenceObject(DeviceObject); 924 925 if (DeviceInstance.Buffer != NULL) 926 ExFreePool(DeviceInstance.Buffer); 927 928 return Status; 929 } 930 931 static NTSTATUS 932 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) 933 { 934 PDEVICE_OBJECT DeviceObject; 935 PDEVICE_NODE DeviceNode; 936 UNICODE_STRING DeviceInstance; 937 NTSTATUS Status = STATUS_SUCCESS; 938 939 DPRINT("IopGetDeviceDepth() called\n"); 940 DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance); 941 942 Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance); 943 if (!NT_SUCCESS(Status)) 944 { 945 return Status; 946 } 947 948 /* Get the device object */ 949 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 950 if (DeviceInstance.Buffer != NULL) 951 { 952 ExFreePool(DeviceInstance.Buffer); 953 } 954 if (DeviceObject == NULL) 955 { 956 return STATUS_NO_SUCH_DEVICE; 957 } 958 959 DeviceNode = IopGetDeviceNode(DeviceObject); 960 961 _SEH2_TRY 962 { 963 DepthData->Depth = DeviceNode->Level; 964 } 965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 966 { 967 Status = _SEH2_GetExceptionCode(); 968 } 969 _SEH2_END; 970 971 ObDereferenceObject(DeviceObject); 972 973 return Status; 974 } 975 976 977 static NTSTATUS 978 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData) 979 { 980 PDEVICE_OBJECT DeviceObject; 981 PDEVICE_NODE DeviceNode; 982 NTSTATUS Status = STATUS_SUCCESS; 983 UNICODE_STRING DeviceInstance; 984 985 Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance); 986 if (!NT_SUCCESS(Status)) 987 { 988 return Status; 989 } 990 991 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance); 992 993 /* Get the device object */ 994 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); 995 if (DeviceInstance.Buffer != NULL) 996 { 997 ExFreePool(DeviceInstance.Buffer); 998 } 999 if (DeviceObject == NULL) 1000 { 1001 return STATUS_NO_SUCH_DEVICE; 1002 } 1003 1004 /* Get the device node */ 1005 DeviceNode = IopGetDeviceNode(DeviceObject); 1006 1007 ASSERT(DeviceNode->Flags & DNF_ENUMERATED); 1008 ASSERT(DeviceNode->Flags & DNF_PROCESSED); 1009 1010 /* Check if there's already a driver loaded for this device */ 1011 if (DeviceNode->Flags & DNF_ADDED) 1012 { 1013 #if 0 1014 /* Remove the device node */ 1015 Status = IopRemoveDevice(DeviceNode); 1016 if (NT_SUCCESS(Status)) 1017 { 1018 /* Invalidate device relations for the parent to reenumerate the device */ 1019 DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode->InstancePath); 1020 Status = IoSynchronousInvalidateDeviceRelations(DeviceNode->Parent->PhysicalDeviceObject, BusRelations); 1021 } 1022 else 1023 #endif 1024 { 1025 /* A driver has already been loaded for this device */ 1026 DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode->InstancePath); 1027 DeviceNode->Problem = CM_PROB_NEED_RESTART; 1028 } 1029 } 1030 else 1031 { 1032 /* FIXME: What if the device really is disabled? */ 1033 DeviceNode->Flags &= ~DNF_DISABLED; 1034 DeviceNode->Problem = 0; 1035 1036 /* Load service data from the registry */ 1037 Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent); 1038 1039 if (NT_SUCCESS(Status)) 1040 { 1041 /* Start the service and begin PnP initialization of the device again */ 1042 DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode->InstancePath); 1043 Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent); 1044 } 1045 } 1046 1047 ObDereferenceObject(DeviceObject); 1048 1049 return Status; 1050 } 1051 1052 /* PUBLIC FUNCTIONS **********************************************************/ 1053 1054 /* 1055 * Plug and Play event structure used by NtGetPlugPlayEvent. 1056 * 1057 * EventGuid 1058 * Can be one of the following values: 1059 * GUID_HWPROFILE_QUERY_CHANGE 1060 * GUID_HWPROFILE_CHANGE_CANCELLED 1061 * GUID_HWPROFILE_CHANGE_COMPLETE 1062 * GUID_TARGET_DEVICE_QUERY_REMOVE 1063 * GUID_TARGET_DEVICE_REMOVE_CANCELLED 1064 * GUID_TARGET_DEVICE_REMOVE_COMPLETE 1065 * GUID_PNP_CUSTOM_NOTIFICATION 1066 * GUID_PNP_POWER_NOTIFICATION 1067 * GUID_DEVICE_* (see above) 1068 * 1069 * EventCategory 1070 * Type of the event that happened. 1071 * 1072 * Result 1073 * ? 1074 * 1075 * Flags 1076 * ? 1077 * 1078 * TotalSize 1079 * Size of the event block including the device IDs and other 1080 * per category specific fields. 1081 */ 1082 1083 /* 1084 * NtGetPlugPlayEvent 1085 * 1086 * Returns one Plug & Play event from a global queue. 1087 * 1088 * Parameters 1089 * Reserved1 1090 * Reserved2 1091 * Always set to zero. 1092 * 1093 * Buffer 1094 * The buffer that will be filled with the event information on 1095 * successful return from the function. 1096 * 1097 * BufferSize 1098 * Size of the buffer pointed by the Buffer parameter. If the 1099 * buffer size is not large enough to hold the whole event 1100 * information, error STATUS_BUFFER_TOO_SMALL is returned and 1101 * the buffer remains untouched. 1102 * 1103 * Return Values 1104 * STATUS_PRIVILEGE_NOT_HELD 1105 * STATUS_BUFFER_TOO_SMALL 1106 * STATUS_SUCCESS 1107 * 1108 * Remarks 1109 * This function isn't multi-thread safe! 1110 * 1111 * @implemented 1112 */ 1113 NTSTATUS 1114 NTAPI 1115 NtGetPlugPlayEvent(IN ULONG Reserved1, 1116 IN ULONG Reserved2, 1117 OUT PPLUGPLAY_EVENT_BLOCK Buffer, 1118 IN ULONG BufferSize) 1119 { 1120 PPNP_EVENT_ENTRY Entry; 1121 NTSTATUS Status; 1122 1123 DPRINT("NtGetPlugPlayEvent() called\n"); 1124 1125 /* Function can only be called from user-mode */ 1126 if (KeGetPreviousMode() == KernelMode) 1127 { 1128 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n"); 1129 return STATUS_ACCESS_DENIED; 1130 } 1131 1132 /* Check for Tcb privilege */ 1133 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, 1134 UserMode)) 1135 { 1136 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n"); 1137 return STATUS_PRIVILEGE_NOT_HELD; 1138 } 1139 1140 /* Wait for a PnP event */ 1141 DPRINT("Waiting for pnp notification event\n"); 1142 Status = KeWaitForSingleObject(&IopPnpNotifyEvent, 1143 UserRequest, 1144 UserMode, 1145 FALSE, 1146 NULL); 1147 if (!NT_SUCCESS(Status) || Status == STATUS_USER_APC) 1148 { 1149 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status); 1150 ASSERT(Status == STATUS_USER_APC); 1151 return Status; 1152 } 1153 1154 /* Get entry from the tail of the queue */ 1155 Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink, 1156 PNP_EVENT_ENTRY, 1157 ListEntry); 1158 1159 /* Check the buffer size */ 1160 if (BufferSize < Entry->Event.TotalSize) 1161 { 1162 DPRINT1("Buffer is too small for the pnp-event\n"); 1163 return STATUS_BUFFER_TOO_SMALL; 1164 } 1165 1166 /* Copy event data to the user buffer */ 1167 _SEH2_TRY 1168 { 1169 ProbeForWrite(Buffer, 1170 Entry->Event.TotalSize, 1171 sizeof(UCHAR)); 1172 RtlCopyMemory(Buffer, 1173 &Entry->Event, 1174 Entry->Event.TotalSize); 1175 } 1176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1177 { 1178 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1179 } 1180 _SEH2_END; 1181 1182 DPRINT("NtGetPlugPlayEvent() done\n"); 1183 1184 return STATUS_SUCCESS; 1185 } 1186 1187 /* 1188 * NtPlugPlayControl 1189 * 1190 * A function for doing various Plug & Play operations from user mode. 1191 * 1192 * Parameters 1193 * PlugPlayControlClass 1194 * 0x00 Reenumerate device tree 1195 * 1196 * Buffer points to UNICODE_STRING decribing the instance 1197 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For 1198 * more information about instance paths see !devnode command 1199 * in kernel debugger or look at "Inside Windows 2000" book, 1200 * chapter "Driver Loading, Initialization, and Installation". 1201 * 1202 * 0x01 Register new device 1203 * 0x02 Deregister device 1204 * 0x03 Initialize device 1205 * 0x04 Start device 1206 * 0x06 Query and remove device 1207 * 0x07 User response 1208 * 1209 * Called after processing the message from NtGetPlugPlayEvent. 1210 * 1211 * 0x08 Generate legacy device 1212 * 0x09 Get interface device list 1213 * 0x0A Get property data 1214 * 0x0B Device class association (Registration) 1215 * 0x0C Get related device 1216 * 0x0D Get device interface alias 1217 * 0x0E Get/set/clear device status 1218 * 0x0F Get device depth 1219 * 0x10 Query device relations 1220 * 0x11 Query target device relation 1221 * 0x12 Query conflict list 1222 * 0x13 Retrieve dock data 1223 * 0x14 Reset device 1224 * 0x15 Halt device 1225 * 0x16 Get blocked driver data 1226 * 1227 * Buffer 1228 * The buffer contains information that is specific to each control 1229 * code. The buffer is read-only. 1230 * 1231 * BufferSize 1232 * Size of the buffer pointed by the Buffer parameter. If the 1233 * buffer size specifies incorrect value for specified control 1234 * code, error ??? is returned. 1235 * 1236 * Return Values 1237 * STATUS_PRIVILEGE_NOT_HELD 1238 * STATUS_SUCCESS 1239 * ... 1240 * 1241 * @unimplemented 1242 */ 1243 NTSTATUS 1244 NTAPI 1245 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, 1246 IN OUT PVOID Buffer, 1247 IN ULONG BufferLength) 1248 { 1249 DPRINT("NtPlugPlayControl(%d %p %lu) called\n", 1250 PlugPlayControlClass, Buffer, BufferLength); 1251 1252 /* Function can only be called from user-mode */ 1253 if (KeGetPreviousMode() == KernelMode) 1254 { 1255 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n"); 1256 return STATUS_ACCESS_DENIED; 1257 } 1258 1259 /* Check for Tcb privilege */ 1260 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, 1261 UserMode)) 1262 { 1263 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n"); 1264 return STATUS_PRIVILEGE_NOT_HELD; 1265 } 1266 1267 /* Probe the buffer */ 1268 _SEH2_TRY 1269 { 1270 ProbeForWrite(Buffer, 1271 BufferLength, 1272 sizeof(ULONG)); 1273 } 1274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1275 { 1276 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1277 } 1278 _SEH2_END; 1279 1280 switch (PlugPlayControlClass) 1281 { 1282 // case PlugPlayControlEnumerateDevice: 1283 // case PlugPlayControlRegisterNewDevice: 1284 // case PlugPlayControlDeregisterDevice: 1285 // case PlugPlayControlInitializeDevice: 1286 // case PlugPlayControlStartDevice: 1287 // case PlugPlayControlUnlockDevice: 1288 // case PlugPlayControlQueryAndRemoveDevice: 1289 1290 case PlugPlayControlUserResponse: 1291 if (Buffer || BufferLength != 0) 1292 return STATUS_INVALID_PARAMETER; 1293 return IopRemovePlugPlayEvent(); 1294 1295 // case PlugPlayControlGenerateLegacyDevice: 1296 1297 case PlugPlayControlGetInterfaceDeviceList: 1298 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)) 1299 return STATUS_INVALID_PARAMETER; 1300 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer); 1301 1302 case PlugPlayControlProperty: 1303 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA)) 1304 return STATUS_INVALID_PARAMETER; 1305 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer); 1306 1307 // case PlugPlayControlDeviceClassAssociation: 1308 1309 case PlugPlayControlGetRelatedDevice: 1310 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA)) 1311 return STATUS_INVALID_PARAMETER; 1312 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer); 1313 1314 // case PlugPlayControlGetInterfaceDeviceAlias: 1315 1316 case PlugPlayControlDeviceStatus: 1317 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA)) 1318 return STATUS_INVALID_PARAMETER; 1319 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer); 1320 1321 case PlugPlayControlGetDeviceDepth: 1322 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA)) 1323 return STATUS_INVALID_PARAMETER; 1324 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer); 1325 1326 case PlugPlayControlQueryDeviceRelations: 1327 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)) 1328 return STATUS_INVALID_PARAMETER; 1329 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer); 1330 1331 // case PlugPlayControlTargetDeviceRelation: 1332 // case PlugPlayControlQueryConflictList: 1333 // case PlugPlayControlRetrieveDock: 1334 1335 case PlugPlayControlResetDevice: 1336 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA)) 1337 return STATUS_INVALID_PARAMETER; 1338 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer); 1339 1340 // case PlugPlayControlHaltDevice: 1341 // case PlugPlayControlGetBlockedDriverList: 1342 1343 default: 1344 return STATUS_NOT_IMPLEMENTED; 1345 } 1346 1347 return STATUS_NOT_IMPLEMENTED; 1348 } 1349