ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pnpmgr.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.