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