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