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