Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpnpmgr.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * COPYRIGHT: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c 00005 * PURPOSE: Initializes the PnP manager 00006 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 00007 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org) 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS *******************************************************************/ 00017 00018 PDEVICE_NODE IopRootDeviceNode; 00019 KSPIN_LOCK IopDeviceTreeLock; 00020 ERESOURCE PpRegistryDeviceResource; 00021 KGUARDED_MUTEX PpDeviceReferenceTableLock; 00022 RTL_AVL_TABLE PpDeviceReferenceTable; 00023 00024 extern ULONG ExpInitializationPhase; 00025 extern BOOLEAN ExpInTextModeSetup; 00026 extern BOOLEAN PnpSystemInit; 00027 00028 /* DATA **********************************************************************/ 00029 00030 PDRIVER_OBJECT IopRootDriverObject; 00031 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL; 00032 00033 typedef struct _INVALIDATE_DEVICE_RELATION_DATA 00034 { 00035 PDEVICE_OBJECT DeviceObject; 00036 DEVICE_RELATION_TYPE Type; 00037 PIO_WORKITEM WorkItem; 00038 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA; 00039 00040 /* FUNCTIONS *****************************************************************/ 00041 NTSTATUS 00042 NTAPI 00043 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, 00044 IN ULONG CreateOptions, 00045 OUT PHANDLE Handle); 00046 00047 VOID 00048 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject); 00049 00050 NTSTATUS 00051 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force); 00052 00053 PDEVICE_OBJECT 00054 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); 00055 00056 PDEVICE_NODE 00057 FASTCALL 00058 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject) 00059 { 00060 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; 00061 } 00062 00063 VOID 00064 IopFixupDeviceId(PWCHAR String) 00065 { 00066 SIZE_T Length = wcslen(String), i; 00067 00068 for (i = 0; i < Length; i++) 00069 { 00070 if (String[i] == L'\\') 00071 String[i] = L'#'; 00072 } 00073 } 00074 00075 VOID 00076 NTAPI 00077 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) 00078 { 00079 NTSTATUS Status; 00080 HANDLE CriticalDeviceKey, InstanceKey; 00081 OBJECT_ATTRIBUTES ObjectAttributes; 00082 UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase"); 00083 UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs"); 00084 UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID"); 00085 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service"); 00086 UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID"); 00087 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 00088 ULONG HidLength = 0, CidLength = 0, BufferLength; 00089 PWCHAR IdBuffer, OriginalIdBuffer; 00090 00091 /* Open the device instance key */ 00092 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey); 00093 if (Status != STATUS_SUCCESS) 00094 return; 00095 00096 Status = ZwQueryValueKey(InstanceKey, 00097 &HardwareIdU, 00098 KeyValuePartialInformation, 00099 NULL, 00100 0, 00101 &HidLength); 00102 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 00103 { 00104 ZwClose(InstanceKey); 00105 return; 00106 } 00107 00108 Status = ZwQueryValueKey(InstanceKey, 00109 &CompatibleIdU, 00110 KeyValuePartialInformation, 00111 NULL, 00112 0, 00113 &CidLength); 00114 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 00115 { 00116 CidLength = 0; 00117 } 00118 00119 BufferLength = HidLength + CidLength; 00120 BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)); 00121 00122 /* Allocate a buffer to hold data from both */ 00123 OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength); 00124 if (!IdBuffer) 00125 { 00126 ZwClose(InstanceKey); 00127 return; 00128 } 00129 00130 /* Compute the buffer size */ 00131 if (HidLength > CidLength) 00132 BufferLength = HidLength; 00133 else 00134 BufferLength = CidLength; 00135 00136 PartialInfo = ExAllocatePool(PagedPool, BufferLength); 00137 if (!PartialInfo) 00138 { 00139 ZwClose(InstanceKey); 00140 ExFreePool(OriginalIdBuffer); 00141 return; 00142 } 00143 00144 Status = ZwQueryValueKey(InstanceKey, 00145 &HardwareIdU, 00146 KeyValuePartialInformation, 00147 PartialInfo, 00148 HidLength, 00149 &HidLength); 00150 if (Status != STATUS_SUCCESS) 00151 { 00152 ExFreePool(PartialInfo); 00153 ExFreePool(OriginalIdBuffer); 00154 ZwClose(InstanceKey); 00155 return; 00156 } 00157 00158 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */ 00159 HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0); 00160 RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength); 00161 00162 if (CidLength != 0) 00163 { 00164 Status = ZwQueryValueKey(InstanceKey, 00165 &CompatibleIdU, 00166 KeyValuePartialInformation, 00167 PartialInfo, 00168 CidLength, 00169 &CidLength); 00170 if (Status != STATUS_SUCCESS) 00171 { 00172 ExFreePool(PartialInfo); 00173 ExFreePool(OriginalIdBuffer); 00174 ZwClose(InstanceKey); 00175 return; 00176 } 00177 00178 /* Copy CID next */ 00179 CidLength = PartialInfo->DataLength; 00180 RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength); 00181 } 00182 00183 /* Free our temp buffer */ 00184 ExFreePool(PartialInfo); 00185 00186 InitializeObjectAttributes(&ObjectAttributes, 00187 &CriticalDeviceKeyU, 00188 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 00189 NULL, 00190 NULL); 00191 Status = ZwOpenKey(&CriticalDeviceKey, 00192 KEY_ENUMERATE_SUB_KEYS, 00193 &ObjectAttributes); 00194 if (!NT_SUCCESS(Status)) 00195 { 00196 /* The critical device database doesn't exist because 00197 * we're probably in 1st stage setup, but it's ok */ 00198 ExFreePool(OriginalIdBuffer); 00199 ZwClose(InstanceKey); 00200 return; 00201 } 00202 00203 while (*IdBuffer) 00204 { 00205 USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index; 00206 00207 IopFixupDeviceId(IdBuffer); 00208 00209 /* Look through all subkeys for a match */ 00210 for (Index = 0; TRUE; Index++) 00211 { 00212 ULONG NeededLength; 00213 PKEY_BASIC_INFORMATION BasicInfo; 00214 00215 Status = ZwEnumerateKey(CriticalDeviceKey, 00216 Index, 00217 KeyBasicInformation, 00218 NULL, 00219 0, 00220 &NeededLength); 00221 if (Status == STATUS_NO_MORE_ENTRIES) 00222 break; 00223 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 00224 { 00225 UNICODE_STRING ChildIdNameU, RegKeyNameU; 00226 00227 BasicInfo = ExAllocatePool(PagedPool, NeededLength); 00228 if (!BasicInfo) 00229 { 00230 /* No memory */ 00231 ExFreePool(OriginalIdBuffer); 00232 ZwClose(CriticalDeviceKey); 00233 ZwClose(InstanceKey); 00234 return; 00235 } 00236 00237 Status = ZwEnumerateKey(CriticalDeviceKey, 00238 Index, 00239 KeyBasicInformation, 00240 BasicInfo, 00241 NeededLength, 00242 &NeededLength); 00243 if (Status != STATUS_SUCCESS) 00244 { 00245 /* This shouldn't happen */ 00246 ExFreePool(BasicInfo); 00247 continue; 00248 } 00249 00250 ChildIdNameU.Buffer = IdBuffer; 00251 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR); 00252 RegKeyNameU.Buffer = BasicInfo->Name; 00253 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength; 00254 00255 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE)) 00256 { 00257 HANDLE ChildKeyHandle; 00258 00259 InitializeObjectAttributes(&ObjectAttributes, 00260 &ChildIdNameU, 00261 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 00262 CriticalDeviceKey, 00263 NULL); 00264 00265 Status = ZwOpenKey(&ChildKeyHandle, 00266 KEY_QUERY_VALUE, 00267 &ObjectAttributes); 00268 if (Status != STATUS_SUCCESS) 00269 { 00270 ExFreePool(BasicInfo); 00271 continue; 00272 } 00273 00274 /* Check if there's already a driver installed */ 00275 Status = ZwQueryValueKey(InstanceKey, 00276 &ClassGuidU, 00277 KeyValuePartialInformation, 00278 NULL, 00279 0, 00280 &NeededLength); 00281 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 00282 { 00283 ExFreePool(BasicInfo); 00284 continue; 00285 } 00286 00287 Status = ZwQueryValueKey(ChildKeyHandle, 00288 &ClassGuidU, 00289 KeyValuePartialInformation, 00290 NULL, 00291 0, 00292 &NeededLength); 00293 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) 00294 { 00295 ExFreePool(BasicInfo); 00296 continue; 00297 } 00298 00299 PartialInfo = ExAllocatePool(PagedPool, NeededLength); 00300 if (!PartialInfo) 00301 { 00302 ExFreePool(OriginalIdBuffer); 00303 ExFreePool(BasicInfo); 00304 ZwClose(InstanceKey); 00305 ZwClose(ChildKeyHandle); 00306 ZwClose(CriticalDeviceKey); 00307 return; 00308 } 00309 00310 /* Read ClassGUID entry in the CDDB */ 00311 Status = ZwQueryValueKey(ChildKeyHandle, 00312 &ClassGuidU, 00313 KeyValuePartialInformation, 00314 PartialInfo, 00315 NeededLength, 00316 &NeededLength); 00317 if (Status != STATUS_SUCCESS) 00318 { 00319 ExFreePool(BasicInfo); 00320 continue; 00321 } 00322 00323 /* Write it to the ENUM key */ 00324 Status = ZwSetValueKey(InstanceKey, 00325 &ClassGuidU, 00326 0, 00327 REG_SZ, 00328 PartialInfo->Data, 00329 PartialInfo->DataLength); 00330 if (Status != STATUS_SUCCESS) 00331 { 00332 ExFreePool(BasicInfo); 00333 ExFreePool(PartialInfo); 00334 ZwClose(ChildKeyHandle); 00335 continue; 00336 } 00337 00338 Status = ZwQueryValueKey(ChildKeyHandle, 00339 &ServiceU, 00340 KeyValuePartialInformation, 00341 NULL, 00342 0, 00343 &NeededLength); 00344 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 00345 { 00346 ExFreePool(PartialInfo); 00347 PartialInfo = ExAllocatePool(PagedPool, NeededLength); 00348 if (!PartialInfo) 00349 { 00350 ExFreePool(OriginalIdBuffer); 00351 ExFreePool(BasicInfo); 00352 ZwClose(InstanceKey); 00353 ZwClose(ChildKeyHandle); 00354 ZwClose(CriticalDeviceKey); 00355 return; 00356 } 00357 00358 /* Read the service entry from the CDDB */ 00359 Status = ZwQueryValueKey(ChildKeyHandle, 00360 &ServiceU, 00361 KeyValuePartialInformation, 00362 PartialInfo, 00363 NeededLength, 00364 &NeededLength); 00365 if (Status != STATUS_SUCCESS) 00366 { 00367 ExFreePool(BasicInfo); 00368 ExFreePool(PartialInfo); 00369 ZwClose(ChildKeyHandle); 00370 continue; 00371 } 00372 00373 /* Write it to the ENUM key */ 00374 Status = ZwSetValueKey(InstanceKey, 00375 &ServiceU, 00376 0, 00377 REG_SZ, 00378 PartialInfo->Data, 00379 PartialInfo->DataLength); 00380 if (Status != STATUS_SUCCESS) 00381 { 00382 ExFreePool(BasicInfo); 00383 ExFreePool(PartialInfo); 00384 ZwClose(ChildKeyHandle); 00385 continue; 00386 } 00387 00388 DPRINT1("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU); 00389 } 00390 else 00391 { 00392 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU); 00393 } 00394 00395 ExFreePool(OriginalIdBuffer); 00396 ExFreePool(PartialInfo); 00397 ExFreePool(BasicInfo); 00398 ZwClose(InstanceKey); 00399 ZwClose(ChildKeyHandle); 00400 ZwClose(CriticalDeviceKey); 00401 00402 /* That's it */ 00403 return; 00404 } 00405 00406 ExFreePool(BasicInfo); 00407 } 00408 else 00409 { 00410 /* Umm, not sure what happened here */ 00411 continue; 00412 } 00413 } 00414 00415 /* Advance to the next ID */ 00416 IdBuffer += StringLength; 00417 } 00418 00419 ExFreePool(OriginalIdBuffer); 00420 ZwClose(InstanceKey); 00421 ZwClose(CriticalDeviceKey); 00422 } 00423 00424 NTSTATUS 00425 FASTCALL 00426 IopInitializeDevice(PDEVICE_NODE DeviceNode, 00427 PDRIVER_OBJECT DriverObject) 00428 { 00429 PDEVICE_OBJECT Fdo; 00430 NTSTATUS Status; 00431 00432 if (!DriverObject) 00433 { 00434 /* Special case for bus driven devices */ 00435 DeviceNode->Flags |= DNF_ADDED; 00436 return STATUS_SUCCESS; 00437 } 00438 00439 if (!DriverObject->DriverExtension->AddDevice) 00440 { 00441 DeviceNode->Flags |= DNF_LEGACY_DRIVER; 00442 } 00443 00444 if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 00445 { 00446 DeviceNode->Flags |= DNF_ADDED + DNF_STARTED; 00447 return STATUS_SUCCESS; 00448 } 00449 00450 /* This is a Plug and Play driver */ 00451 DPRINT("Plug and Play driver found\n"); 00452 ASSERT(DeviceNode->PhysicalDeviceObject); 00453 00454 DPRINT("Calling %wZ->AddDevice(%wZ)\n", 00455 &DriverObject->DriverName, 00456 &DeviceNode->InstancePath); 00457 Status = DriverObject->DriverExtension->AddDevice( 00458 DriverObject, DeviceNode->PhysicalDeviceObject); 00459 if (!NT_SUCCESS(Status)) 00460 { 00461 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n", 00462 &DriverObject->DriverName, 00463 &DeviceNode->InstancePath, 00464 Status); 00465 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 00466 DeviceNode->Problem = CM_PROB_FAILED_ADD; 00467 return Status; 00468 } 00469 00470 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject); 00471 00472 /* Check if we have a ACPI device (needed for power management) */ 00473 if (Fdo->DeviceType == FILE_DEVICE_ACPI) 00474 { 00475 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE; 00476 00477 /* There can be only one system power device */ 00478 if (!SystemPowerDeviceNodeCreated) 00479 { 00480 PopSystemPowerDeviceNode = DeviceNode; 00481 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject); 00482 SystemPowerDeviceNodeCreated = TRUE; 00483 } 00484 } 00485 00486 ObDereferenceObject(Fdo); 00487 00488 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); 00489 00490 return STATUS_SUCCESS; 00491 } 00492 00493 static 00494 NTSTATUS 00495 NTAPI 00496 IopSendEject(IN PDEVICE_OBJECT DeviceObject) 00497 { 00498 IO_STACK_LOCATION Stack; 00499 PVOID Dummy; 00500 00501 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00502 Stack.MajorFunction = IRP_MJ_PNP; 00503 Stack.MinorFunction = IRP_MN_EJECT; 00504 00505 return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00506 } 00507 00508 static 00509 VOID 00510 NTAPI 00511 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject) 00512 { 00513 IO_STACK_LOCATION Stack; 00514 PVOID Dummy; 00515 00516 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00517 Stack.MajorFunction = IRP_MJ_PNP; 00518 Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL; 00519 00520 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */ 00521 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00522 } 00523 00524 static 00525 NTSTATUS 00526 NTAPI 00527 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 00528 { 00529 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 00530 IO_STACK_LOCATION Stack; 00531 PVOID Dummy; 00532 NTSTATUS Status; 00533 00534 ASSERT(DeviceNode); 00535 00536 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING, 00537 &DeviceNode->InstancePath); 00538 00539 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00540 Stack.MajorFunction = IRP_MJ_PNP; 00541 Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE; 00542 00543 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00544 00545 IopNotifyPlugPlayNotification(DeviceObject, 00546 EventCategoryTargetDeviceChange, 00547 &GUID_TARGET_DEVICE_QUERY_REMOVE, 00548 NULL, 00549 NULL); 00550 00551 if (!NT_SUCCESS(Status)) 00552 { 00553 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath); 00554 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED, 00555 &DeviceNode->InstancePath); 00556 } 00557 00558 return Status; 00559 } 00560 00561 static 00562 NTSTATUS 00563 NTAPI 00564 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject) 00565 { 00566 IO_STACK_LOCATION Stack; 00567 PVOID Dummy; 00568 00569 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00570 Stack.MajorFunction = IRP_MJ_PNP; 00571 Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE; 00572 00573 return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00574 } 00575 00576 static 00577 VOID 00578 NTAPI 00579 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 00580 { 00581 IO_STACK_LOCATION Stack; 00582 PVOID Dummy; 00583 00584 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00585 Stack.MajorFunction = IRP_MJ_PNP; 00586 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE; 00587 00588 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ 00589 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00590 00591 IopNotifyPlugPlayNotification(DeviceObject, 00592 EventCategoryTargetDeviceChange, 00593 &GUID_TARGET_DEVICE_REMOVE_COMPLETE, 00594 NULL, 00595 NULL); 00596 } 00597 00598 static 00599 VOID 00600 NTAPI 00601 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject) 00602 { 00603 IO_STACK_LOCATION Stack; 00604 PVOID Dummy; 00605 00606 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00607 Stack.MajorFunction = IRP_MJ_PNP; 00608 Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE; 00609 00610 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */ 00611 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00612 00613 IopNotifyPlugPlayNotification(DeviceObject, 00614 EventCategoryTargetDeviceChange, 00615 &GUID_TARGET_DEVICE_REMOVE_CANCELLED, 00616 NULL, 00617 NULL); 00618 } 00619 00620 static 00621 VOID 00622 NTAPI 00623 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject) 00624 { 00625 IO_STACK_LOCATION Stack; 00626 PVOID Dummy; 00627 00628 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00629 Stack.MajorFunction = IRP_MJ_PNP; 00630 Stack.MinorFunction = IRP_MN_STOP_DEVICE; 00631 00632 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */ 00633 IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00634 } 00635 00636 VOID 00637 NTAPI 00638 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject) 00639 { 00640 IO_STACK_LOCATION Stack; 00641 PDEVICE_NODE DeviceNode; 00642 NTSTATUS Status; 00643 PVOID Dummy; 00644 DEVICE_CAPABILITIES DeviceCapabilities; 00645 00646 /* Get the device node */ 00647 DeviceNode = IopGetDeviceNode(DeviceObject); 00648 00649 ASSERT(!(DeviceNode->Flags & DNF_DISABLED)); 00650 00651 /* Build the I/O stack locaiton */ 00652 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00653 Stack.MajorFunction = IRP_MJ_PNP; 00654 Stack.MinorFunction = IRP_MN_START_DEVICE; 00655 00656 Stack.Parameters.StartDevice.AllocatedResources = 00657 DeviceNode->ResourceList; 00658 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = 00659 DeviceNode->ResourceListTranslated; 00660 00661 /* Do the call */ 00662 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); 00663 if (!NT_SUCCESS(Status)) 00664 { 00665 /* Send an IRP_MN_REMOVE_DEVICE request */ 00666 IopRemoveDevice(DeviceNode); 00667 00668 /* Set the appropriate flag */ 00669 DeviceNode->Flags |= DNF_START_FAILED; 00670 DeviceNode->Problem = CM_PROB_FAILED_START; 00671 00672 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status); 00673 return; 00674 } 00675 00676 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n"); 00677 00678 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 00679 if (!NT_SUCCESS(Status)) 00680 { 00681 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 00682 } 00683 00684 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */ 00685 IoInvalidateDeviceState(DeviceObject); 00686 00687 /* Otherwise, mark us as started */ 00688 DeviceNode->Flags |= DNF_STARTED; 00689 DeviceNode->Flags &= ~DNF_STOPPED; 00690 00691 /* We now need enumeration */ 00692 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY; 00693 } 00694 00695 NTSTATUS 00696 NTAPI 00697 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode) 00698 { 00699 PDEVICE_OBJECT DeviceObject; 00700 NTSTATUS Status; 00701 PAGED_CODE(); 00702 00703 /* Sanity check */ 00704 ASSERT((DeviceNode->Flags & DNF_ADDED)); 00705 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED | 00706 DNF_RESOURCE_REPORTED | 00707 DNF_NO_RESOURCE_REQUIRED))); 00708 00709 /* Get the device object */ 00710 DeviceObject = DeviceNode->PhysicalDeviceObject; 00711 00712 /* Check if we're not started yet */ 00713 if (!(DeviceNode->Flags & DNF_STARTED)) 00714 { 00715 /* Start us */ 00716 IopStartDevice2(DeviceObject); 00717 } 00718 00719 /* Do we need to query IDs? This happens in the case of manual reporting */ 00720 #if 0 00721 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS) 00722 { 00723 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n"); 00724 /* And that case shouldn't happen yet */ 00725 ASSERT(FALSE); 00726 } 00727 #endif 00728 00729 /* Make sure we're started, and check if we need enumeration */ 00730 if ((DeviceNode->Flags & DNF_STARTED) && 00731 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)) 00732 { 00733 /* Enumerate us */ 00734 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations); 00735 Status = STATUS_SUCCESS; 00736 } 00737 else 00738 { 00739 /* Nothing to do */ 00740 Status = STATUS_SUCCESS; 00741 } 00742 00743 /* Return */ 00744 return Status; 00745 } 00746 00747 NTSTATUS 00748 IopStopDevice( 00749 PDEVICE_NODE DeviceNode) 00750 { 00751 NTSTATUS Status; 00752 00753 DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath); 00754 00755 Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject); 00756 if (NT_SUCCESS(Status)) 00757 { 00758 IopSendStopDevice(DeviceNode->PhysicalDeviceObject); 00759 00760 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); 00761 DeviceNode->Flags |= DNF_STOPPED; 00762 00763 return STATUS_SUCCESS; 00764 } 00765 00766 return Status; 00767 } 00768 00769 NTSTATUS 00770 IopStartDevice( 00771 PDEVICE_NODE DeviceNode) 00772 { 00773 NTSTATUS Status; 00774 HANDLE InstanceHandle = INVALID_HANDLE_VALUE, ControlHandle = INVALID_HANDLE_VALUE; 00775 UNICODE_STRING KeyName; 00776 OBJECT_ATTRIBUTES ObjectAttributes; 00777 00778 if (DeviceNode->Flags & DNF_DISABLED) 00779 return STATUS_SUCCESS; 00780 00781 Status = IopAssignDeviceResources(DeviceNode); 00782 if (!NT_SUCCESS(Status)) 00783 goto ByeBye; 00784 00785 /* New PnP ABI */ 00786 IopStartAndEnumerateDevice(DeviceNode); 00787 00788 /* FIX: Should be done in new device instance code */ 00789 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle); 00790 if (!NT_SUCCESS(Status)) 00791 goto ByeBye; 00792 00793 /* FIX: Should be done in IoXxxPrepareDriverLoading */ 00794 // { 00795 RtlInitUnicodeString(&KeyName, L"Control"); 00796 InitializeObjectAttributes(&ObjectAttributes, 00797 &KeyName, 00798 OBJ_CASE_INSENSITIVE, 00799 InstanceHandle, 00800 NULL); 00801 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL); 00802 if (!NT_SUCCESS(Status)) 00803 goto ByeBye; 00804 00805 RtlInitUnicodeString(&KeyName, L"ActiveService"); 00806 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length); 00807 // } 00808 00809 ByeBye: 00810 if (ControlHandle != INVALID_HANDLE_VALUE) 00811 ZwClose(ControlHandle); 00812 00813 if (InstanceHandle != INVALID_HANDLE_VALUE) 00814 ZwClose(InstanceHandle); 00815 00816 return Status; 00817 } 00818 00819 NTSTATUS 00820 NTAPI 00821 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, 00822 PDEVICE_CAPABILITIES DeviceCaps) 00823 { 00824 IO_STATUS_BLOCK StatusBlock; 00825 IO_STACK_LOCATION Stack; 00826 NTSTATUS Status; 00827 HANDLE InstanceKey; 00828 UNICODE_STRING ValueName; 00829 00830 /* Set up the Header */ 00831 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES)); 00832 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES); 00833 DeviceCaps->Version = 1; 00834 DeviceCaps->Address = -1; 00835 DeviceCaps->UINumber = -1; 00836 00837 /* Set up the Stack */ 00838 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 00839 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps; 00840 00841 /* Send the IRP */ 00842 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 00843 &StatusBlock, 00844 IRP_MN_QUERY_CAPABILITIES, 00845 &Stack); 00846 if (!NT_SUCCESS(Status)) 00847 { 00848 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status); 00849 return Status; 00850 } 00851 00852 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCaps->Version + sizeof(DeviceCaps->Version)); 00853 00854 if (DeviceCaps->NoDisplayInUI) 00855 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 00856 else 00857 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 00858 00859 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey); 00860 if (NT_SUCCESS(Status)) 00861 { 00862 /* Set 'Capabilities' value */ 00863 RtlInitUnicodeString(&ValueName, L"Capabilities"); 00864 Status = ZwSetValueKey(InstanceKey, 00865 &ValueName, 00866 0, 00867 REG_DWORD, 00868 (PVOID)&DeviceNode->CapabilityFlags, 00869 sizeof(ULONG)); 00870 00871 /* Set 'UINumber' value */ 00872 if (DeviceCaps->UINumber != MAXULONG) 00873 { 00874 RtlInitUnicodeString(&ValueName, L"UINumber"); 00875 Status = ZwSetValueKey(InstanceKey, 00876 &ValueName, 00877 0, 00878 REG_DWORD, 00879 &DeviceCaps->UINumber, 00880 sizeof(ULONG)); 00881 } 00882 } 00883 00884 return Status; 00885 } 00886 00887 static VOID NTAPI 00888 IopAsynchronousInvalidateDeviceRelations( 00889 IN PDEVICE_OBJECT DeviceObject, 00890 IN PVOID InvalidateContext) 00891 { 00892 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext; 00893 00894 IoSynchronousInvalidateDeviceRelations( 00895 Data->DeviceObject, 00896 Data->Type); 00897 00898 ObDereferenceObject(Data->DeviceObject); 00899 IoFreeWorkItem(Data->WorkItem); 00900 ExFreePool(Data); 00901 } 00902 00903 NTSTATUS 00904 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject) 00905 { 00906 KIRQL OldIrql; 00907 00908 if (PopSystemPowerDeviceNode) 00909 { 00910 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 00911 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject; 00912 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 00913 00914 return STATUS_SUCCESS; 00915 } 00916 00917 return STATUS_UNSUCCESSFUL; 00918 } 00919 00920 USHORT 00921 NTAPI 00922 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid) 00923 { 00924 USHORT i = 0, FoundIndex = 0xFFFF; 00925 ULONG NewSize; 00926 PVOID NewList; 00927 00928 /* Acquire the lock */ 00929 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock); 00930 00931 /* Loop all entries */ 00932 while (i < PnpBusTypeGuidList->GuidCount) 00933 { 00934 /* Try to find a match */ 00935 if (RtlCompareMemory(BusTypeGuid, 00936 &PnpBusTypeGuidList->Guids[i], 00937 sizeof(GUID)) == sizeof(GUID)) 00938 { 00939 /* Found it */ 00940 FoundIndex = i; 00941 goto Quickie; 00942 } 00943 i++; 00944 } 00945 00946 /* Check if we have to grow the list */ 00947 if (PnpBusTypeGuidList->GuidCount) 00948 { 00949 /* Calculate the new size */ 00950 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) + 00951 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount); 00952 00953 /* Allocate the new copy */ 00954 NewList = ExAllocatePool(PagedPool, NewSize); 00955 00956 if (!NewList) { 00957 /* Fail */ 00958 ExFreePool(PnpBusTypeGuidList); 00959 goto Quickie; 00960 } 00961 00962 /* Now copy them, decrease the size too */ 00963 NewSize -= sizeof(GUID); 00964 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize); 00965 00966 /* Free the old list */ 00967 ExFreePool(PnpBusTypeGuidList); 00968 00969 /* Use the new buffer */ 00970 PnpBusTypeGuidList = NewList; 00971 } 00972 00973 /* Copy the new GUID */ 00974 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount], 00975 BusTypeGuid, 00976 sizeof(GUID)); 00977 00978 /* The new entry is the index */ 00979 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount; 00980 PnpBusTypeGuidList->GuidCount++; 00981 00982 Quickie: 00983 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock); 00984 return FoundIndex; 00985 } 00986 00987 /* 00988 * DESCRIPTION 00989 * Creates a device node 00990 * 00991 * ARGUMENTS 00992 * ParentNode = Pointer to parent device node 00993 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL 00994 * to have the root device node create one 00995 * (eg. for legacy drivers) 00996 * DeviceNode = Pointer to storage for created device node 00997 * 00998 * RETURN VALUE 00999 * Status 01000 */ 01001 NTSTATUS 01002 IopCreateDeviceNode(PDEVICE_NODE ParentNode, 01003 PDEVICE_OBJECT PhysicalDeviceObject, 01004 PUNICODE_STRING ServiceName, 01005 PDEVICE_NODE *DeviceNode) 01006 { 01007 PDEVICE_NODE Node; 01008 NTSTATUS Status; 01009 KIRQL OldIrql; 01010 UNICODE_STRING FullServiceName; 01011 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_"); 01012 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN"); 01013 UNICODE_STRING KeyName, ClassName; 01014 PUNICODE_STRING ServiceName1; 01015 ULONG LegacyValue; 01016 UNICODE_STRING ClassGUID; 01017 HANDLE InstanceHandle; 01018 01019 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n", 01020 ParentNode, PhysicalDeviceObject, ServiceName); 01021 01022 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE)); 01023 if (!Node) 01024 { 01025 return STATUS_INSUFFICIENT_RESOURCES; 01026 } 01027 01028 RtlZeroMemory(Node, sizeof(DEVICE_NODE)); 01029 01030 if (!ServiceName) 01031 ServiceName1 = &UnknownDeviceName; 01032 else 01033 ServiceName1 = ServiceName; 01034 01035 if (!PhysicalDeviceObject) 01036 { 01037 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length; 01038 FullServiceName.Length = 0; 01039 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength); 01040 if (!FullServiceName.Buffer) 01041 { 01042 ExFreePool(Node); 01043 return STATUS_INSUFFICIENT_RESOURCES; 01044 } 01045 01046 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix); 01047 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1); 01048 01049 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath); 01050 if (!NT_SUCCESS(Status)) 01051 { 01052 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status); 01053 ExFreePool(Node); 01054 return Status; 01055 } 01056 01057 /* Create the device key for legacy drivers */ 01058 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle); 01059 if (!NT_SUCCESS(Status)) 01060 { 01061 ZwClose(InstanceHandle); 01062 ExFreePool(Node); 01063 ExFreePool(FullServiceName.Buffer); 01064 return Status; 01065 } 01066 01067 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length); 01068 if (!Node->ServiceName.Buffer) 01069 { 01070 ZwClose(InstanceHandle); 01071 ExFreePool(Node); 01072 ExFreePool(FullServiceName.Buffer); 01073 return Status; 01074 } 01075 01076 Node->ServiceName.MaximumLength = ServiceName1->Length; 01077 Node->ServiceName.Length = 0; 01078 01079 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1); 01080 01081 if (ServiceName) 01082 { 01083 RtlInitUnicodeString(&KeyName, L"Service"); 01084 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length); 01085 } 01086 01087 if (NT_SUCCESS(Status)) 01088 { 01089 RtlInitUnicodeString(&KeyName, L"Legacy"); 01090 01091 LegacyValue = 1; 01092 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue)); 01093 if (NT_SUCCESS(Status)) 01094 { 01095 RtlInitUnicodeString(&KeyName, L"Class"); 01096 01097 RtlInitUnicodeString(&ClassName, L"LegacyDriver\0"); 01098 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length + sizeof(UNICODE_NULL)); 01099 if (NT_SUCCESS(Status)) 01100 { 01101 RtlInitUnicodeString(&KeyName, L"ClassGUID"); 01102 01103 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}\0"); 01104 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length + sizeof(UNICODE_NULL)); 01105 if (NT_SUCCESS(Status)) 01106 { 01107 RtlInitUnicodeString(&KeyName, L"DeviceDesc"); 01108 01109 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName1->Buffer, ServiceName1->Length + sizeof(UNICODE_NULL)); 01110 } 01111 } 01112 } 01113 } 01114 01115 ZwClose(InstanceHandle); 01116 ExFreePool(FullServiceName.Buffer); 01117 01118 if (!NT_SUCCESS(Status)) 01119 { 01120 ExFreePool(Node); 01121 return Status; 01122 } 01123 01124 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER); 01125 IopDeviceNodeSetFlag(Node, DNF_PROCESSED); 01126 IopDeviceNodeSetFlag(Node, DNF_ADDED); 01127 IopDeviceNodeSetFlag(Node, DNF_STARTED); 01128 } 01129 01130 Node->PhysicalDeviceObject = PhysicalDeviceObject; 01131 01132 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node; 01133 01134 if (ParentNode) 01135 { 01136 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 01137 Node->Parent = ParentNode; 01138 Node->Sibling = NULL; 01139 if (ParentNode->LastChild == NULL) 01140 { 01141 ParentNode->Child = Node; 01142 ParentNode->LastChild = Node; 01143 } 01144 else 01145 { 01146 ParentNode->LastChild->Sibling = Node; 01147 ParentNode->LastChild = Node; 01148 } 01149 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 01150 Node->Level = ParentNode->Level + 1; 01151 } 01152 01153 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 01154 01155 *DeviceNode = Node; 01156 01157 return STATUS_SUCCESS; 01158 } 01159 01160 NTSTATUS 01161 IopFreeDeviceNode(PDEVICE_NODE DeviceNode) 01162 { 01163 KIRQL OldIrql; 01164 PDEVICE_NODE PrevSibling = NULL; 01165 01166 /* All children must be deleted before a parent is deleted */ 01167 ASSERT(!DeviceNode->Child); 01168 ASSERT(DeviceNode->PhysicalDeviceObject); 01169 01170 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 01171 01172 /* Get previous sibling */ 01173 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode) 01174 { 01175 PrevSibling = DeviceNode->Parent->Child; 01176 while (PrevSibling->Sibling != DeviceNode) 01177 PrevSibling = PrevSibling->Sibling; 01178 } 01179 01180 /* Unlink from parent if it exists */ 01181 if (DeviceNode->Parent) 01182 { 01183 if (DeviceNode->Parent->LastChild == DeviceNode) 01184 { 01185 DeviceNode->Parent->LastChild = PrevSibling; 01186 if (PrevSibling) 01187 PrevSibling->Sibling = NULL; 01188 } 01189 if (DeviceNode->Parent->Child == DeviceNode) 01190 DeviceNode->Parent->Child = DeviceNode->Sibling; 01191 } 01192 01193 /* Unlink from sibling list */ 01194 if (PrevSibling) 01195 PrevSibling->Sibling = DeviceNode->Sibling; 01196 01197 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 01198 01199 RtlFreeUnicodeString(&DeviceNode->InstancePath); 01200 01201 RtlFreeUnicodeString(&DeviceNode->ServiceName); 01202 01203 if (DeviceNode->ResourceList) 01204 { 01205 ExFreePool(DeviceNode->ResourceList); 01206 } 01207 01208 if (DeviceNode->ResourceListTranslated) 01209 { 01210 ExFreePool(DeviceNode->ResourceListTranslated); 01211 } 01212 01213 if (DeviceNode->ResourceRequirements) 01214 { 01215 ExFreePool(DeviceNode->ResourceRequirements); 01216 } 01217 01218 if (DeviceNode->BootResources) 01219 { 01220 ExFreePool(DeviceNode->BootResources); 01221 } 01222 01223 ExFreePool(DeviceNode); 01224 01225 return STATUS_SUCCESS; 01226 } 01227 01228 NTSTATUS 01229 NTAPI 01230 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject, 01231 IN PIO_STACK_LOCATION IoStackLocation, 01232 OUT PVOID *Information) 01233 { 01234 PIRP Irp; 01235 PIO_STACK_LOCATION IrpStack; 01236 IO_STATUS_BLOCK IoStatusBlock; 01237 KEVENT Event; 01238 NTSTATUS Status; 01239 PDEVICE_OBJECT TopDeviceObject; 01240 PAGED_CODE(); 01241 01242 /* Call the top of the device stack */ 01243 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); 01244 01245 /* Allocate an IRP */ 01246 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE); 01247 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 01248 01249 /* Initialize to failure */ 01250 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED; 01251 Irp->IoStatus.Information = IoStatusBlock.Information = 0; 01252 01253 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */ 01254 if (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS) 01255 { 01256 /* Copy the resource requirements list into the IOSB */ 01257 Irp->IoStatus.Information = 01258 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList; 01259 } 01260 01261 /* Initialize the event */ 01262 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 01263 01264 /* Set them up */ 01265 Irp->UserIosb = &IoStatusBlock; 01266 Irp->UserEvent = &Event; 01267 01268 /* Queue the IRP */ 01269 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 01270 IoQueueThreadIrp(Irp); 01271 01272 /* Copy-in the stack */ 01273 IrpStack = IoGetNextIrpStackLocation(Irp); 01274 *IrpStack = *IoStackLocation; 01275 01276 /* Call the driver */ 01277 Status = IoCallDriver(TopDeviceObject, Irp); 01278 if (Status == STATUS_PENDING) 01279 { 01280 /* Wait for it */ 01281 KeWaitForSingleObject(&Event, 01282 Executive, 01283 KernelMode, 01284 FALSE, 01285 NULL); 01286 Status = IoStatusBlock.Status; 01287 } 01288 01289 /* Remove the reference */ 01290 ObDereferenceObject(TopDeviceObject); 01291 01292 /* Return the information */ 01293 *Information = (PVOID)IoStatusBlock.Information; 01294 return Status; 01295 } 01296 01297 NTSTATUS 01298 NTAPI 01299 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject, 01300 IN OUT PIO_STATUS_BLOCK IoStatusBlock, 01301 IN UCHAR MinorFunction, 01302 IN PIO_STACK_LOCATION Stack OPTIONAL) 01303 { 01304 IO_STACK_LOCATION IoStackLocation; 01305 01306 /* Fill out the stack information */ 01307 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION)); 01308 IoStackLocation.MajorFunction = IRP_MJ_PNP; 01309 IoStackLocation.MinorFunction = MinorFunction; 01310 if (Stack) 01311 { 01312 /* Copy the rest */ 01313 RtlCopyMemory(&IoStackLocation.Parameters, 01314 &Stack->Parameters, 01315 sizeof(Stack->Parameters)); 01316 } 01317 01318 /* Do the PnP call */ 01319 IoStatusBlock->Status = IopSynchronousCall(DeviceObject, 01320 &IoStackLocation, 01321 (PVOID)&IoStatusBlock->Information); 01322 return IoStatusBlock->Status; 01323 } 01324 01325 NTSTATUS 01326 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context) 01327 { 01328 PDEVICE_NODE ParentDeviceNode; 01329 PDEVICE_NODE ChildDeviceNode; 01330 NTSTATUS Status; 01331 01332 /* Copy context data so we don't overwrite it in subsequent calls to this function */ 01333 ParentDeviceNode = Context->DeviceNode; 01334 01335 /* Call the action routine */ 01336 Status = (Context->Action)(ParentDeviceNode, Context->Context); 01337 if (!NT_SUCCESS(Status)) 01338 { 01339 return Status; 01340 } 01341 01342 /* Traversal of all children nodes */ 01343 for (ChildDeviceNode = ParentDeviceNode->Child; 01344 ChildDeviceNode != NULL; 01345 ChildDeviceNode = ChildDeviceNode->Sibling) 01346 { 01347 /* Pass the current device node to the action routine */ 01348 Context->DeviceNode = ChildDeviceNode; 01349 01350 Status = IopTraverseDeviceTreeNode(Context); 01351 if (!NT_SUCCESS(Status)) 01352 { 01353 return Status; 01354 } 01355 } 01356 01357 return Status; 01358 } 01359 01360 01361 NTSTATUS 01362 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context) 01363 { 01364 NTSTATUS Status; 01365 01366 DPRINT("Context 0x%p\n", Context); 01367 01368 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n", 01369 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context); 01370 01371 /* Start from the specified device node */ 01372 Context->DeviceNode = Context->FirstDeviceNode; 01373 01374 /* Recursively traverse the device tree */ 01375 Status = IopTraverseDeviceTreeNode(Context); 01376 if (Status == STATUS_UNSUCCESSFUL) 01377 { 01378 /* The action routine just wanted to terminate the traversal with status 01379 code STATUS_SUCCESS */ 01380 Status = STATUS_SUCCESS; 01381 } 01382 01383 return Status; 01384 } 01385 01386 01387 /* 01388 * IopCreateDeviceKeyPath 01389 * 01390 * Creates a registry key 01391 * 01392 * Parameters 01393 * RegistryPath 01394 * Name of the key to be created. 01395 * Handle 01396 * Handle to the newly created key 01397 * 01398 * Remarks 01399 * This method can create nested trees, so parent of RegistryPath can 01400 * be not existant, and will be created if needed. 01401 */ 01402 NTSTATUS 01403 NTAPI 01404 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, 01405 IN ULONG CreateOptions, 01406 OUT PHANDLE Handle) 01407 { 01408 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT); 01409 HANDLE hParent = NULL, hKey; 01410 OBJECT_ATTRIBUTES ObjectAttributes; 01411 UNICODE_STRING KeyName; 01412 LPCWSTR Current, Last; 01413 USHORT Length; 01414 NTSTATUS Status; 01415 01416 /* Assume failure */ 01417 *Handle = NULL; 01418 01419 /* Create a volatile device tree in 1st stage so we have a clean slate 01420 * for enumeration using the correct HAL (chosen in 1st stage setup) */ 01421 if (ExpInTextModeSetup) CreateOptions |= REG_OPTION_VOLATILE; 01422 01423 /* Open root key for device instances */ 01424 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY); 01425 if (!NT_SUCCESS(Status)) 01426 { 01427 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status); 01428 return Status; 01429 } 01430 01431 Current = KeyName.Buffer = RegistryPath->Buffer; 01432 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)]; 01433 01434 /* Go up to the end of the string */ 01435 while (Current <= Last) 01436 { 01437 if (Current != Last && *Current != '\\') 01438 { 01439 /* Not the end of the string and not a separator */ 01440 Current++; 01441 continue; 01442 } 01443 01444 /* Prepare relative key name */ 01445 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer); 01446 KeyName.MaximumLength = KeyName.Length = Length; 01447 DPRINT("Create '%wZ'\n", &KeyName); 01448 01449 /* Open key */ 01450 InitializeObjectAttributes(&ObjectAttributes, 01451 &KeyName, 01452 OBJ_CASE_INSENSITIVE, 01453 hParent, 01454 NULL); 01455 Status = ZwCreateKey(&hKey, 01456 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY, 01457 &ObjectAttributes, 01458 0, 01459 NULL, 01460 CreateOptions, 01461 NULL); 01462 01463 /* Close parent key handle, we don't need it anymore */ 01464 if (hParent) 01465 ZwClose(hParent); 01466 01467 /* Key opening/creating failed? */ 01468 if (!NT_SUCCESS(Status)) 01469 { 01470 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status); 01471 return Status; 01472 } 01473 01474 /* Check if it is the end of the string */ 01475 if (Current == Last) 01476 { 01477 /* Yes, return success */ 01478 *Handle = hKey; 01479 return STATUS_SUCCESS; 01480 } 01481 01482 /* Start with this new parent key */ 01483 hParent = hKey; 01484 Current++; 01485 KeyName.Buffer = (LPWSTR)Current; 01486 } 01487 01488 return STATUS_UNSUCCESSFUL; 01489 } 01490 01491 NTSTATUS 01492 IopSetDeviceInstanceData(HANDLE InstanceKey, 01493 PDEVICE_NODE DeviceNode) 01494 { 01495 OBJECT_ATTRIBUTES ObjectAttributes; 01496 UNICODE_STRING KeyName; 01497 HANDLE LogConfKey; 01498 ULONG ResCount; 01499 ULONG ResultLength; 01500 NTSTATUS Status; 01501 HANDLE ControlHandle; 01502 01503 DPRINT("IopSetDeviceInstanceData() called\n"); 01504 01505 /* Create the 'LogConf' key */ 01506 RtlInitUnicodeString(&KeyName, L"LogConf"); 01507 InitializeObjectAttributes(&ObjectAttributes, 01508 &KeyName, 01509 OBJ_CASE_INSENSITIVE, 01510 InstanceKey, 01511 NULL); 01512 Status = ZwCreateKey(&LogConfKey, 01513 KEY_ALL_ACCESS, 01514 &ObjectAttributes, 01515 0, 01516 NULL, 01517 REG_OPTION_VOLATILE, 01518 NULL); 01519 if (NT_SUCCESS(Status)) 01520 { 01521 /* Set 'BootConfig' value */ 01522 if (DeviceNode->BootResources != NULL) 01523 { 01524 ResCount = DeviceNode->BootResources->Count; 01525 if (ResCount != 0) 01526 { 01527 RtlInitUnicodeString(&KeyName, L"BootConfig"); 01528 Status = ZwSetValueKey(LogConfKey, 01529 &KeyName, 01530 0, 01531 REG_RESOURCE_LIST, 01532 DeviceNode->BootResources, 01533 PnpDetermineResourceListSize(DeviceNode->BootResources)); 01534 } 01535 } 01536 01537 /* Set 'BasicConfigVector' value */ 01538 if (DeviceNode->ResourceRequirements != NULL && 01539 DeviceNode->ResourceRequirements->ListSize != 0) 01540 { 01541 RtlInitUnicodeString(&KeyName, L"BasicConfigVector"); 01542 Status = ZwSetValueKey(LogConfKey, 01543 &KeyName, 01544 0, 01545 REG_RESOURCE_REQUIREMENTS_LIST, 01546 DeviceNode->ResourceRequirements, 01547 DeviceNode->ResourceRequirements->ListSize); 01548 } 01549 01550 ZwClose(LogConfKey); 01551 } 01552 01553 /* Set the 'ConfigFlags' value */ 01554 RtlInitUnicodeString(&KeyName, L"ConfigFlags"); 01555 Status = ZwQueryValueKey(InstanceKey, 01556 &KeyName, 01557 KeyValueBasicInformation, 01558 NULL, 01559 0, 01560 &ResultLength); 01561 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 01562 { 01563 /* Write the default value */ 01564 ULONG DefaultConfigFlags = 0; 01565 Status = ZwSetValueKey(InstanceKey, 01566 &KeyName, 01567 0, 01568 REG_DWORD, 01569 &DefaultConfigFlags, 01570 sizeof(DefaultConfigFlags)); 01571 } 01572 01573 /* Create the 'Control' key */ 01574 RtlInitUnicodeString(&KeyName, L"Control"); 01575 InitializeObjectAttributes(&ObjectAttributes, 01576 &KeyName, 01577 OBJ_CASE_INSENSITIVE, 01578 InstanceKey, 01579 NULL); 01580 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL); 01581 01582 if (NT_SUCCESS(Status)) 01583 ZwClose(ControlHandle); 01584 01585 DPRINT("IopSetDeviceInstanceData() done\n"); 01586 01587 return Status; 01588 } 01589 01590 /* 01591 * IopGetParentIdPrefix 01592 * 01593 * Retrieve (or create) a string which identifies a device. 01594 * 01595 * Parameters 01596 * DeviceNode 01597 * Pointer to device node. 01598 * ParentIdPrefix 01599 * Pointer to the string where is returned the parent node identifier 01600 * 01601 * Remarks 01602 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is 01603 * valid and its Buffer field is NULL-terminated. The caller needs to 01604 * to free the string with RtlFreeUnicodeString when it is no longer 01605 * needed. 01606 */ 01607 01608 NTSTATUS 01609 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, 01610 PUNICODE_STRING ParentIdPrefix) 01611 { 01612 ULONG KeyNameBufferLength; 01613 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL; 01614 UNICODE_STRING KeyName = {0, 0, NULL}; 01615 UNICODE_STRING KeyValue; 01616 UNICODE_STRING ValueName; 01617 HANDLE hKey = NULL; 01618 ULONG crc32; 01619 NTSTATUS Status; 01620 01621 /* HACK: As long as some devices have a NULL device 01622 * instance path, the following test is required :( 01623 */ 01624 if (DeviceNode->Parent->InstancePath.Length == 0) 01625 { 01626 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n", 01627 &DeviceNode->InstancePath); 01628 return STATUS_UNSUCCESSFUL; 01629 } 01630 01631 /* 1. Try to retrieve ParentIdPrefix from registry */ 01632 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR); 01633 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR)); 01634 if (!ParentIdPrefixInformation) 01635 { 01636 return STATUS_INSUFFICIENT_RESOURCES; 01637 } 01638 01639 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length); 01640 if (!KeyName.Buffer) 01641 { 01642 Status = STATUS_INSUFFICIENT_RESOURCES; 01643 goto cleanup; 01644 } 01645 KeyName.Length = 0; 01646 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length; 01647 01648 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); 01649 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath); 01650 01651 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE); 01652 if (!NT_SUCCESS(Status)) 01653 goto cleanup; 01654 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix"); 01655 Status = ZwQueryValueKey( 01656 hKey, &ValueName, 01657 KeyValuePartialInformation, ParentIdPrefixInformation, 01658 KeyNameBufferLength, &KeyNameBufferLength); 01659 if (NT_SUCCESS(Status)) 01660 { 01661 if (ParentIdPrefixInformation->Type != REG_SZ) 01662 Status = STATUS_UNSUCCESSFUL; 01663 else 01664 { 01665 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength; 01666 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data; 01667 } 01668 goto cleanup; 01669 } 01670 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 01671 { 01672 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength; 01673 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data; 01674 goto cleanup; 01675 } 01676 01677 /* 2. Create the ParentIdPrefix value */ 01678 crc32 = RtlComputeCrc32(0, 01679 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer, 01680 DeviceNode->Parent->InstancePath.Length); 01681 01682 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32); 01683 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data); 01684 01685 /* 3. Try to write the ParentIdPrefix to registry */ 01686 Status = ZwSetValueKey(hKey, 01687 &ValueName, 01688 0, 01689 REG_SZ, 01690 (PVOID)KeyValue.Buffer, 01691 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR)); 01692 01693 cleanup: 01694 if (NT_SUCCESS(Status)) 01695 { 01696 /* Duplicate the string to return it */ 01697 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix); 01698 } 01699 ExFreePool(ParentIdPrefixInformation); 01700 RtlFreeUnicodeString(&KeyName); 01701 if (hKey != NULL) 01702 ZwClose(hKey); 01703 return Status; 01704 } 01705 01706 NTSTATUS 01707 IopQueryHardwareIds(PDEVICE_NODE DeviceNode, 01708 HANDLE InstanceKey) 01709 { 01710 IO_STACK_LOCATION Stack; 01711 IO_STATUS_BLOCK IoStatusBlock; 01712 PWSTR Ptr; 01713 UNICODE_STRING ValueName; 01714 NTSTATUS Status; 01715 ULONG Length, TotalLength; 01716 01717 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n"); 01718 01719 RtlZeroMemory(&Stack, sizeof(Stack)); 01720 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs; 01721 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 01722 &IoStatusBlock, 01723 IRP_MN_QUERY_ID, 01724 &Stack); 01725 if (NT_SUCCESS(Status)) 01726 { 01727 /* 01728 * FIXME: Check for valid characters, if there is invalid characters 01729 * then bugcheck. 01730 */ 01731 TotalLength = 0; 01732 Ptr = (PWSTR)IoStatusBlock.Information; 01733 DPRINT("Hardware IDs:\n"); 01734 while (*Ptr) 01735 { 01736 DPRINT(" %S\n", Ptr); 01737 Length = (ULONG)wcslen(Ptr) + 1; 01738 01739 Ptr += Length; 01740 TotalLength += Length; 01741 } 01742 DPRINT("TotalLength: %hu\n", TotalLength); 01743 DPRINT("\n"); 01744 01745 RtlInitUnicodeString(&ValueName, L"HardwareID"); 01746 Status = ZwSetValueKey(InstanceKey, 01747 &ValueName, 01748 0, 01749 REG_MULTI_SZ, 01750 (PVOID)IoStatusBlock.Information, 01751 (TotalLength + 1) * sizeof(WCHAR)); 01752 if (!NT_SUCCESS(Status)) 01753 { 01754 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 01755 } 01756 } 01757 else 01758 { 01759 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 01760 } 01761 01762 return Status; 01763 } 01764 01765 NTSTATUS 01766 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, 01767 HANDLE InstanceKey) 01768 { 01769 IO_STACK_LOCATION Stack; 01770 IO_STATUS_BLOCK IoStatusBlock; 01771 PWSTR Ptr; 01772 UNICODE_STRING ValueName; 01773 NTSTATUS Status; 01774 ULONG Length, TotalLength; 01775 01776 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n"); 01777 01778 RtlZeroMemory(&Stack, sizeof(Stack)); 01779 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs; 01780 Status = IopInitiatePnpIrp( 01781 DeviceNode->PhysicalDeviceObject, 01782 &IoStatusBlock, 01783 IRP_MN_QUERY_ID, 01784 &Stack); 01785 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 01786 { 01787 /* 01788 * FIXME: Check for valid characters, if there is invalid characters 01789 * then bugcheck. 01790 */ 01791 TotalLength = 0; 01792 Ptr = (PWSTR)IoStatusBlock.Information; 01793 DPRINT("Compatible IDs:\n"); 01794 while (*Ptr) 01795 { 01796 DPRINT(" %S\n", Ptr); 01797 Length = (ULONG)wcslen(Ptr) + 1; 01798 01799 Ptr += Length; 01800 TotalLength += Length; 01801 } 01802 DPRINT("TotalLength: %hu\n", TotalLength); 01803 DPRINT("\n"); 01804 01805 RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); 01806 Status = ZwSetValueKey(InstanceKey, 01807 &ValueName, 01808 0, 01809 REG_MULTI_SZ, 01810 (PVOID)IoStatusBlock.Information, 01811 (TotalLength + 1) * sizeof(WCHAR)); 01812 if (!NT_SUCCESS(Status)) 01813 { 01814 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status); 01815 } 01816 } 01817 else 01818 { 01819 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 01820 } 01821 01822 return Status; 01823 } 01824 01825 01826 /* 01827 * IopActionInterrogateDeviceStack 01828 * 01829 * Retrieve information for all (direct) child nodes of a parent node. 01830 * 01831 * Parameters 01832 * DeviceNode 01833 * Pointer to device node. 01834 * Context 01835 * Pointer to parent node to retrieve child node information for. 01836 * 01837 * Remarks 01838 * Any errors that occur are logged instead so that all child services have a chance 01839 * of being interrogated. 01840 */ 01841 01842 NTSTATUS 01843 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, 01844 PVOID Context) 01845 { 01846 IO_STATUS_BLOCK IoStatusBlock; 01847 PDEVICE_NODE ParentDeviceNode; 01848 WCHAR InstancePath[MAX_PATH]; 01849 IO_STACK_LOCATION Stack; 01850 NTSTATUS Status; 01851 ULONG RequiredLength; 01852 LCID LocaleId; 01853 HANDLE InstanceKey = NULL; 01854 UNICODE_STRING ValueName; 01855 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL }; 01856 UNICODE_STRING InstancePathU; 01857 DEVICE_CAPABILITIES DeviceCapabilities; 01858 PDEVICE_OBJECT OldDeviceObject; 01859 01860 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context); 01861 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); 01862 01863 ParentDeviceNode = (PDEVICE_NODE)Context; 01864 01865 /* 01866 * We are called for the parent too, but we don't need to do special 01867 * handling for this node 01868 */ 01869 01870 if (DeviceNode == ParentDeviceNode) 01871 { 01872 DPRINT("Success\n"); 01873 return STATUS_SUCCESS; 01874 } 01875 01876 /* 01877 * Make sure this device node is a direct child of the parent device node 01878 * that is given as an argument 01879 */ 01880 01881 if (DeviceNode->Parent != ParentDeviceNode) 01882 { 01883 DPRINT("Skipping 2+ level child\n"); 01884 return STATUS_SUCCESS; 01885 } 01886 01887 /* Skip processing if it was already completed before */ 01888 if (DeviceNode->Flags & DNF_PROCESSED) 01889 { 01890 /* Nothing to do */ 01891 return STATUS_SUCCESS; 01892 } 01893 01894 /* Get Locale ID */ 01895 Status = ZwQueryDefaultLocale(FALSE, &LocaleId); 01896 if (!NT_SUCCESS(Status)) 01897 { 01898 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status); 01899 return Status; 01900 } 01901 01902 /* 01903 * FIXME: For critical errors, cleanup and disable device, but always 01904 * return STATUS_SUCCESS. 01905 */ 01906 01907 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n"); 01908 01909 Stack.Parameters.QueryId.IdType = BusQueryDeviceID; 01910 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 01911 &IoStatusBlock, 01912 IRP_MN_QUERY_ID, 01913 &Stack); 01914 if (NT_SUCCESS(Status)) 01915 { 01916 /* Copy the device id string */ 01917 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information); 01918 01919 /* 01920 * FIXME: Check for valid characters, if there is invalid characters 01921 * then bugcheck. 01922 */ 01923 } 01924 else 01925 { 01926 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status); 01927 01928 /* We have to return success otherwise we abort the traverse operation */ 01929 return STATUS_SUCCESS; 01930 } 01931 01932 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n"); 01933 01934 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); 01935 if (!NT_SUCCESS(Status)) 01936 { 01937 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); 01938 01939 /* We have to return success otherwise we abort the traverse operation */ 01940 return STATUS_SUCCESS; 01941 } 01942 01943 /* This bit is only check after enumeration */ 01944 if (DeviceCapabilities.HardwareDisabled) 01945 { 01946 /* FIXME: Cleanup device */ 01947 DeviceNode->Flags |= DNF_DISABLED; 01948 return STATUS_SUCCESS; 01949 } 01950 else 01951 DeviceNode->Flags &= ~DNF_DISABLED; 01952 01953 if (!DeviceCapabilities.UniqueID) 01954 { 01955 /* Device has not a unique ID. We need to prepend parent bus unique identifier */ 01956 DPRINT("Instance ID is not unique\n"); 01957 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix); 01958 if (!NT_SUCCESS(Status)) 01959 { 01960 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status); 01961 01962 /* We have to return success otherwise we abort the traverse operation */ 01963 return STATUS_SUCCESS; 01964 } 01965 } 01966 01967 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n"); 01968 01969 Stack.Parameters.QueryId.IdType = BusQueryInstanceID; 01970 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, 01971 &IoStatusBlock, 01972 IRP_MN_QUERY_ID, 01973 &Stack); 01974 if (NT_SUCCESS(Status)) 01975 { 01976 /* Append the instance id string */ 01977 wcscat(InstancePath, L"\\"); 01978 if (ParentIdPrefix.Length > 0) 01979 { 01980 /* Add information from parent bus device to InstancePath */ 01981 wcscat(InstancePath, ParentIdPrefix.Buffer); 01982 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information) 01983 wcscat(InstancePath, L"&"); 01984 } 01985 if (IoStatusBlock.Information) 01986 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information); 01987 01988 /* 01989 * FIXME: Check for valid characters, if there is invalid characters 01990 * then bugcheck 01991 */ 01992 } 01993 else 01994 { 01995 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); 01996 } 01997 RtlFreeUnicodeString(&ParentIdPrefix); 01998 01999 if (!RtlCreateUnicodeString(&InstancePathU, InstancePath)) 02000 { 02001 DPRINT("No resources\n"); 02002 /* FIXME: Cleanup and disable device */ 02003 } 02004 02005 /* Verify that this is not a duplicate */ 02006 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU); 02007 if (OldDeviceObject != NULL) 02008 { 02009 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject); 02010 02011 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU); 02012 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath); 02013 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath); 02014 02015 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 02016 0x01, 02017 (ULONG_PTR)DeviceNode->PhysicalDeviceObject, 02018 (ULONG_PTR)OldDeviceObject, 02019 0); 02020 } 02021 02022 DeviceNode->InstancePath = InstancePathU; 02023 02024 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); 02025 02026 /* 02027 * Create registry key for the instance id, if it doesn't exist yet 02028 */ 02029 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey); 02030 if (!NT_SUCCESS(Status)) 02031 { 02032 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); 02033 02034 /* We have to return success otherwise we abort the traverse operation */ 02035 return STATUS_SUCCESS; 02036 } 02037 02038 IopQueryHardwareIds(DeviceNode, InstanceKey); 02039 02040 IopQueryCompatibleIds(DeviceNode, InstanceKey); 02041 02042 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n"); 02043 02044 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; 02045 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; 02046 Status = IopInitiatePnpIrp( 02047 DeviceNode->PhysicalDeviceObject, 02048 &IoStatusBlock, 02049 IRP_MN_QUERY_DEVICE_TEXT, 02050 &Stack); 02051 /* This key is mandatory, so even if the Irp fails, we still write it */ 02052 RtlInitUnicodeString(&ValueName, L"DeviceDesc"); 02053 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) 02054 { 02055 if (NT_SUCCESS(Status) && 02056 IoStatusBlock.Information && 02057 (*(PWSTR)IoStatusBlock.Information != 0)) 02058 { 02059 /* This key is overriden when a driver is installed. Don't write the 02060 * new description if another one already exists */ 02061 Status = ZwSetValueKey(InstanceKey, 02062 &ValueName, 02063 0, 02064 REG_SZ, 02065 (PVOID)IoStatusBlock.Information, 02066 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR)); 02067 } 02068 else 02069 { 02070 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); 02071 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status); 02072 02073 Status = ZwSetValueKey(InstanceKey, 02074 &ValueName, 02075 0, 02076 REG_SZ, 02077 DeviceDesc.Buffer, 02078 DeviceDesc.MaximumLength); 02079 02080 if (!NT_SUCCESS(Status)) 02081 { 02082 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status); 02083 } 02084 02085 } 02086 } 02087 02088 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n"); 02089 02090 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; 02091 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; 02092 Status = IopInitiatePnpIrp( 02093 DeviceNode->PhysicalDeviceObject, 02094 &IoStatusBlock, 02095 IRP_MN_QUERY_DEVICE_TEXT, 02096 &Stack); 02097 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 02098 { 02099 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information); 02100 RtlInitUnicodeString(&ValueName, L"LocationInformation"); 02101 Status = ZwSetValueKey(InstanceKey, 02102 &ValueName, 02103 0, 02104 REG_SZ, 02105 (PVOID)IoStatusBlock.Information, 02106 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR)); 02107 if (!NT_SUCCESS(Status)) 02108 { 02109 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); 02110 } 02111 } 02112 else 02113 { 02114 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 02115 } 02116 02117 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); 02118 02119 Status = IopInitiatePnpIrp( 02120 DeviceNode->PhysicalDeviceObject, 02121 &IoStatusBlock, 02122 IRP_MN_QUERY_BUS_INFORMATION, 02123 NULL); 02124 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 02125 { 02126 PPNP_BUS_INFORMATION BusInformation = 02127 (PPNP_BUS_INFORMATION)IoStatusBlock.Information; 02128 02129 DeviceNode->ChildBusNumber = BusInformation->BusNumber; 02130 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType; 02131 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid); 02132 ExFreePool(BusInformation); 02133 } 02134 else 02135 { 02136 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 02137 02138 DeviceNode->ChildBusNumber = 0xFFFFFFF0; 02139 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 02140 DeviceNode->ChildBusTypeIndex = -1; 02141 } 02142 02143 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 02144 02145 Status = IopInitiatePnpIrp( 02146 DeviceNode->PhysicalDeviceObject, 02147 &IoStatusBlock, 02148 IRP_MN_QUERY_RESOURCES, 02149 NULL); 02150 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 02151 { 02152 DeviceNode->BootResources = 02153 (PCM_RESOURCE_LIST)IoStatusBlock.Information; 02154 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 02155 } 02156 else 02157 { 02158 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 02159 DeviceNode->BootResources = NULL; 02160 } 02161 02162 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 02163 02164 Status = IopInitiatePnpIrp( 02165 DeviceNode->PhysicalDeviceObject, 02166 &IoStatusBlock, 02167 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 02168 NULL); 02169 if (NT_SUCCESS(Status)) 02170 { 02171 DeviceNode->ResourceRequirements = 02172 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 02173 } 02174 else 02175 { 02176 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 02177 DeviceNode->ResourceRequirements = NULL; 02178 } 02179 02180 if (InstanceKey != NULL) 02181 { 02182 IopSetDeviceInstanceData(InstanceKey, DeviceNode); 02183 } 02184 02185 ZwClose(InstanceKey); 02186 02187 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED); 02188 02189 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER)) 02190 { 02191 /* Report the device to the user-mode pnp manager */ 02192 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, 02193 &DeviceNode->InstancePath); 02194 } 02195 02196 return STATUS_SUCCESS; 02197 } 02198 02199 static 02200 VOID 02201 IopHandleDeviceRemoval( 02202 IN PDEVICE_NODE DeviceNode, 02203 IN PDEVICE_RELATIONS DeviceRelations) 02204 { 02205 PDEVICE_NODE Child = DeviceNode->Child, NextChild; 02206 ULONG i; 02207 BOOLEAN Found; 02208 02209 if (DeviceNode == IopRootDeviceNode) 02210 return; 02211 02212 while (Child != NULL) 02213 { 02214 NextChild = Child->Sibling; 02215 Found = FALSE; 02216 02217 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++) 02218 { 02219 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child) 02220 { 02221 Found = TRUE; 02222 break; 02223 } 02224 } 02225 02226 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED)) 02227 { 02228 /* Send removal IRPs to all of its children */ 02229 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE); 02230 02231 /* Send the surprise removal IRP */ 02232 IopSendSurpriseRemoval(Child->PhysicalDeviceObject); 02233 02234 /* Tell the user-mode PnP manager that a device was removed */ 02235 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 02236 &Child->InstancePath); 02237 02238 /* Send the remove device IRP */ 02239 IopSendRemoveDevice(Child->PhysicalDeviceObject); 02240 } 02241 02242 Child = NextChild; 02243 } 02244 } 02245 02246 NTSTATUS 02247 IopEnumerateDevice( 02248 IN PDEVICE_OBJECT DeviceObject) 02249 { 02250 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 02251 DEVICETREE_TRAVERSE_CONTEXT Context; 02252 PDEVICE_RELATIONS DeviceRelations; 02253 PDEVICE_OBJECT ChildDeviceObject; 02254 IO_STATUS_BLOCK IoStatusBlock; 02255 PDEVICE_NODE ChildDeviceNode; 02256 IO_STACK_LOCATION Stack; 02257 NTSTATUS Status; 02258 ULONG i; 02259 02260 DPRINT("DeviceObject 0x%p\n", DeviceObject); 02261 02262 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) 02263 { 02264 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; 02265 02266 DPRINT("Sending GUID_DEVICE_ARRIVAL\n"); 02267 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, 02268 &DeviceNode->InstancePath); 02269 } 02270 02271 DeviceNode->Flags &= ~DNF_NEED_TO_ENUM; 02272 02273 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n"); 02274 02275 Stack.Parameters.QueryDeviceRelations.Type = BusRelations; 02276 02277 Status = IopInitiatePnpIrp( 02278 DeviceObject, 02279 &IoStatusBlock, 02280 IRP_MN_QUERY_DEVICE_RELATIONS, 02281 &Stack); 02282 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) 02283 { 02284 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 02285 return Status; 02286 } 02287 02288 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 02289 02290 /* 02291 * Send removal IRPs for devices that have disappeared 02292 * NOTE: This code handles the case where no relations are specified 02293 */ 02294 IopHandleDeviceRemoval(DeviceNode, DeviceRelations); 02295 02296 /* Now we bail if nothing was returned */ 02297 if (!DeviceRelations) 02298 { 02299 /* We're all done */ 02300 DPRINT("No PDOs\n"); 02301 return STATUS_SUCCESS; 02302 } 02303 02304 DPRINT("Got %u PDOs\n", DeviceRelations->Count); 02305 02306 /* 02307 * Create device nodes for all discovered devices 02308 */ 02309 for (i = 0; i < DeviceRelations->Count; i++) 02310 { 02311 ChildDeviceObject = DeviceRelations->Objects[i]; 02312 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); 02313 02314 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); 02315 if (!ChildDeviceNode) 02316 { 02317 /* One doesn't exist, create it */ 02318 Status = IopCreateDeviceNode( 02319 DeviceNode, 02320 ChildDeviceObject, 02321 NULL, 02322 &ChildDeviceNode); 02323 if (NT_SUCCESS(Status)) 02324 { 02325 /* Mark the node as enumerated */ 02326 ChildDeviceNode->Flags |= DNF_ENUMERATED; 02327 02328 /* Mark the DO as bus enumerated */ 02329 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; 02330 } 02331 else 02332 { 02333 /* Ignore this DO */ 02334 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i); 02335 ObDereferenceObject(ChildDeviceObject); 02336 } 02337 } 02338 else 02339 { 02340 /* Mark it as enumerated */ 02341 ChildDeviceNode->Flags |= DNF_ENUMERATED; 02342 ObDereferenceObject(ChildDeviceObject); 02343 } 02344 } 02345 ExFreePool(DeviceRelations); 02346 02347 /* 02348 * Retrieve information about all discovered children from the bus driver 02349 */ 02350 IopInitDeviceTreeTraverseContext( 02351 &Context, 02352 DeviceNode, 02353 IopActionInterrogateDeviceStack, 02354 DeviceNode); 02355 02356 Status = IopTraverseDeviceTree(&Context); 02357 if (!NT_SUCCESS(Status)) 02358 { 02359 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); 02360 return Status; 02361 } 02362 02363 /* 02364 * Retrieve configuration from the registry for discovered children 02365 */ 02366 IopInitDeviceTreeTraverseContext( 02367 &Context, 02368 DeviceNode, 02369 IopActionConfigureChildServices, 02370 DeviceNode); 02371 02372 Status = IopTraverseDeviceTree(&Context); 02373 if (!NT_SUCCESS(Status)) 02374 { 02375 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); 02376 return Status; 02377 } 02378 02379 /* 02380 * Initialize services for discovered children. 02381 */ 02382 Status = IopInitializePnpServices(DeviceNode); 02383 if (!NT_SUCCESS(Status)) 02384 { 02385 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status); 02386 return Status; 02387 } 02388 02389 DPRINT("IopEnumerateDevice() finished\n"); 02390 return STATUS_SUCCESS; 02391 } 02392 02393 02394 /* 02395 * IopActionConfigureChildServices 02396 * 02397 * Retrieve configuration for all (direct) child nodes of a parent node. 02398 * 02399 * Parameters 02400 * DeviceNode 02401 * Pointer to device node. 02402 * Context 02403 * Pointer to parent node to retrieve child node configuration for. 02404 * 02405 * Remarks 02406 * Any errors that occur are logged instead so that all child services have a chance of beeing 02407 * configured. 02408 */ 02409 02410 NTSTATUS 02411 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, 02412 PVOID Context) 02413 { 02414 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 02415 PDEVICE_NODE ParentDeviceNode; 02416 PUNICODE_STRING Service; 02417 UNICODE_STRING ClassGUID; 02418 NTSTATUS Status; 02419 DEVICE_CAPABILITIES DeviceCaps; 02420 02421 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context); 02422 02423 ParentDeviceNode = (PDEVICE_NODE)Context; 02424 02425 /* 02426 * We are called for the parent too, but we don't need to do special 02427 * handling for this node 02428 */ 02429 if (DeviceNode == ParentDeviceNode) 02430 { 02431 DPRINT("Success\n"); 02432 return STATUS_SUCCESS; 02433 } 02434 02435 /* 02436 * Make sure this device node is a direct child of the parent device node 02437 * that is given as an argument 02438 */ 02439 02440 if (DeviceNode->Parent != ParentDeviceNode) 02441 { 02442 DPRINT("Skipping 2+ level child\n"); 02443 return STATUS_SUCCESS; 02444 } 02445 02446 if (!(DeviceNode->Flags & DNF_PROCESSED)) 02447 { 02448 DPRINT1("Child not ready to be configured\n"); 02449 return STATUS_SUCCESS; 02450 } 02451 02452 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED))) 02453 { 02454 WCHAR RegKeyBuffer[MAX_PATH]; 02455 UNICODE_STRING RegKey; 02456 02457 /* Install the service for this if it's in the CDDB */ 02458 IopInstallCriticalDevice(DeviceNode); 02459 02460 RegKey.Length = 0; 02461 RegKey.MaximumLength = sizeof(RegKeyBuffer); 02462 RegKey.Buffer = RegKeyBuffer; 02463 02464 /* 02465 * Retrieve configuration from Enum key 02466 */ 02467 02468 Service = &DeviceNode->ServiceName; 02469 02470 RtlZeroMemory(QueryTable, sizeof(QueryTable)); 02471 RtlInitUnicodeString(Service, NULL); 02472 RtlInitUnicodeString(&ClassGUID, NULL); 02473 02474 QueryTable[0].Name = L"Service"; 02475 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 02476 QueryTable[0].EntryContext = Service; 02477 02478 QueryTable[1].Name = L"ClassGUID"; 02479 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; 02480 QueryTable[1].EntryContext = &ClassGUID; 02481 QueryTable[1].DefaultType = REG_SZ; 02482 QueryTable[1].DefaultData = L""; 02483 QueryTable[1].DefaultLength = 0; 02484 02485 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); 02486 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); 02487 02488 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 02489 RegKey.Buffer, QueryTable, NULL, NULL); 02490 02491 if (!NT_SUCCESS(Status)) 02492 { 02493 /* FIXME: Log the error */ 02494 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n", 02495 &DeviceNode->InstancePath, Status); 02496 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 02497 return STATUS_SUCCESS; 02498 } 02499 02500 if (Service->Buffer == NULL) 02501 { 02502 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) && 02503 DeviceCaps.RawDeviceOK) 02504 { 02505 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName); 02506 02507 DeviceNode->ServiceName.Length = 0; 02508 DeviceNode->ServiceName.MaximumLength = 0; 02509 DeviceNode->ServiceName.Buffer = NULL; 02510 } 02511 else if (ClassGUID.Length != 0) 02512 { 02513 /* Device has a ClassGUID value, but no Service value. 02514 * Suppose it is using the NULL driver, so state the 02515 * device is started */ 02516 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath); 02517 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); 02518 } 02519 else 02520 { 02521 DeviceNode->Problem = CM_PROB_FAILED_INSTALL; 02522 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 02523 } 02524 return STATUS_SUCCESS; 02525 } 02526 02527 DPRINT("Got Service %S\n", Service->Buffer); 02528 } 02529 02530 return STATUS_SUCCESS; 02531 } 02532 02533 /* 02534 * IopActionInitChildServices 02535 * 02536 * Initialize the service for all (direct) child nodes of a parent node 02537 * 02538 * Parameters 02539 * DeviceNode 02540 * Pointer to device node. 02541 * Context 02542 * Pointer to parent node to initialize child node services for. 02543 * 02544 * Remarks 02545 * If the driver image for a service is not loaded and initialized 02546 * it is done here too. Any errors that occur are logged instead so 02547 * that all child services have a chance of being initialized. 02548 */ 02549 02550 NTSTATUS 02551 IopActionInitChildServices(PDEVICE_NODE DeviceNode, 02552 PVOID Context) 02553 { 02554 PDEVICE_NODE ParentDeviceNode; 02555 NTSTATUS Status; 02556 BOOLEAN BootDrivers = !PnpSystemInit; 02557 02558 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context); 02559 02560 ParentDeviceNode = (PDEVICE_NODE)Context; 02561 02562 /* 02563 * We are called for the parent too, but we don't need to do special 02564 * handling for this node 02565 */ 02566 if (DeviceNode == ParentDeviceNode) 02567 { 02568 DPRINT("Success\n"); 02569 return STATUS_SUCCESS; 02570 } 02571 02572 /* 02573 * We don't want to check for a direct child because 02574 * this function is called during boot to reinitialize 02575 * devices with drivers that couldn't load yet due to 02576 * stage 0 limitations (ie can't load from disk yet). 02577 */ 02578 02579 if (!(DeviceNode->Flags & DNF_PROCESSED)) 02580 { 02581 DPRINT1("Child not ready to be added\n"); 02582 return STATUS_SUCCESS; 02583 } 02584 02585 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) || 02586 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) || 02587 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) 02588 return STATUS_SUCCESS; 02589 02590 if (DeviceNode->ServiceName.Buffer == NULL) 02591 { 02592 /* We don't need to worry about loading the driver because we're 02593 * being driven in raw mode so our parent must be loaded to get here */ 02594 Status = IopInitializeDevice(DeviceNode, NULL); 02595 if (NT_SUCCESS(Status)) 02596 { 02597 Status = IopStartDevice(DeviceNode); 02598 if (!NT_SUCCESS(Status)) 02599 { 02600 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n", 02601 &DeviceNode->InstancePath, Status); 02602 } 02603 } 02604 } 02605 else 02606 { 02607 PLDR_DATA_TABLE_ENTRY ModuleObject; 02608 PDRIVER_OBJECT DriverObject; 02609 02610 /* Get existing DriverObject pointer (in case the driver has 02611 already been loaded and initialized) */ 02612 Status = IopGetDriverObject( 02613 &DriverObject, 02614 &DeviceNode->ServiceName, 02615 FALSE); 02616 02617 if (!NT_SUCCESS(Status)) 02618 { 02619 /* Driver is not initialized, try to load it */ 02620 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject); 02621 02622 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED) 02623 { 02624 /* Initialize the driver */ 02625 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, 02626 &DeviceNode->ServiceName, FALSE, &DriverObject); 02627 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY; 02628 } 02629 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD) 02630 { 02631 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName); 02632 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE; 02633 } 02634 else 02635 { 02636 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n", 02637 &DeviceNode->ServiceName, Status); 02638 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD; 02639 } 02640 } 02641 02642 /* Driver is loaded and initialized at this point */ 02643 if (NT_SUCCESS(Status)) 02644 { 02645 /* Initialize the device, including all filters */ 02646 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject); 02647 02648 /* Remove the extra reference */ 02649 ObDereferenceObject(DriverObject); 02650 } 02651 else 02652 { 02653 /* 02654 * Don't disable when trying to load only boot drivers 02655 */ 02656 if (!BootDrivers) 02657 { 02658 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); 02659 } 02660 } 02661 } 02662 02663 return STATUS_SUCCESS; 02664 } 02665 02666 /* 02667 * IopInitializePnpServices 02668 * 02669 * Initialize services for discovered children 02670 * 02671 * Parameters 02672 * DeviceNode 02673 * Top device node to start initializing services. 02674 * 02675 * Return Value 02676 * Status 02677 */ 02678 NTSTATUS 02679 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode) 02680 { 02681 DEVICETREE_TRAVERSE_CONTEXT Context; 02682 02683 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode); 02684 02685 IopInitDeviceTreeTraverseContext( 02686 &Context, 02687 DeviceNode, 02688 IopActionInitChildServices, 02689 DeviceNode); 02690 02691 return IopTraverseDeviceTree(&Context); 02692 } 02693 02694 static NTSTATUS INIT_FUNCTION 02695 IopEnumerateDetectedDevices( 02696 IN HANDLE hBaseKey, 02697 IN PUNICODE_STRING RelativePath OPTIONAL, 02698 IN HANDLE hRootKey, 02699 IN BOOLEAN EnumerateSubKeys, 02700 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources, 02701 IN ULONG ParentBootResourcesLength) 02702 { 02703 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier"); 02704 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 02705 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data"); 02706 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig"); 02707 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf"); 02708 OBJECT_ATTRIBUTES ObjectAttributes; 02709 HANDLE hDevicesKey = NULL; 02710 HANDLE hDeviceKey = NULL; 02711 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf; 02712 UNICODE_STRING Level2NameU; 02713 WCHAR Level2Name[5]; 02714 ULONG IndexDevice = 0; 02715 ULONG IndexSubKey; 02716 PKEY_BASIC_INFORMATION pDeviceInformation = NULL; 02717 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR); 02718 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL; 02719 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR); 02720 UNICODE_STRING DeviceName, ValueName; 02721 ULONG RequiredSize; 02722 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL; 02723 ULONG BootResourcesLength; 02724 NTSTATUS Status; 02725 02726 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController"); 02727 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0"); 02728 static ULONG DeviceIndexSerial = 0; 02729 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController"); 02730 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0"); 02731 static ULONG DeviceIndexKeyboard = 0; 02732 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController"); 02733 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0"); 02734 static ULONG DeviceIndexMouse = 0; 02735 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController"); 02736 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0"); 02737 static ULONG DeviceIndexParallel = 0; 02738 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral"); 02739 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0"); 02740 static ULONG DeviceIndexFloppy = 0; 02741 UNICODE_STRING HardwareIdKey; 02742 PUNICODE_STRING pHardwareId; 02743 ULONG DeviceIndex = 0; 02744 PUCHAR CmResourceList; 02745 ULONG ListCount; 02746 02747 if (RelativePath) 02748 { 02749 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS); 02750 if (!NT_SUCCESS(Status)) 02751 { 02752 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 02753 goto cleanup; 02754 } 02755 } 02756 else 02757 hDevicesKey = hBaseKey; 02758 02759 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 02760 if (!pDeviceInformation) 02761 { 02762 DPRINT("ExAllocatePool() failed\n"); 02763 Status = STATUS_NO_MEMORY; 02764 goto cleanup; 02765 } 02766 02767 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 02768 if (!pValueInformation) 02769 { 02770 DPRINT("ExAllocatePool() failed\n"); 02771 Status = STATUS_NO_MEMORY; 02772 goto cleanup; 02773 } 02774 02775 while (TRUE) 02776 { 02777 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 02778 if (Status == STATUS_NO_MORE_ENTRIES) 02779 break; 02780 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 02781 { 02782 ExFreePool(pDeviceInformation); 02783 DeviceInfoLength = RequiredSize; 02784 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 02785 if (!pDeviceInformation) 02786 { 02787 DPRINT("ExAllocatePool() failed\n"); 02788 Status = STATUS_NO_MEMORY; 02789 goto cleanup; 02790 } 02791 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 02792 } 02793 if (!NT_SUCCESS(Status)) 02794 { 02795 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 02796 goto cleanup; 02797 } 02798 IndexDevice++; 02799 02800 /* Open device key */ 02801 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 02802 DeviceName.Buffer = pDeviceInformation->Name; 02803 02804 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName, 02805 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0)); 02806 if (!NT_SUCCESS(Status)) 02807 { 02808 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 02809 goto cleanup; 02810 } 02811 02812 /* Read boot resources, and add then to parent ones */ 02813 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 02814 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 02815 { 02816 ExFreePool(pValueInformation); 02817 ValueInfoLength = RequiredSize; 02818 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 02819 if (!pValueInformation) 02820 { 02821 DPRINT("ExAllocatePool() failed\n"); 02822 ZwDeleteKey(hLevel2Key); 02823 Status = STATUS_NO_MEMORY; 02824 goto cleanup; 02825 } 02826 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 02827 } 02828 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 02829 { 02830 BootResources = ParentBootResources; 02831 BootResourcesLength = ParentBootResourcesLength; 02832 } 02833 else if (!NT_SUCCESS(Status)) 02834 { 02835 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 02836 goto nextdevice; 02837 } 02838 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR) 02839 { 02840 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR); 02841 goto nextdevice; 02842 } 02843 else 02844 { 02845 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors); 02846 02847 /* Concatenate current resources and parent ones */ 02848 if (ParentBootResourcesLength == 0) 02849 BootResourcesLength = pValueInformation->DataLength; 02850 else 02851 BootResourcesLength = ParentBootResourcesLength 02852 + pValueInformation->DataLength 02853 - Header; 02854 BootResources = ExAllocatePool(PagedPool, BootResourcesLength); 02855 if (!BootResources) 02856 { 02857 DPRINT("ExAllocatePool() failed\n"); 02858 goto nextdevice; 02859 } 02860 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 02861 { 02862 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 02863 } 02864 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific) 02865 { 02866 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength); 02867 RtlCopyMemory( 02868 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength), 02869 (PVOID)((ULONG_PTR)ParentBootResources + Header), 02870 ParentBootResourcesLength - Header); 02871 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 02872 } 02873 else 02874 { 02875 RtlCopyMemory(BootResources, pValueInformation->Data, Header); 02876 RtlCopyMemory( 02877 (PVOID)((ULONG_PTR)BootResources + Header), 02878 (PVOID)((ULONG_PTR)ParentBootResources + Header), 02879 ParentBootResourcesLength - Header); 02880 RtlCopyMemory( 02881 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength), 02882 pValueInformation->Data + Header, 02883 pValueInformation->DataLength - Header); 02884 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count; 02885 } 02886 } 02887 02888 if (EnumerateSubKeys) 02889 { 02890 IndexSubKey = 0; 02891 while (TRUE) 02892 { 02893 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 02894 if (Status == STATUS_NO_MORE_ENTRIES) 02895 break; 02896 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 02897 { 02898 ExFreePool(pDeviceInformation); 02899 DeviceInfoLength = RequiredSize; 02900 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength); 02901 if (!pDeviceInformation) 02902 { 02903 DPRINT("ExAllocatePool() failed\n"); 02904 Status = STATUS_NO_MEMORY; 02905 goto cleanup; 02906 } 02907 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize); 02908 } 02909 if (!NT_SUCCESS(Status)) 02910 { 02911 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 02912 goto cleanup; 02913 } 02914 IndexSubKey++; 02915 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength; 02916 DeviceName.Buffer = pDeviceInformation->Name; 02917 02918 Status = IopEnumerateDetectedDevices( 02919 hDeviceKey, 02920 &DeviceName, 02921 hRootKey, 02922 TRUE, 02923 BootResources, 02924 BootResourcesLength); 02925 if (!NT_SUCCESS(Status)) 02926 goto cleanup; 02927 } 02928 } 02929 02930 /* Read identifier */ 02931 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 02932 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) 02933 { 02934 ExFreePool(pValueInformation); 02935 ValueInfoLength = RequiredSize; 02936 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength); 02937 if (!pValueInformation) 02938 { 02939 DPRINT("ExAllocatePool() failed\n"); 02940 Status = STATUS_NO_MEMORY; 02941 goto cleanup; 02942 } 02943 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize); 02944 } 02945 if (!NT_SUCCESS(Status)) 02946 { 02947 if (Status != STATUS_OBJECT_NAME_NOT_FOUND) 02948 { 02949 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 02950 goto nextdevice; 02951 } 02952 ValueName.Length = ValueName.MaximumLength = 0; 02953 } 02954 else if (pValueInformation->Type != REG_SZ) 02955 { 02956 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ); 02957 goto nextdevice; 02958 } 02959 else 02960 { 02961 /* Assign hardware id to this device */ 02962 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength; 02963 ValueName.Buffer = (PWCHAR)pValueInformation->Data; 02964 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL) 02965 ValueName.Length -= sizeof(WCHAR); 02966 } 02967 02968 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0) 02969 { 02970 pHardwareId = &HardwareIdSerial; 02971 DeviceIndex = DeviceIndexSerial++; 02972 } 02973 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0) 02974 { 02975 pHardwareId = &HardwareIdKeyboard; 02976 DeviceIndex = DeviceIndexKeyboard++; 02977 } 02978 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0) 02979 { 02980 pHardwareId = &HardwareIdMouse; 02981 DeviceIndex = DeviceIndexMouse++; 02982 } 02983 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0) 02984 { 02985 pHardwareId = &HardwareIdParallel; 02986 DeviceIndex = DeviceIndexParallel++; 02987 } 02988 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0) 02989 { 02990 pHardwareId = &HardwareIdFloppy; 02991 DeviceIndex = DeviceIndexFloppy++; 02992 } 02993 else 02994 { 02995 /* Unknown key path */ 02996 DPRINT("Unknown key path '%wZ'\n", RelativePath); 02997 goto nextdevice; 02998 } 02999 03000 /* Prepare hardware id key (hardware id value without final \0) */ 03001 HardwareIdKey = *pHardwareId; 03002 HardwareIdKey.Length -= sizeof(UNICODE_NULL); 03003 03004 /* Add the detected device to Root key */ 03005 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL); 03006 Status = ZwCreateKey( 03007 &hLevel1Key, 03008 KEY_CREATE_SUB_KEY, 03009 &ObjectAttributes, 03010 0, 03011 NULL, 03012 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, 03013 NULL); 03014 if (!NT_SUCCESS(Status)) 03015 { 03016 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 03017 goto nextdevice; 03018 } 03019 swprintf(Level2Name, L"%04lu", DeviceIndex); 03020 RtlInitUnicodeString(&Level2NameU, Level2Name); 03021 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL); 03022 Status = ZwCreateKey( 03023 &hLevel2Key, 03024 KEY_SET_VALUE | KEY_CREATE_SUB_KEY, 03025 &ObjectAttributes, 03026 0, 03027 NULL, 03028 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, 03029 NULL); 03030 ZwClose(hLevel1Key); 03031 if (!NT_SUCCESS(Status)) 03032 { 03033 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 03034 goto nextdevice; 03035 } 03036 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey); 03037 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength); 03038 if (!NT_SUCCESS(Status)) 03039 { 03040 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 03041 ZwDeleteKey(hLevel2Key); 03042 goto nextdevice; 03043 } 03044 /* Create 'LogConf' subkey */ 03045 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL); 03046 Status = ZwCreateKey( 03047 &hLogConf, 03048 KEY_SET_VALUE, 03049 &ObjectAttributes, 03050 0, 03051 NULL, 03052 REG_OPTION_VOLATILE, 03053 NULL); 03054 if (!NT_SUCCESS(Status)) 03055 { 03056 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 03057 ZwDeleteKey(hLevel2Key); 03058 goto nextdevice; 03059 } 03060 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) 03061 { 03062 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG)); 03063 if (!CmResourceList) 03064 { 03065 ZwClose(hLogConf); 03066 ZwDeleteKey(hLevel2Key); 03067 goto nextdevice; 03068 } 03069 03070 /* Add the list count (1st member of CM_RESOURCE_LIST) */ 03071 ListCount = 1; 03072 RtlCopyMemory(CmResourceList, 03073 &ListCount, 03074 sizeof(ULONG)); 03075 03076 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */ 03077 RtlCopyMemory(CmResourceList + sizeof(ULONG), 03078 BootResources, 03079 BootResourcesLength); 03080 03081 /* Save boot resources to 'LogConf\BootConfig' */ 03082 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG)); 03083 if (!NT_SUCCESS(Status)) 03084 { 03085 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 03086 ZwClose(hLogConf); 03087 ZwDeleteKey(hLevel2Key); 03088 goto nextdevice; 03089 } 03090 } 03091 ZwClose(hLogConf); 03092 03093 nextdevice: 03094 if (BootResources && BootResources != ParentBootResources) 03095 { 03096 ExFreePool(BootResources); 03097 BootResources = NULL; 03098 } 03099 if (hLevel2Key) 03100 { 03101 ZwClose(hLevel2Key); 03102 hLevel2Key = NULL; 03103 } 03104 if (hDeviceKey) 03105 { 03106 ZwClose(hDeviceKey); 03107 hDeviceKey = NULL; 03108 } 03109 } 03110 03111 Status = STATUS_SUCCESS; 03112 03113 cleanup: 03114 if (hDevicesKey && hDevicesKey != hBaseKey) 03115 ZwClose(hDevicesKey); 03116 if (hDeviceKey) 03117 ZwClose(hDeviceKey); 03118 if (pDeviceInformation) 03119 ExFreePool(pDeviceInformation); 03120 if (pValueInformation) 03121 ExFreePool(pValueInformation); 03122 return Status; 03123 } 03124 03125 static BOOLEAN INIT_FUNCTION 03126 IopIsFirmwareMapperDisabled(VOID) 03127 { 03128 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp"); 03129 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper"); 03130 OBJECT_ATTRIBUTES ObjectAttributes; 03131 HANDLE hPnpKey; 03132 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation; 03133 ULONG DesiredLength, Length; 03134 ULONG KeyValue = 0; 03135 NTSTATUS Status; 03136 03137 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 03138 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes); 03139 if (NT_SUCCESS(Status)) 03140 { 03141 Status = ZwQueryValueKey(hPnpKey, 03142 &KeyNameU, 03143 KeyValuePartialInformation, 03144 NULL, 03145 0, 03146 &DesiredLength); 03147 if ((Status == STATUS_BUFFER_TOO_SMALL) || 03148 (Status == STATUS_BUFFER_OVERFLOW)) 03149 { 03150 Length = DesiredLength; 03151 KeyInformation = ExAllocatePool(PagedPool, Length); 03152 if (KeyInformation) 03153 { 03154 Status = ZwQueryValueKey(hPnpKey, 03155 &KeyNameU, 03156 KeyValuePartialInformation, 03157 KeyInformation, 03158 Length, 03159 &DesiredLength); 03160 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG)) 03161 { 03162 KeyValue = (ULONG)(*KeyInformation->Data); 03163 } 03164 else 03165 { 03166 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU); 03167 } 03168 03169 ExFreePool(KeyInformation); 03170 } 03171 else 03172 { 03173 DPRINT1("Failed to allocate memory for registry query\n"); 03174 } 03175 } 03176 else 03177 { 03178 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status); 03179 } 03180 03181 ZwClose(hPnpKey); 03182 } 03183 else 03184 { 03185 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status); 03186 } 03187 03188 DPRINT1("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled"); 03189 03190 return (KeyValue != 0) ? TRUE : FALSE; 03191 } 03192 03193 NTSTATUS 03194 NTAPI 03195 INIT_FUNCTION 03196 IopUpdateRootKey(VOID) 03197 { 03198 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); 03199 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root"); 03200 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"); 03201 OBJECT_ATTRIBUTES ObjectAttributes; 03202 HANDLE hEnum, hRoot; 03203 NTSTATUS Status; 03204 03205 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); 03206 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL); 03207 if (!NT_SUCCESS(Status)) 03208 { 03209 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status); 03210 return Status; 03211 } 03212 03213 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL); 03214 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL); 03215 ZwClose(hEnum); 03216 if (!NT_SUCCESS(Status)) 03217 { 03218 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status); 03219 return Status; 03220 } 03221 03222 if (!IopIsFirmwareMapperDisabled()) 03223 { 03224 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS); 03225 if (!NT_SUCCESS(Status)) 03226 { 03227 /* Nothing to do, don't return with an error status */ 03228 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 03229 ZwClose(hRoot); 03230 return STATUS_SUCCESS; 03231 } 03232 Status = IopEnumerateDetectedDevices( 03233 hEnum, 03234 NULL, 03235 hRoot, 03236 TRUE, 03237 NULL, 03238 0); 03239 ZwClose(hEnum); 03240 } 03241 else 03242 { 03243 /* Enumeration is disabled */ 03244 Status = STATUS_SUCCESS; 03245 } 03246 03247 ZwClose(hRoot); 03248 03249 return Status; 03250 } 03251 03252 NTSTATUS 03253 NTAPI 03254 IopOpenRegistryKeyEx(PHANDLE KeyHandle, 03255 HANDLE ParentKey, 03256 PUNICODE_STRING Name, 03257 ACCESS_MASK DesiredAccess) 03258 { 03259 OBJECT_ATTRIBUTES ObjectAttributes; 03260 NTSTATUS Status; 03261 03262 PAGED_CODE(); 03263 03264 *KeyHandle = NULL; 03265 03266 InitializeObjectAttributes(&ObjectAttributes, 03267 Name, 03268 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 03269 ParentKey, 03270 NULL); 03271 03272 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); 03273 03274 return Status; 03275 } 03276 03277 NTSTATUS 03278 NTAPI 03279 IopCreateRegistryKeyEx(OUT PHANDLE Handle, 03280 IN HANDLE RootHandle OPTIONAL, 03281 IN PUNICODE_STRING KeyName, 03282 IN ACCESS_MASK DesiredAccess, 03283 IN ULONG CreateOptions, 03284 OUT PULONG Disposition OPTIONAL) 03285 { 03286 OBJECT_ATTRIBUTES ObjectAttributes; 03287 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0; 03288 USHORT Length; 03289 HANDLE HandleArray[2]; 03290 BOOLEAN Recursing = TRUE; 03291 PWCHAR pp, p, p1; 03292 UNICODE_STRING KeyString; 03293 NTSTATUS Status = STATUS_SUCCESS; 03294 PAGED_CODE(); 03295 03296 /* P1 is start, pp is end */ 03297 p1 = KeyName->Buffer; 03298 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length); 03299 03300 /* Create the target key */ 03301 InitializeObjectAttributes(&ObjectAttributes, 03302 KeyName, 03303 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 03304 RootHandle, 03305 NULL); 03306 Status = ZwCreateKey(&HandleArray[i], 03307 DesiredAccess, 03308 &ObjectAttributes, 03309 0, 03310 NULL, 03311 CreateOptions, 03312 &KeyDisposition); 03313 03314 /* Now we check if this failed */ 03315 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle)) 03316 { 03317 /* Target key failed, so we'll need to create its parent. Setup array */ 03318 HandleArray[0] = NULL; 03319 HandleArray[1] = RootHandle; 03320 03321 /* Keep recursing for each missing parent */ 03322 while (Recursing) 03323 { 03324 /* And if we're deep enough, close the last handle */ 03325 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 03326 03327 /* We're setup to ping-pong between the two handle array entries */ 03328 RootHandleIndex = i; 03329 i = (i + 1) & 1; 03330 03331 /* Clear the one we're attempting to open now */ 03332 HandleArray[i] = NULL; 03333 03334 /* Process the parent key name */ 03335 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++); 03336 Length = (USHORT)(p - p1) * sizeof(WCHAR); 03337 03338 /* Is there a parent name? */ 03339 if (Length) 03340 { 03341 /* Build the unicode string for it */ 03342 KeyString.Buffer = p1; 03343 KeyString.Length = KeyString.MaximumLength = Length; 03344 03345 /* Now try opening the parent */ 03346 InitializeObjectAttributes(&ObjectAttributes, 03347 &KeyString, 03348 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 03349 HandleArray[RootHandleIndex], 03350 NULL); 03351 Status = ZwCreateKey(&HandleArray[i], 03352 DesiredAccess, 03353 &ObjectAttributes, 03354 0, 03355 NULL, 03356 CreateOptions, 03357 &KeyDisposition); 03358 if (NT_SUCCESS(Status)) 03359 { 03360 /* It worked, we have one more handle */ 03361 NestedCloseLevel++; 03362 } 03363 else 03364 { 03365 /* Parent key creation failed, abandon loop */ 03366 Recursing = FALSE; 03367 continue; 03368 } 03369 } 03370 else 03371 { 03372 /* We don't have a parent name, probably corrupted key name */ 03373 Status = STATUS_INVALID_PARAMETER; 03374 Recursing = FALSE; 03375 continue; 03376 } 03377 03378 /* Now see if there's more parents to create */ 03379 p1 = p + 1; 03380 if ((p == pp) || (p1 == pp)) 03381 { 03382 /* We're done, hopefully successfully, so stop */ 03383 Recursing = FALSE; 03384 } 03385 } 03386 03387 /* Outer loop check for handle nesting that requires closing the top handle */ 03388 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]); 03389 } 03390 03391 /* Check if we broke out of the loop due to success */ 03392 if (NT_SUCCESS(Status)) 03393 { 03394 /* Return the target handle (we closed all the parent ones) and disposition */ 03395 *Handle = HandleArray[i]; 03396 if (Disposition) *Disposition = KeyDisposition; 03397 } 03398 03399 /* Return the success state */ 03400 return Status; 03401 } 03402 03403 NTSTATUS 03404 NTAPI 03405 IopGetRegistryValue(IN HANDLE Handle, 03406 IN PWSTR ValueName, 03407 OUT PKEY_VALUE_FULL_INFORMATION *Information) 03408 { 03409 UNICODE_STRING ValueString; 03410 NTSTATUS Status; 03411 PKEY_VALUE_FULL_INFORMATION FullInformation; 03412 ULONG Size; 03413 PAGED_CODE(); 03414 03415 RtlInitUnicodeString(&ValueString, ValueName); 03416 03417 Status = ZwQueryValueKey(Handle, 03418 &ValueString, 03419 KeyValueFullInformation, 03420 NULL, 03421 0, 03422 &Size); 03423 if ((Status != STATUS_BUFFER_OVERFLOW) && 03424 (Status != STATUS_BUFFER_TOO_SMALL)) 03425 { 03426 return Status; 03427 } 03428 03429 FullInformation = ExAllocatePool(NonPagedPool, Size); 03430 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES; 03431 03432 Status = ZwQueryValueKey(Handle, 03433 &ValueString, 03434 KeyValueFullInformation, 03435 FullInformation, 03436 Size, 03437 &Size); 03438 if (!NT_SUCCESS(Status)) 03439 { 03440 ExFreePool(FullInformation); 03441 return Status; 03442 } 03443 03444 *Information = FullInformation; 03445 return STATUS_SUCCESS; 03446 } 03447 03448 RTL_GENERIC_COMPARE_RESULTS 03449 NTAPI 03450 PiCompareInstancePath(IN PRTL_AVL_TABLE Table, 03451 IN PVOID FirstStruct, 03452 IN PVOID SecondStruct) 03453 { 03454 /* FIXME: TODO */ 03455 ASSERT(FALSE); 03456 return 0; 03457 } 03458 03459 // 03460 // The allocation function is called by the generic table package whenever 03461 // it needs to allocate memory for the table. 03462 // 03463 03464 PVOID 03465 NTAPI 03466 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table, 03467 IN CLONG ByteSize) 03468 { 03469 /* FIXME: TODO */ 03470 ASSERT(FALSE); 03471 return NULL; 03472 } 03473 03474 VOID 03475 NTAPI 03476 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table, 03477 IN PVOID Buffer) 03478 { 03479 /* FIXME: TODO */ 03480 ASSERT(FALSE); 03481 } 03482 03483 VOID 03484 NTAPI 03485 PpInitializeDeviceReferenceTable(VOID) 03486 { 03487 /* Setup the guarded mutex and AVL table */ 03488 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock); 03489 RtlInitializeGenericTableAvl( 03490 &PpDeviceReferenceTable, 03491 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath, 03492 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry, 03493 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry, 03494 NULL); 03495 } 03496 03497 BOOLEAN 03498 NTAPI 03499 PiInitPhase0(VOID) 03500 { 03501 /* Initialize the resource when accessing device registry data */ 03502 ExInitializeResourceLite(&PpRegistryDeviceResource); 03503 03504 /* Setup the device reference AVL table */ 03505 PpInitializeDeviceReferenceTable(); 03506 return TRUE; 03507 } 03508 03509 BOOLEAN 03510 NTAPI 03511 PpInitSystem(VOID) 03512 { 03513 /* Check the initialization phase */ 03514 switch (ExpInitializationPhase) 03515 { 03516 case 0: 03517 03518 /* Do Phase 0 */ 03519 return PiInitPhase0(); 03520 03521 case 1: 03522 03523 /* Do Phase 1 */ 03524 return TRUE; 03525 //return PiInitPhase1(); 03526 03527 default: 03528 03529 /* Don't know any other phase! Bugcheck! */ 03530 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL); 03531 return FALSE; 03532 } 03533 } 03534 03535 LONG IopNumberDeviceNodes; 03536 03537 PDEVICE_NODE 03538 NTAPI 03539 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject) 03540 { 03541 PDEVICE_NODE DeviceNode; 03542 PAGED_CODE(); 03543 03544 /* Allocate it */ 03545 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD'); 03546 if (!DeviceNode) return DeviceNode; 03547 03548 /* Statistics */ 03549 InterlockedIncrement(&IopNumberDeviceNodes); 03550 03551 /* Set it up */ 03552 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE)); 03553 DeviceNode->InterfaceType = InterfaceTypeUndefined; 03554 DeviceNode->BusNumber = -1; 03555 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 03556 DeviceNode->ChildBusNumber = -1; 03557 DeviceNode->ChildBusTypeIndex = -1; 03558 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE); 03559 InitializeListHead(&DeviceNode->DeviceArbiterList); 03560 InitializeListHead(&DeviceNode->DeviceTranslatorList); 03561 InitializeListHead(&DeviceNode->TargetDeviceNotify); 03562 InitializeListHead(&DeviceNode->DockInfo.ListEntry); 03563 InitializeListHead(&DeviceNode->PendedSetInterfaceState); 03564 03565 /* Check if there is a PDO */ 03566 if (PhysicalDeviceObject) 03567 { 03568 /* Link it and remove the init flag */ 03569 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject; 03570 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode; 03571 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 03572 } 03573 03574 /* Return the node */ 03575 return DeviceNode; 03576 } 03577 03578 /* PUBLIC FUNCTIONS **********************************************************/ 03579 03580 NTSTATUS 03581 NTAPI 03582 PnpBusTypeGuidGet(IN USHORT Index, 03583 IN LPGUID BusTypeGuid) 03584 { 03585 NTSTATUS Status = STATUS_SUCCESS; 03586 03587 /* Acquire the lock */ 03588 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock); 03589 03590 /* Validate size */ 03591 if (Index < PnpBusTypeGuidList->GuidCount) 03592 { 03593 /* Copy the data */ 03594 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID)); 03595 } 03596 else 03597 { 03598 /* Failure path */ 03599 Status = STATUS_OBJECT_NAME_NOT_FOUND; 03600 } 03601 03602 /* Release lock and return status */ 03603 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock); 03604 return Status; 03605 } 03606 03607 NTSTATUS 03608 NTAPI 03609 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject, 03610 IN PHANDLE DeviceInstanceHandle, 03611 IN ACCESS_MASK DesiredAccess) 03612 { 03613 NTSTATUS Status; 03614 HANDLE KeyHandle; 03615 PDEVICE_NODE DeviceNode; 03616 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); 03617 PAGED_CODE(); 03618 03619 /* Open the enum key */ 03620 Status = IopOpenRegistryKeyEx(&KeyHandle, 03621 NULL, 03622 &KeyName, 03623 KEY_READ); 03624 if (!NT_SUCCESS(Status)) return Status; 03625 03626 /* Make sure we have an instance path */ 03627 DeviceNode = IopGetDeviceNode(DeviceObject); 03628 if ((DeviceNode) && (DeviceNode->InstancePath.Length)) 03629 { 03630 /* Get the instance key */ 03631 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle, 03632 KeyHandle, 03633 &DeviceNode->InstancePath, 03634 DesiredAccess); 03635 } 03636 else 03637 { 03638 /* Fail */ 03639 Status = STATUS_INVALID_DEVICE_REQUEST; 03640 } 03641 03642 /* Close the handle and return status */ 03643 ZwClose(KeyHandle); 03644 return Status; 03645 } 03646 03647 ULONG 03648 NTAPI 03649 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList) 03650 { 03651 ULONG FinalSize, PartialSize, EntrySize, i, j; 03652 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 03653 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 03654 03655 /* If we don't have one, that's easy */ 03656 if (!ResourceList) return 0; 03657 03658 /* Start with the minimum size possible */ 03659 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List); 03660 03661 /* Loop each full descriptor */ 03662 FullDescriptor = ResourceList->List; 03663 for (i = 0; i < ResourceList->Count; i++) 03664 { 03665 /* Start with the minimum size possible */ 03666 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) + 03667 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); 03668 03669 /* Loop each partial descriptor */ 03670 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors; 03671 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++) 03672 { 03673 /* Start with the minimum size possible */ 03674 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 03675 03676 /* Check if there is extra data */ 03677 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) 03678 { 03679 /* Add that data */ 03680 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize; 03681 } 03682 03683 /* The size of partial descriptors is bigger */ 03684 PartialSize += EntrySize; 03685 03686 /* Go to the next partial descriptor */ 03687 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize); 03688 } 03689 03690 /* The size of full descriptors is bigger */ 03691 FinalSize += PartialSize; 03692 03693 /* Go to the next full descriptor */ 03694 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize); 03695 } 03696 03697 /* Return the final size */ 03698 return FinalSize; 03699 } 03700 03701 NTSTATUS 03702 NTAPI 03703 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject, 03704 IN ULONG ValueType, 03705 IN PWSTR ValueName, 03706 IN PWSTR KeyName, 03707 OUT PVOID Buffer, 03708 IN PULONG BufferLength) 03709 { 03710 NTSTATUS Status; 03711 HANDLE KeyHandle, SubHandle; 03712 UNICODE_STRING KeyString; 03713 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL; 03714 ULONG Length; 03715 PAGED_CODE(); 03716 03717 /* Find the instance key */ 03718 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ); 03719 if (NT_SUCCESS(Status)) 03720 { 03721 /* Check for name given by caller */ 03722 if (KeyName) 03723 { 03724 /* Open this key */ 03725 RtlInitUnicodeString(&KeyString, KeyName); 03726 Status = IopOpenRegistryKeyEx(&SubHandle, 03727 KeyHandle, 03728 &KeyString, 03729 KEY_READ); 03730 if (NT_SUCCESS(Status)) 03731 { 03732 /* And use this handle instead */ 03733 ZwClose(KeyHandle); 03734 KeyHandle = SubHandle; 03735 } 03736 } 03737 03738 /* Check if sub-key handle succeeded (or no-op if no key name given) */ 03739 if (NT_SUCCESS(Status)) 03740 { 03741 /* Now get the size of the property */ 03742 Status = IopGetRegistryValue(KeyHandle, 03743 ValueName, 03744 &KeyValueInfo); 03745 } 03746 03747 /* Close the key */ 03748 ZwClose(KeyHandle); 03749 } 03750 03751 /* Fail if any of the registry operations failed */ 03752 if (!NT_SUCCESS(Status)) return Status; 03753 03754 /* Check how much data we have to copy */ 03755 Length = KeyValueInfo->DataLength; 03756 if (*BufferLength >= Length) 03757 { 03758 /* Check for a match in the value type */ 03759 if (KeyValueInfo->Type == ValueType) 03760 { 03761 /* Copy the data */ 03762 RtlCopyMemory(Buffer, 03763 (PVOID)((ULONG_PTR)KeyValueInfo + 03764 KeyValueInfo->DataOffset), 03765 Length); 03766 } 03767 else 03768 { 03769 /* Invalid registry property type, fail */ 03770 Status = STATUS_INVALID_PARAMETER_2; 03771 } 03772 } 03773 else 03774 { 03775 /* Buffer is too small to hold data */ 03776 Status = STATUS_BUFFER_TOO_SMALL; 03777 } 03778 03779 /* Return the required buffer length, free the buffer, and return status */ 03780 *BufferLength = Length; 03781 ExFreePool(KeyValueInfo); 03782 return Status; 03783 } 03784 03785 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;} 03786 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;} 03787 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;} 03788 03789 /* 03790 * @implemented 03791 */ 03792 NTSTATUS 03793 NTAPI 03794 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, 03795 IN DEVICE_REGISTRY_PROPERTY DeviceProperty, 03796 IN ULONG BufferLength, 03797 OUT PVOID PropertyBuffer, 03798 OUT PULONG ResultLength) 03799 { 03800 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 03801 DEVICE_CAPABILITIES DeviceCaps; 03802 ULONG ReturnLength = 0, Length = 0, ValueType; 03803 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName; 03804 PVOID Data = NULL; 03805 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL; 03806 GUID BusTypeGuid; 03807 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL; 03808 BOOLEAN NullTerminate = FALSE; 03809 03810 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty); 03811 03812 /* Assume failure */ 03813 *ResultLength = 0; 03814 03815 /* Only PDOs can call this */ 03816 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST; 03817 03818 /* Handle all properties */ 03819 switch (DeviceProperty) 03820 { 03821 case DevicePropertyBusTypeGuid: 03822 03823 /* Get the GUID from the internal cache */ 03824 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid); 03825 if (!NT_SUCCESS(Status)) return Status; 03826 03827 /* This is the format of the returned data */ 03828 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid); 03829 03830 case DevicePropertyLegacyBusType: 03831 03832 /* Validate correct interface type */ 03833 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined) 03834 return STATUS_OBJECT_NAME_NOT_FOUND; 03835 03836 /* This is the format of the returned data */ 03837 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType); 03838 03839 case DevicePropertyBusNumber: 03840 03841 /* Validate correct bus number */ 03842 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000) 03843 return STATUS_OBJECT_NAME_NOT_FOUND; 03844 03845 /* This is the format of the returned data */ 03846 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber); 03847 03848 case DevicePropertyEnumeratorName: 03849 03850 /* Get the instance path */ 03851 DeviceInstanceName = DeviceNode->InstancePath.Buffer; 03852 03853 /* Sanity checks */ 03854 ASSERT((BufferLength & 1) == 0); 03855 ASSERT(DeviceInstanceName != NULL); 03856 03857 /* Get the name from the path */ 03858 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR); 03859 ASSERT(EnumeratorNameEnd); 03860 03861 /* This string needs to be NULL-terminated */ 03862 NullTerminate = TRUE; 03863 03864 /* This is the format of the returned data */ 03865 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR), 03866 DeviceInstanceName); 03867 03868 case DevicePropertyAddress: 03869 03870 /* Query the device caps */ 03871 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps); 03872 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG)) 03873 return STATUS_OBJECT_NAME_NOT_FOUND; 03874 03875 /* This is the format of the returned data */ 03876 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address); 03877 03878 case DevicePropertyBootConfigurationTranslated: 03879 03880 /* Validate we have resources */ 03881 if (!DeviceNode->BootResources) 03882 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field 03883 { 03884 /* No resources will still fake success, but with 0 bytes */ 03885 *ResultLength = 0; 03886 return STATUS_SUCCESS; 03887 } 03888 03889 /* This is the format of the returned data */ 03890 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated 03891 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated 03892 03893 case DevicePropertyPhysicalDeviceObjectName: 03894 03895 /* Sanity check for Unicode-sized string */ 03896 ASSERT((BufferLength & 1) == 0); 03897 03898 /* Allocate name buffer */ 03899 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION); 03900 ObjectNameInfo = ExAllocatePool(PagedPool, Length); 03901 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES; 03902 03903 /* Query the PDO name */ 03904 Status = ObQueryNameString(DeviceObject, 03905 ObjectNameInfo, 03906 Length, 03907 ResultLength); 03908 if (Status == STATUS_INFO_LENGTH_MISMATCH) 03909 { 03910 /* It's up to the caller to try again */ 03911 Status = STATUS_BUFFER_TOO_SMALL; 03912 } 03913 03914 /* This string needs to be NULL-terminated */ 03915 NullTerminate = TRUE; 03916 03917 /* Return if successful */ 03918 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length, 03919 ObjectNameInfo->Name.Buffer); 03920 03921 /* Let the caller know how big the name is */ 03922 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION); 03923 break; 03924 03925 /* Handle the registry-based properties */ 03926 case DevicePropertyUINumber: 03927 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD); 03928 case DevicePropertyLocationInformation: 03929 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ); 03930 case DevicePropertyDeviceDescription: 03931 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ); 03932 case DevicePropertyHardwareID: 03933 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ); 03934 case DevicePropertyCompatibleIDs: 03935 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ); 03936 case DevicePropertyBootConfiguration: 03937 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST); 03938 case DevicePropertyClassName: 03939 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ); 03940 case DevicePropertyClassGuid: 03941 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ); 03942 case DevicePropertyDriverKeyName: 03943 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ); 03944 case DevicePropertyManufacturer: 03945 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ); 03946 case DevicePropertyFriendlyName: 03947 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ); 03948 case DevicePropertyContainerID: 03949 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7 03950 PIP_UNIMPLEMENTED(); 03951 case DevicePropertyRemovalPolicy: 03952 PIP_UNIMPLEMENTED(); 03953 case DevicePropertyInstallState: 03954 PIP_UNIMPLEMENTED(); 03955 case DevicePropertyResourceRequirements: 03956 PIP_UNIMPLEMENTED(); 03957 case DevicePropertyAllocatedResources: 03958 PIP_UNIMPLEMENTED(); 03959 default: 03960 return STATUS_INVALID_PARAMETER_2; 03961 } 03962 03963 /* Having a registry value name implies registry data */ 03964 if (ValueName) 03965 { 03966 /* We know up-front how much data to expect */ 03967 *ResultLength = BufferLength; 03968 03969 /* Go get the data, use the LogConf subkey if necessary */ 03970 Status = PiGetDeviceRegistryProperty(DeviceObject, 03971 ValueType, 03972 ValueName, 03973 (DeviceProperty == 03974 DevicePropertyBootConfiguration) ? 03975 L"LogConf": NULL, 03976 PropertyBuffer, 03977 ResultLength); 03978 } 03979 else if (NT_SUCCESS(Status)) 03980 { 03981 /* We know up-front how much data to expect, check the caller's buffer */ 03982 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0); 03983 if (*ResultLength <= BufferLength) 03984 { 03985 /* Buffer is all good, copy the data */ 03986 RtlCopyMemory(PropertyBuffer, Data, ReturnLength); 03987 03988 /* Check if we need to NULL-terminate the string */ 03989 if (NullTerminate) 03990 { 03991 /* Terminate the string */ 03992 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL; 03993 } 03994 03995 /* This is the success path */ 03996 Status = STATUS_SUCCESS; 03997 } 03998 else 03999 { 04000 /* Failure path */ 04001 Status = STATUS_BUFFER_TOO_SMALL; 04002 } 04003 } 04004 04005 /* Free any allocation we may have made, and return the status code */ 04006 if (ObjectNameInfo) ExFreePool(ObjectNameInfo); 04007 return Status; 04008 } 04009 04010 /* 04011 * @implemented 04012 */ 04013 VOID 04014 NTAPI 04015 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) 04016 { 04017 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 04018 IO_STACK_LOCATION Stack; 04019 ULONG PnPFlags; 04020 NTSTATUS Status; 04021 IO_STATUS_BLOCK IoStatusBlock; 04022 04023 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); 04024 Stack.MajorFunction = IRP_MJ_PNP; 04025 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE; 04026 04027 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags); 04028 if (!NT_SUCCESS(Status)) 04029 { 04030 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status); 04031 return; 04032 } 04033 04034 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) 04035 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; 04036 else 04037 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; 04038 04039 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) 04040 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 04041 else 04042 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; 04043 04044 if ((PnPFlags & PNP_DEVICE_REMOVED) || 04045 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) 04046 { 04047 /* Flag it if it's failed */ 04048 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START; 04049 04050 /* Send removal IRPs to all of its children */ 04051 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE); 04052 04053 /* Send surprise removal */ 04054 IopSendSurpriseRemoval(PhysicalDeviceObject); 04055 04056 /* Tell the user-mode PnP manager that a device was removed */ 04057 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, 04058 &DeviceNode->InstancePath); 04059 04060 IopSendRemoveDevice(PhysicalDeviceObject); 04061 } 04062 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) 04063 { 04064 /* Stop for resource rebalance */ 04065 Status = IopStopDevice(DeviceNode); 04066 if (!NT_SUCCESS(Status)) 04067 { 04068 DPRINT1("Failed to stop device for rebalancing\n"); 04069 04070 /* Stop failed so don't rebalance */ 04071 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; 04072 } 04073 } 04074 04075 /* Resource rebalance */ 04076 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) 04077 { 04078 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); 04079 04080 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 04081 &IoStatusBlock, 04082 IRP_MN_QUERY_RESOURCES, 04083 NULL); 04084 if (NT_SUCCESS(Status) && IoStatusBlock.Information) 04085 { 04086 DeviceNode->BootResources = 04087 (PCM_RESOURCE_LIST)IoStatusBlock.Information; 04088 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 04089 } 04090 else 04091 { 04092 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); 04093 DeviceNode->BootResources = NULL; 04094 } 04095 04096 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); 04097 04098 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 04099 &IoStatusBlock, 04100 IRP_MN_QUERY_RESOURCE_REQUIREMENTS, 04101 NULL); 04102 if (NT_SUCCESS(Status)) 04103 { 04104 DeviceNode->ResourceRequirements = 04105 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; 04106 } 04107 else 04108 { 04109 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); 04110 DeviceNode->ResourceRequirements = NULL; 04111 } 04112 04113 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ 04114 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) 04115 { 04116 DPRINT1("Restart after resource rebalance failed\n"); 04117 04118 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); 04119 DeviceNode->Flags |= DNF_START_FAILED; 04120 04121 IopRemoveDevice(DeviceNode); 04122 } 04123 } 04124 } 04125 04141 NTSTATUS 04142 NTAPI 04143 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, 04144 IN ULONG DevInstKeyType, 04145 IN ACCESS_MASK DesiredAccess, 04146 OUT PHANDLE DevInstRegKey) 04147 { 04148 static WCHAR RootKeyName[] = 04149 L"\\Registry\\Machine\\System\\CurrentControlSet\\"; 04150 static WCHAR ProfileKeyName[] = 04151 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\"; 04152 static WCHAR ClassKeyName[] = L"Control\\Class\\"; 04153 static WCHAR EnumKeyName[] = L"Enum\\"; 04154 static WCHAR DeviceParametersKeyName[] = L"Device Parameters"; 04155 ULONG KeyNameLength; 04156 LPWSTR KeyNameBuffer; 04157 UNICODE_STRING KeyName; 04158 ULONG DriverKeyLength; 04159 OBJECT_ATTRIBUTES ObjectAttributes; 04160 PDEVICE_NODE DeviceNode = NULL; 04161 NTSTATUS Status; 04162 04163 DPRINT("IoOpenDeviceRegistryKey() called\n"); 04164 04165 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0) 04166 { 04167 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n"); 04168 return STATUS_INVALID_PARAMETER; 04169 } 04170 04171 if (!IopIsValidPhysicalDeviceObject(DeviceObject)) 04172 return STATUS_INVALID_DEVICE_REQUEST; 04173 DeviceNode = IopGetDeviceNode(DeviceObject); 04174 04175 /* 04176 * Calculate the length of the base key name. This is the full 04177 * name for driver key or the name excluding "Device Parameters" 04178 * subkey for device key. 04179 */ 04180 04181 KeyNameLength = sizeof(RootKeyName); 04182 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 04183 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL); 04184 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 04185 { 04186 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL); 04187 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 04188 0, NULL, &DriverKeyLength); 04189 if (Status != STATUS_BUFFER_TOO_SMALL) 04190 return Status; 04191 KeyNameLength += DriverKeyLength; 04192 } 04193 else 04194 { 04195 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) + 04196 DeviceNode->InstancePath.Length; 04197 } 04198 04199 /* 04200 * Now allocate the buffer for the key name... 04201 */ 04202 04203 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength); 04204 if (KeyNameBuffer == NULL) 04205 return STATUS_INSUFFICIENT_RESOURCES; 04206 04207 KeyName.Length = 0; 04208 KeyName.MaximumLength = (USHORT)KeyNameLength; 04209 KeyName.Buffer = KeyNameBuffer; 04210 04211 /* 04212 * ...and build the key name. 04213 */ 04214 04215 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL); 04216 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length); 04217 04218 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) 04219 RtlAppendUnicodeToString(&KeyName, ProfileKeyName); 04220 04221 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 04222 { 04223 RtlAppendUnicodeToString(&KeyName, ClassKeyName); 04224 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName, 04225 DriverKeyLength, KeyNameBuffer + 04226 (KeyName.Length / sizeof(WCHAR)), 04227 &DriverKeyLength); 04228 if (!NT_SUCCESS(Status)) 04229 { 04230 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status); 04231 ExFreePool(KeyNameBuffer); 04232 return Status; 04233 } 04234 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL); 04235 } 04236 else 04237 { 04238 RtlAppendUnicodeToString(&KeyName, EnumKeyName); 04239 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath); 04240 if (DeviceNode->InstancePath.Length == 0) 04241 { 04242 ExFreePool(KeyNameBuffer); 04243 return Status; 04244 } 04245 } 04246 04247 /* 04248 * Open the base key. 04249 */ 04250 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess); 04251 if (!NT_SUCCESS(Status)) 04252 { 04253 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status); 04254 ExFreePool(KeyNameBuffer); 04255 return Status; 04256 } 04257 ExFreePool(KeyNameBuffer); 04258 04259 /* 04260 * For driver key we're done now. 04261 */ 04262 04263 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) 04264 return Status; 04265 04266 /* 04267 * Let's go further. For device key we must open "Device Parameters" 04268 * subkey and create it if it doesn't exist yet. 04269 */ 04270 04271 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName); 04272 InitializeObjectAttributes(&ObjectAttributes, &KeyName, 04273 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL); 04274 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes, 04275 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL); 04276 ZwClose(ObjectAttributes.RootDirectory); 04277 04278 return Status; 04279 } 04280 04281 static 04282 NTSTATUS 04283 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) 04284 { 04285 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; 04286 NTSTATUS Status; 04287 KIRQL OldIrql; 04288 04289 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04290 ChildDeviceNode = ParentDeviceNode->Child; 04291 while (ChildDeviceNode != NULL) 04292 { 04293 NextDeviceNode = ChildDeviceNode->Sibling; 04294 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04295 04296 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); 04297 if (!NT_SUCCESS(Status)) 04298 { 04299 FailedRemoveDevice = ChildDeviceNode; 04300 goto cleanup; 04301 } 04302 04303 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04304 ChildDeviceNode = NextDeviceNode; 04305 } 04306 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04307 04308 return STATUS_SUCCESS; 04309 04310 cleanup: 04311 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04312 ChildDeviceNode = ParentDeviceNode->Child; 04313 while (ChildDeviceNode != NULL) 04314 { 04315 NextDeviceNode = ChildDeviceNode->Sibling; 04316 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04317 04318 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 04319 04320 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 04321 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 04322 if (ChildDeviceNode == FailedRemoveDevice) 04323 return Status; 04324 04325 ChildDeviceNode = NextDeviceNode; 04326 04327 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04328 } 04329 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04330 04331 return Status; 04332 } 04333 04334 static 04335 VOID 04336 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 04337 { 04338 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 04339 KIRQL OldIrql; 04340 04341 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04342 ChildDeviceNode = ParentDeviceNode->Child; 04343 while (ChildDeviceNode != NULL) 04344 { 04345 NextDeviceNode = ChildDeviceNode->Sibling; 04346 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04347 04348 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); 04349 04350 ChildDeviceNode = NextDeviceNode; 04351 04352 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04353 } 04354 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04355 } 04356 04357 static 04358 VOID 04359 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) 04360 { 04361 PDEVICE_NODE ChildDeviceNode, NextDeviceNode; 04362 KIRQL OldIrql; 04363 04364 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04365 ChildDeviceNode = ParentDeviceNode->Child; 04366 while (ChildDeviceNode != NULL) 04367 { 04368 NextDeviceNode = ChildDeviceNode->Sibling; 04369 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04370 04371 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); 04372 04373 ChildDeviceNode = NextDeviceNode; 04374 04375 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); 04376 } 04377 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); 04378 } 04379 04380 static 04381 NTSTATUS 04382 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) 04383 { 04384 /* This function DOES NOT dereference the device objects on SUCCESS 04385 * but it DOES dereference device objects on FAILURE */ 04386 04387 ULONG i, j; 04388 NTSTATUS Status; 04389 04390 for (i = 0; i < DeviceRelations->Count; i++) 04391 { 04392 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); 04393 if (!NT_SUCCESS(Status)) 04394 { 04395 j = i; 04396 goto cleanup; 04397 } 04398 } 04399 04400 return STATUS_SUCCESS; 04401 04402 cleanup: 04403 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device 04404 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ 04405 for (i = 0; i <= j; i++) 04406 { 04407 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 04408 ObDereferenceObject(DeviceRelations->Objects[i]); 04409 DeviceRelations->Objects[i] = NULL; 04410 } 04411 for (; i < DeviceRelations->Count; i++) 04412 { 04413 ObDereferenceObject(DeviceRelations->Objects[i]); 04414 DeviceRelations->Objects[i] = NULL; 04415 } 04416 ExFreePool(DeviceRelations); 04417 04418 return Status; 04419 } 04420 04421 static 04422 VOID 04423 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 04424 { 04425 /* This function DOES dereference the device objects in all cases */ 04426 04427 ULONG i; 04428 04429 for (i = 0; i < DeviceRelations->Count; i++) 04430 { 04431 IopSendRemoveDevice(DeviceRelations->Objects[i]); 04432 ObDereferenceObject(DeviceRelations->Objects[i]); 04433 DeviceRelations->Objects[i] = NULL; 04434 } 04435 04436 ExFreePool(DeviceRelations); 04437 } 04438 04439 static 04440 VOID 04441 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) 04442 { 04443 /* This function DOES dereference the device objects in all cases */ 04444 04445 ULONG i; 04446 04447 for (i = 0; i < DeviceRelations->Count; i++) 04448 { 04449 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); 04450 ObDereferenceObject(DeviceRelations->Objects[i]); 04451 DeviceRelations->Objects[i] = NULL; 04452 } 04453 04454 ExFreePool(DeviceRelations); 04455 } 04456 04457 VOID 04458 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) 04459 { 04460 IO_STACK_LOCATION Stack; 04461 IO_STATUS_BLOCK IoStatusBlock; 04462 PDEVICE_RELATIONS DeviceRelations; 04463 NTSTATUS Status; 04464 04465 IopCancelRemoveDevice(DeviceObject); 04466 04467 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 04468 04469 Status = IopInitiatePnpIrp(DeviceObject, 04470 &IoStatusBlock, 04471 IRP_MN_QUERY_DEVICE_RELATIONS, 04472 &Stack); 04473 if (!NT_SUCCESS(Status)) 04474 { 04475 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 04476 DeviceRelations = NULL; 04477 } 04478 else 04479 { 04480 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 04481 } 04482 04483 if (DeviceRelations) 04484 IopCancelRemoveDeviceRelations(DeviceRelations); 04485 } 04486 04487 NTSTATUS 04488 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) 04489 { 04490 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 04491 IO_STACK_LOCATION Stack; 04492 IO_STATUS_BLOCK IoStatusBlock; 04493 PDEVICE_RELATIONS DeviceRelations; 04494 NTSTATUS Status; 04495 04496 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) 04497 { 04498 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); 04499 return STATUS_UNSUCCESSFUL; 04500 } 04501 04502 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) 04503 { 04504 DPRINT1("Removal vetoed by failing the query remove request\n"); 04505 04506 IopCancelRemoveDevice(DeviceObject); 04507 04508 return STATUS_UNSUCCESSFUL; 04509 } 04510 04511 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; 04512 04513 Status = IopInitiatePnpIrp(DeviceObject, 04514 &IoStatusBlock, 04515 IRP_MN_QUERY_DEVICE_RELATIONS, 04516 &Stack); 04517 if (!NT_SUCCESS(Status)) 04518 { 04519 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 04520 DeviceRelations = NULL; 04521 } 04522 else 04523 { 04524 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 04525 } 04526 04527 if (DeviceRelations) 04528 { 04529 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); 04530 if (!NT_SUCCESS(Status)) 04531 return Status; 04532 } 04533 04534 Status = IopQueryRemoveChildDevices(DeviceNode, Force); 04535 if (!NT_SUCCESS(Status)) 04536 { 04537 if (DeviceRelations) 04538 IopCancelRemoveDeviceRelations(DeviceRelations); 04539 return Status; 04540 } 04541 04542 DeviceNode->Flags |= DNF_WILL_BE_REMOVED; 04543 DeviceNode->Problem = CM_PROB_WILL_BE_REMOVED; 04544 if (DeviceRelations) 04545 IopSendRemoveDeviceRelations(DeviceRelations); 04546 IopSendRemoveChildDevices(DeviceNode); 04547 04548 return STATUS_SUCCESS; 04549 } 04550 04551 NTSTATUS 04552 IopRemoveDevice(PDEVICE_NODE DeviceNode) 04553 { 04554 NTSTATUS Status; 04555 04556 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); 04557 04558 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); 04559 if (NT_SUCCESS(Status)) 04560 { 04561 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); 04562 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, 04563 &DeviceNode->InstancePath); 04564 return STATUS_SUCCESS; 04565 } 04566 04567 return Status; 04568 } 04569 04570 /* 04571 * @implemented 04572 */ 04573 VOID 04574 NTAPI 04575 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) 04576 { 04577 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); 04578 PDEVICE_RELATIONS DeviceRelations; 04579 IO_STATUS_BLOCK IoStatusBlock; 04580 IO_STACK_LOCATION Stack; 04581 DEVICE_CAPABILITIES Capabilities; 04582 NTSTATUS Status; 04583 04584 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, 04585 &DeviceNode->InstancePath); 04586 04587 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) 04588 { 04589 goto cleanup; 04590 } 04591 04592 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; 04593 04594 Status = IopInitiatePnpIrp(PhysicalDeviceObject, 04595 &IoStatusBlock, 04596 IRP_MN_QUERY_DEVICE_RELATIONS, 04597 &Stack); 04598 if (!NT_SUCCESS(Status)) 04599 { 04600 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); 04601 DeviceRelations = NULL; 04602 } 04603 else 04604 { 04605 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 04606 } 04607 04608 if (DeviceRelations) 04609 { 04610 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); 04611 if (!NT_SUCCESS(Status)) 04612 goto cleanup; 04613 } 04614 04615 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); 04616 if (!NT_SUCCESS(Status)) 04617 { 04618 if (DeviceRelations) 04619 IopCancelRemoveDeviceRelations(DeviceRelations); 04620 goto cleanup; 04621 } 04622 04623 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) 04624 { 04625 if (DeviceRelations) 04626 IopCancelRemoveDeviceRelations(DeviceRelations); 04627 IopCancelRemoveChildDevices(DeviceNode); 04628 goto cleanup; 04629 } 04630 04631 if (DeviceRelations) 04632 IopSendRemoveDeviceRelations(DeviceRelations); 04633 IopSendRemoveChildDevices(DeviceNode); 04634 04635 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; 04636 if (Capabilities.EjectSupported) 04637 { 04638 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) 04639 { 04640 goto cleanup; 04641 } 04642 } 04643 else 04644 { 04645 DeviceNode->Flags |= DNF_DISABLED; 04646 } 04647 04648 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, 04649 &DeviceNode->InstancePath); 04650 04651 return; 04652 04653 cleanup: 04654 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, 04655 &DeviceNode->InstancePath); 04656 } 04657 04658 /* 04659 * @implemented 04660 */ 04661 VOID 04662 NTAPI 04663 IoInvalidateDeviceRelations( 04664 IN PDEVICE_OBJECT DeviceObject, 04665 IN DEVICE_RELATION_TYPE Type) 04666 { 04667 PIO_WORKITEM WorkItem; 04668 PINVALIDATE_DEVICE_RELATION_DATA Data; 04669 04670 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA)); 04671 if (!Data) 04672 return; 04673 WorkItem = IoAllocateWorkItem(DeviceObject); 04674 if (!WorkItem) 04675 { 04676 ExFreePool(Data); 04677 return; 04678 } 04679 04680 ObReferenceObject(DeviceObject); 04681 Data->DeviceObject = DeviceObject; 04682 Data->Type = Type; 04683 Data->WorkItem = WorkItem; 04684 04685 IoQueueWorkItem( 04686 WorkItem, 04687 IopAsynchronousInvalidateDeviceRelations, 04688 DelayedWorkQueue, 04689 Data); 04690 } 04691 04692 /* 04693 * @implemented 04694 */ 04695 NTSTATUS 04696 NTAPI 04697 IoSynchronousInvalidateDeviceRelations( 04698 IN PDEVICE_OBJECT DeviceObject, 04699 IN DEVICE_RELATION_TYPE Type) 04700 { 04701 PAGED_CODE(); 04702 04703 switch (Type) 04704 { 04705 case BusRelations: 04706 /* Enumerate the device */ 04707 return IopEnumerateDevice(DeviceObject); 04708 case PowerRelations: 04709 /* Not handled yet */ 04710 return STATUS_NOT_IMPLEMENTED; 04711 case TargetDeviceRelation: 04712 /* Nothing to do */ 04713 return STATUS_SUCCESS; 04714 default: 04715 /* Ejection relations are not supported */ 04716 return STATUS_NOT_SUPPORTED; 04717 } 04718 } 04719 04720 /* 04721 * @implemented 04722 */ 04723 BOOLEAN 04724 NTAPI 04725 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, 04726 IN ULONG BusNumber, 04727 IN PHYSICAL_ADDRESS BusAddress, 04728 IN OUT PULONG AddressSpace, 04729 OUT PPHYSICAL_ADDRESS TranslatedAddress) 04730 { 04731 /* FIXME: Notify the resource arbiter */ 04732 04733 return HalTranslateBusAddress(InterfaceType, 04734 BusNumber, 04735 BusAddress, 04736 AddressSpace, 04737 TranslatedAddress); 04738 } Generated on Fri May 25 2012 04:35:47 for ReactOS by
1.7.6.1
|